diff --git a/mozilla/base/Makefile b/mozilla/base/Makefile new file mode 100644 index 00000000000..b8eb68125f7 --- /dev/null +++ b/mozilla/base/Makefile @@ -0,0 +1,24 @@ +#!gmake +# +# 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. + +DEPTH = .. + +DIRS = src tests + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/base/makefile.win b/mozilla/base/makefile.win new file mode 100644 index 00000000000..077ce4c1185 --- /dev/null +++ b/mozilla/base/makefile.win @@ -0,0 +1,23 @@ +#!nmake +# +# 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. + +DEPTH=.. +IGNORE_MANIFEST=1 + +DIRS=src tests + +include <$(DEPTH)\config\rules.mak> diff --git a/mozilla/base/src/Makefile b/mozilla/base/src/Makefile new file mode 100644 index 00000000000..be513d43cc6 --- /dev/null +++ b/mozilla/base/src/Makefile @@ -0,0 +1,62 @@ +#!gmake +# +# 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. + +DEPTH=../../.. + +DEFINES =-D_IMPL_NS_BASE + +LIBRARY_NAME = raptorbase + +CPPSRCS = \ + nsArena.cpp \ + nsAtomTable.cpp \ + nsByteBuffer.cpp \ + nsCRT.cpp \ + nsInputStream.cpp \ + nsString.cpp \ + nsUnicharBuffer.cpp \ + nsUnicharInputStream.cpp \ + nsURL.cpp \ + nsVoidArray.cpp \ + $(NULL) + +EXPORTS = \ + nscore.h \ + nsCRT.h \ + nsIArena.h \ + nsIAtom.h \ + nsIByteBuffer.h \ + nsIInputStream.h \ + nsITimer.h \ + nsITimerCallback.h \ + nsIUnicharBuffer.h \ + nsIUnicharInputStream.h \ + nsIURL.h \ + nsString.h \ + nsVoidArray.h \ + nsUnitConversion.h \ + $(NULL) + +MODULE = raptor + +REQUIRES = xpcom netlib raptor + +include $(DEPTH)/config/config.mk + +TARGET = $(LIBARY) + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/base/src/makefile.win b/mozilla/base/src/makefile.win new file mode 100644 index 00000000000..1df0f061e51 --- /dev/null +++ b/mozilla/base/src/makefile.win @@ -0,0 +1,74 @@ +#!nmake +# +# 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. + +DEPTH=..\.. +IGNORE_MANIFEST=1 + +DIRS = windows + +DEFINES=-D_IMPL_NS_BASE +LIBRARY_NAME=raptorbase + +CPPSRCS=nsArena.cpp nsAtomTable.cpp nsByteBuffer.cpp nsCRT.cpp \ + nsInputStream.cpp nsString.cpp nsUnicharBuffer.cpp \ + nsUnicharInputStream.cpp nsURL.cpp nsVoidArray.cpp + +CPP_OBJS=.\$(OBJDIR)\nsArena.obj .\$(OBJDIR)\nsAtomTable.obj \ + .\$(OBJDIR)\nsByteBuffer.obj .\$(OBJDIR)\nsCRT.obj \ + .\$(OBJDIR)\nsInputStream.obj .\$(OBJDIR)\nsString.obj \ + .\$(OBJDIR)\nsUnicharBuffer.obj .\$(OBJDIR)\nsUnicharInputStream.obj \ + .\$(OBJDIR)\nsURL.obj .\$(OBJDIR)\nsVoidArray.obj + +EXPORTS=nscore.h nsCRT.h nsIArena.h nsIAtom.h nsIByteBuffer.h \ + nsIInputStream.h nsITimer.h nsITimerCallback.h nsIUnicharBuffer.h \ + nsIUnicharInputStream.h nsIURL.h nsString.h nsVoidArray.h \ + nsUnitConversion.h + +MODULE=raptor + +REQUIRES=xpcom netlib raptor + +LINCS=-I$(XPDIST)\public\xpcom -I$(XPDIST)\public\netlib \ + -I$(XPDIST)\public\raptor + +MAKE_OBJ_TYPE = DLL +DLLNAME = raptorbase +DLL=.\$(OBJDIR)\$(DLLNAME).dll + +OBJS = $(OBJS) .\$(OBJDIR)\nsTimer.obj + +LCFLAGS = \ + $(LCFLAGS) \ + $(DEFINES) \ + $(NULL) + +# These are the libraries we need to link with to create the dll +LLIBS= \ + $(DIST)\lib\xpcom32.lib \ + $(DIST)\lib\libplc21.lib \ + $(DIST)\lib\netlib.lib \ + $(LIBNSPR) + +include <$(DEPTH)\config\rules.mak> + +libs:: $(DLL) + $(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).dll $(DIST)\bin + $(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).lib $(DIST)\lib + +clobber:: + rm -f $(DIST)\bin\$(DLLNAME).dll + rm -f $(DIST)\lib\$(DLLNAME).lib diff --git a/mozilla/base/src/nsArena.cpp b/mozilla/base/src/nsArena.cpp new file mode 100644 index 00000000000..a38ef687f58 --- /dev/null +++ b/mozilla/base/src/nsArena.cpp @@ -0,0 +1,80 @@ +/* -*- 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 "nsIArena.h" +#include "nsCRT.h" + +#define PL_ARENA_CONST_ALIGN_MASK 7 +#include "plarena.h" + +static NS_DEFINE_IID(kArenaIID, NS_IARENA_IID); + +// Simple arena implementation layered on plarena +class ArenaImpl : public nsIArena { +public: + ArenaImpl(PRInt32 aBlockSize); + + NS_DECL_ISUPPORTS + + virtual void* Alloc(PRInt32 aSize); + +protected: + ~ArenaImpl(); + + PLArenaPool mPool; + PRInt32 mBlockSize; +}; + +ArenaImpl::ArenaImpl(PRInt32 aBlockSize) +{ + NS_INIT_REFCNT(); + if (aBlockSize < NS_MIN_ARENA_BLOCK_SIZE) { + aBlockSize = NS_DEFAULT_ARENA_BLOCK_SIZE; + } + PL_INIT_ARENA_POOL(&mPool, "nsIArena", aBlockSize); + mBlockSize = aBlockSize; +} + +NS_IMPL_ISUPPORTS(ArenaImpl,kArenaIID) + +ArenaImpl::~ArenaImpl() +{ + PL_FinishArenaPool(&mPool); +} + +void* ArenaImpl::Alloc(PRInt32 size) +{ + // Adjust size so that it's a multiple of sizeof(double) + PRInt32 align = size & (sizeof(double) - 1); + if (0 != align) { + size += sizeof(double) - align; + } + + void* p; + PL_ARENA_ALLOCATE(p, &mPool, size); + return p; +} + +NS_BASE nsresult NS_NewHeapArena(nsIArena** aInstancePtrResult, + PRInt32 aArenaBlockSize) +{ + ArenaImpl* it = new ArenaImpl(aArenaBlockSize); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kArenaIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/base/src/nsAtomTable.cpp b/mozilla/base/src/nsAtomTable.cpp new file mode 100644 index 00000000000..75998008cb5 --- /dev/null +++ b/mozilla/base/src/nsAtomTable.cpp @@ -0,0 +1,144 @@ +/* -*- 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 "nsIAtom.h" +#include "nsString.h" +#include "nsCRT.h" +#include "plhash.h" + +/** + * The shared hash table for atom lookups. + */ +static nsrefcnt gAtoms; +static struct PLHashTable* gAtomHashTable; + +class AtomImpl : public nsIAtom { +public: + AtomImpl(); + ~AtomImpl(); + + NS_DECL_ISUPPORTS + + void* operator new(size_t size, const PRUnichar* us, PRInt32 uslen); + + virtual void ToString(nsString& aBuf) const; + + virtual const PRUnichar* GetUnicode() const; + + // Actually more; 0 terminated. This slot is reserved for the + // terminating zero. + PRUnichar mString[1]; +}; + +AtomImpl::AtomImpl() +{ + NS_INIT_REFCNT(); + // Every live atom holds a reference on the atom hashtable + gAtoms++; +} + +AtomImpl::~AtomImpl() +{ + NS_PRECONDITION(nsnull != gAtomHashTable, "null atom hashtable"); + if (nsnull != gAtomHashTable) { + PL_HashTableRemove(gAtomHashTable, mString); + nsrefcnt cnt = --gAtoms; + if (0 == cnt) { + // When the last atom is destroyed, the atom arena is destroyed + NS_ASSERTION(0 == gAtomHashTable->nentries, "bad atom table"); + PL_HashTableDestroy(gAtomHashTable); + gAtomHashTable = nsnull; + } + } +} + +static NS_DEFINE_IID(kIAtomIID, NS_IATOM_IID); +NS_IMPL_ISUPPORTS(AtomImpl, kIAtomIID); + +void* AtomImpl::operator new(size_t size, const PRUnichar* us, PRInt32 uslen) +{ + size = size + uslen * sizeof(PRUnichar); + AtomImpl* ii = (AtomImpl*) new char[size]; + nsCRT::memcpy(ii->mString, us, uslen * sizeof(PRUnichar)); + ii->mString[uslen] = 0; + return ii; +} + +void AtomImpl::ToString(nsString& aBuf) const +{ + aBuf.SetLength(0); + aBuf.Append(mString, nsCRT::strlen(mString)); +} + +const PRUnichar* AtomImpl::GetUnicode() const +{ + return mString; +} + +//---------------------------------------------------------------------- + +static PLHashNumber HashKey(const PRUnichar* k) +{ + return (PLHashNumber) nsCRT::HashCode(k); +} + +static PRIntn CompareKeys(const PRUnichar* k1, const PRUnichar* k2) +{ + return nsCRT::strcmp(k1, k2) == 0; +} + +NS_BASE nsIAtom* NS_NewAtom(const char* isolatin1) +{ + nsAutoString tmp(isolatin1); + return NS_NewAtom(tmp.GetUnicode()); +} + +NS_BASE nsIAtom* NS_NewAtom(const nsString& aString) +{ + return NS_NewAtom(aString.GetUnicode()); +} + +NS_BASE nsIAtom* NS_NewAtom(const PRUnichar* us) +{ + if (nsnull == gAtomHashTable) { + gAtomHashTable = PL_NewHashTable(8, (PLHashFunction) HashKey, + (PLHashComparator) CompareKeys, + (PLHashComparator) nsnull, + nsnull, nsnull); + } + PRInt32 uslen; + PRInt32 hashCode = nsCRT::HashCode(us, &uslen); + PLHashEntry** hep = PL_HashTableRawLookup(gAtomHashTable, hashCode, us); + PLHashEntry* he = *hep; + if (nsnull != he) { + nsIAtom* id = (nsIAtom*) he->value; + NS_ADDREF(id); + return id; + } + AtomImpl* id = new(us, uslen) AtomImpl(); + PL_HashTableRawAdd(gAtomHashTable, hep, hashCode, id->mString, id); + NS_ADDREF(id); + return id; +} + +NS_BASE nsrefcnt NS_GetNumberOfAtoms(void) +{ + if (nsnull != gAtomHashTable) { + NS_PRECONDITION(nsrefcnt(gAtomHashTable->nentries) == gAtoms, "bad atom table"); + } + return gAtoms; +} diff --git a/mozilla/base/src/nsByteBuffer.cpp b/mozilla/base/src/nsByteBuffer.cpp new file mode 100644 index 00000000000..a27f8cbf2c9 --- /dev/null +++ b/mozilla/base/src/nsByteBuffer.cpp @@ -0,0 +1,135 @@ +/* -*- 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 "nsIByteBuffer.h" +#include "nsIInputStream.h" +#include "nsCRT.h" + +#define MIN_BUFFER_SIZE 32 + +class ByteBufferImpl : public nsIByteBuffer { +public: + ByteBufferImpl(PRInt32 aBufferSize); + ~ByteBufferImpl(); + + NS_DECL_ISUPPORTS + virtual PRInt32 GetLength() const; + virtual PRInt32 GetBufferSize() const; + virtual char* GetBuffer() const; + virtual PRBool Grow(PRInt32 aNewSize); + virtual PRInt32 Fill(PRInt32* aErrorCode, nsIInputStream* aStream, + PRInt32 aKeep); + + char* mBuffer; + PRInt32 mSpace; + PRInt32 mLength; +}; + +ByteBufferImpl::ByteBufferImpl(PRInt32 aBufferSize) +{ + if (PRUint32(aBufferSize) < MIN_BUFFER_SIZE) { + aBufferSize = MIN_BUFFER_SIZE; + } + mSpace = aBufferSize; + mBuffer = new char[aBufferSize]; + mLength = 0; + NS_INIT_REFCNT(); +} + +NS_DEFINE_IID(kByteBufferIID,NS_IBYTE_BUFFER_IID); +NS_IMPL_ISUPPORTS(ByteBufferImpl,kByteBufferIID) + +ByteBufferImpl::~ByteBufferImpl() +{ + if (nsnull != mBuffer) { + delete mBuffer; + mBuffer = nsnull; + } + mLength = 0; +} + +PRInt32 ByteBufferImpl::GetLength() const +{ + return mLength; +} + +PRInt32 ByteBufferImpl::GetBufferSize() const +{ + return mSpace; +} + +char* ByteBufferImpl::GetBuffer() const +{ + return mBuffer; +} + +PRBool ByteBufferImpl::Grow(PRInt32 aNewSize) +{ + if (PRUint32(aNewSize) < MIN_BUFFER_SIZE) { + aNewSize = MIN_BUFFER_SIZE; + } + char* newbuf = new char[aNewSize]; + if (nsnull != newbuf) { + if (0 != mLength) { + nsCRT::memcpy(newbuf, mBuffer, mLength); + } + delete mBuffer; + mBuffer = newbuf; + return PR_TRUE; + } + return PR_FALSE; +} + +PRInt32 ByteBufferImpl::Fill(PRInt32* aErrorCode, nsIInputStream* aStream, + PRInt32 aKeep) +{ + NS_PRECONDITION(nsnull != aStream, "null stream"); + NS_PRECONDITION(PRUint32(aKeep) <= PRUint32(mLength), "illegal keep count"); + if ((nsnull == aStream) || (PRUint32(aKeep) > PRUint32(mLength))) { + // whoops + *aErrorCode = NS_INPUTSTREAM_ILLEGAL_ARGS; + return -1; + } + + if (0 != aKeep) { + // Slide over kept data + nsCRT::memmove(mBuffer, mBuffer + (mLength - aKeep), aKeep); + } + + // Read in some new data + mLength = aKeep; + PRInt32 amount = mSpace - aKeep; + PRInt32 nb = aStream->Read(aErrorCode, mBuffer, aKeep, amount); + if (nb > 0) { + mLength += nb; + } + return nb; +} + +NS_BASE nsresult NS_NewByteBuffer(nsIByteBuffer** aInstancePtrResult, + nsISupports* aOuter, + PRInt32 aBufferSize) +{ + if (nsnull != aOuter) { + return NS_ERROR_NO_AGGREGATION; + } + ByteBufferImpl* it = new ByteBufferImpl(aBufferSize); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kByteBufferIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/base/src/nsCRT.cpp b/mozilla/base/src/nsCRT.cpp new file mode 100644 index 00000000000..c4ac141a2ad --- /dev/null +++ b/mozilla/base/src/nsCRT.cpp @@ -0,0 +1,290 @@ +/* -*- 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 "nsCRT.h" + +// XXX Bug: These tables don't lowercase the upper 128 characters properly + +// This table maps uppercase characters to lower case characters; +// characters that are neither upper nor lower case are unaffected. +static const unsigned char kUpper2Lower[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, + + // upper band mapped to lower [A-Z] => [a-z] + 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122, + + 91, 92, 93, 94, 95, + 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 +}; + +static const unsigned char kLower2Upper[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, + + // lower band mapped to upper [a-z] => [A-Z] + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + + 123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 +}; + +static const PRUnichar kIsoLatin1ToUCS2[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 +}; + +//---------------------------------------------------------------------- + +#define TOLOWER(_ucs2) \ + (((_ucs2) < 256) ? PRUnichar(kUpper2Lower[_ucs2]) : _ToLower(_ucs2)) + +#define TOUPPER(_ucs2) \ + (((_ucs2) < 256) ? PRUnichar(kLower2Upper[_ucs2]) : _ToUpper(_ucs2)) + +static PRUnichar _ToLower(PRUnichar aChar) +{ + // XXX need i18n code here + return aChar; +} + +static PRUnichar _ToUpper(PRUnichar aChar) +{ + // XXX need i18n code here + return aChar; +} + +//---------------------------------------------------------------------- + +PRUnichar nsCRT::ToUpper(PRUnichar aChar) +{ + return TOUPPER(aChar); +} + +PRUnichar nsCRT::ToLower(PRUnichar aChar) +{ + return TOLOWER(aChar); +} + +PRInt32 nsCRT::strlen(const PRUnichar* s) +{ + PRInt32 len = 0; + while (*s++ != 0) { + len++; + } + return len; +} + +PRInt32 nsCRT::strcmp(const PRUnichar* s1, const PRUnichar* s2) +{ + for (;;) { + PRUnichar c1 = *s1++; + PRUnichar c2 = *s2++; + if (c1 != c2) { + if (c1 < c2) return -1; + return 1; + } + if (c1 == 0) break; + } + return 0; +} + +// characters following a null character are not compared +PRInt32 nsCRT::strncmp(const PRUnichar* s1, const PRUnichar* s2, PRInt32 n) +{ + while (--n >= 0) { + PRUnichar c1 = *s1++; + PRUnichar c2 = *s2++; + if (c1 != c2) { + if (c1 < c2) return -1; + return 1; + } + if (c1 == 0) break; + } + return 0; +} + +PRInt32 nsCRT::strcasecmp(const PRUnichar* s1, const PRUnichar* s2) +{ + for (;;) { + PRUnichar c1 = *s1++; + PRUnichar c2 = *s2++; + if (c1 != c2) { + c1 = TOLOWER(c1); + c2 = TOLOWER(c2); + if (c1 != c2) { + if (c1 < c2) return -1; + return 1; + } + } + if (c1 == 0) break; + } + return 0; +} + +PRInt32 nsCRT::strncasecmp(const PRUnichar* s1, const PRUnichar* s2, PRInt32 n) +{ + while (--n >= 0) { + PRUnichar c1 = *s1++; + PRUnichar c2 = *s2++; + if (c1 != c2) { + c1 = TOLOWER(c1); + c2 = TOLOWER(c2); + if (c1 != c2) { + if (c1 < c2) return -1; + return 1; + } + } + if (c1 == 0) break; + } + return 0; +} + +PRInt32 nsCRT::strcmp(const PRUnichar* s1, const char* s2) +{ + for (;;) { + PRUnichar c1 = *s1++; + PRUnichar c2 = kIsoLatin1ToUCS2[*(const unsigned char*)s2++]; + if (c1 != c2) { + if (c1 < c2) return -1; + return 1; + } + if (c1 == 0) break; + } + return 0; +} + +PRInt32 nsCRT::strncmp(const PRUnichar* s1, const char* s2, PRInt32 n) +{ + while (--n >= 0) { + PRUnichar c1 = *s1++; + PRUnichar c2 = kIsoLatin1ToUCS2[*(const unsigned char*)s2++]; + if (c1 != c2) { + if (c1 < c2) return -1; + return 1; + } + if (c1 == 0) break; + } + return 0; +} + +PRInt32 nsCRT::strcasecmp(const PRUnichar* s1, const char* s2) +{ + for (;;) { + PRUnichar c1 = *s1++; + PRUnichar c2 = kIsoLatin1ToUCS2[*(const unsigned char*)s2++]; + if (c1 != c2) { + c1 = TOLOWER(c1); + c2 = TOLOWER(c2); + if (c1 != c2) { + if (c1 < c2) return -1; + return 1; + } + } + if (c1 == 0) break; + } + return 0; +} + +PRInt32 nsCRT::strncasecmp(const PRUnichar* s1, const char* s2, PRInt32 n) +{ + while (--n >= 0) { + PRUnichar c1 = *s1++; + PRUnichar c2 = kIsoLatin1ToUCS2[*(const unsigned char*)s2++]; + if (c1 != c2) { + c1 = TOLOWER(c1); + c2 = TOLOWER(c2); + if (c1 != c2) { + if (c1 < c2) return -1; + return 1; + } + } + if (c1 == 0) break; + } + return 0; +} + +PRInt32 nsCRT::HashCode(const PRUnichar* us) +{ + PRInt32 rv = 0; + PRUnichar ch; + while ((ch = *us++) != 0) { + // FYI: rv = rv*37 + ch + rv = ((rv << 5) + (rv << 2) + rv) + ch; + } + return rv; +} + +PRInt32 nsCRT::HashCode(const PRUnichar* us, PRInt32* uslenp) +{ + PRInt32 rv = 0; + PRInt32 len = 0; + PRUnichar ch; + while ((ch = *us++) != 0) { + // FYI: rv = rv*37 + ch + rv = ((rv << 5) + (rv << 2) + rv) + ch; + len++; + } + *uslenp = len; + return rv; +} + +PRInt32 nsCRT::atoi( const PRUnichar *string ) +{ + return atoi(string); +} + diff --git a/mozilla/base/src/nsCRT.h b/mozilla/base/src/nsCRT.h new file mode 100644 index 00000000000..a14ed2bbcb5 --- /dev/null +++ b/mozilla/base/src/nsCRT.h @@ -0,0 +1,110 @@ +/* -*- 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. + */ +#ifndef nsCRT_h___ +#define nsCRT_h___ + +#include +#include +#include "plstr.h" +#include "nscore.h" + +/// This is a wrapper class around all the C runtime functions. + +class NS_BASE nsCRT { +public: + /** Copy bytes from aSrc to aDest. + @param aDest the destination address + @param aSrc the source address + @param aCount the number of bytes to copy + */ + static void memcpy(void* aDest, const void* aSrc, PRInt32 aCount) { + ::memcpy(aDest, aSrc, (size_t)aCount); + } + + static void memmove(void* aDest, const void* aSrc, PRInt32 aCount) { + ::memmove(aDest, aSrc, (size_t)aCount); + } + + static void memset(void* aDest, PRUint8 aByte, PRInt32 aCount) { + ::memset(aDest, aByte, aCount); + } + + static void zero(void* aDest, PRInt32 aCount) { + ::memset(aDest, 0, (size_t)aCount); + } + + /** Compute the string length of s + @param s the string in question + @return the length of s + */ + static PRInt32 strlen(const char* s) { + return PRInt32(::strlen(s)); + } + + /// Compare s1 and s2. + static PRInt32 strcmp(const char* s1, const char* s2) { + return PRInt32(PL_strcmp(s1, s2)); + } + + /// Case-insensitive string comparison. + static PRInt32 strcasecmp(const char* s1, const char* s2) { + return PRInt32(PL_strcasecmp(s1, s2)); + } + + /// Like strlen except for ucs2 strings + static PRInt32 strlen(const PRUnichar* s); + + /// Like strcmp except for ucs2 strings + static PRInt32 strcmp(const PRUnichar* s1, const PRUnichar* s2); + /// Like strcmp except for ucs2 strings + static PRInt32 strncmp(const PRUnichar* s1, const PRUnichar* s2, + PRInt32 aMaxLen); + + /// Like strcasecmp except for ucs2 strings + static PRInt32 strcasecmp(const PRUnichar* s1, const PRUnichar* s2); + /// Like strncasecmp except for ucs2 strings + static PRInt32 strncasecmp(const PRUnichar* s1, const PRUnichar* s2, + PRInt32 aMaxLen); + + /// Like strcmp with a char* and a ucs2 string + static PRInt32 strcmp(const PRUnichar* s1, const char* s2); + /// Like strncmp with a char* and a ucs2 string + static PRInt32 strncmp(const PRUnichar* s1, const char* s2, + PRInt32 aMaxLen); + + /// Like strcasecmp with a char* and a ucs2 string + static PRInt32 strcasecmp(const PRUnichar* s1, const char* s2); + /// Like strncasecmp with a char* and a ucs2 string + static PRInt32 strncasecmp(const PRUnichar* s1, const char* s2, + PRInt32 aMaxLen); + + /// Compute a hashcode for a ucs2 string + static PRInt32 HashCode(const PRUnichar* s1); + + /// Same as above except that we return the length in s1len + static PRInt32 HashCode(const PRUnichar* s1, PRInt32* s1len); + + /// String to integer. + static PRInt32 atoi( const PRUnichar *string ); + + static PRUnichar ToUpper(PRUnichar aChar); + + static PRUnichar ToLower(PRUnichar aChar); +}; + +#endif /* nsCRT_h___ */ diff --git a/mozilla/base/src/nsIArena.h b/mozilla/base/src/nsIArena.h new file mode 100644 index 00000000000..c530f914631 --- /dev/null +++ b/mozilla/base/src/nsIArena.h @@ -0,0 +1,51 @@ +/* -*- 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. + */ +#ifndef nsIArena_h___ +#define nsIArena_h___ + +#include "nscore.h" +#include "nsISupports.h" + +#define NS_MIN_ARENA_BLOCK_SIZE 64 +#define NS_DEFAULT_ARENA_BLOCK_SIZE 4096 + +/// Interface IID for nsIArena +#define NS_IARENA_IID \ +{ 0xa24fdad0, 0x93b4, 0x11d1, \ + {0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } + +/** Interface to a memory arena abstraction. Arena's use large blocks + * of memory to allocate smaller objects. Arena's provide no free + * operator; instead, all of the objects in the arena are deallocated + * by deallocating the arena (e.g. when it's reference count goes to + * zero) + */ +class nsIArena : public nsISupports { +public: + virtual void* Alloc(PRInt32 size) = 0; +}; + +/** + * Create a new arena using the desired block size for allocating the + * underlying memory blocks. The underlying memory blocks are allocated + * using the PR heap. + */ +extern NS_BASE nsresult NS_NewHeapArena(nsIArena** aInstancePtrResult, + PRInt32 aArenaBlockSize = 0); + +#endif /* nsIArena_h___ */ diff --git a/mozilla/base/src/nsIAtom.h b/mozilla/base/src/nsIAtom.h new file mode 100644 index 00000000000..59e13f2035e --- /dev/null +++ b/mozilla/base/src/nsIAtom.h @@ -0,0 +1,71 @@ +/* -*- 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. + */ +#ifndef nsIAtom_h___ +#define nsIAtom_h___ + +#include "nscore.h" +#include "nsISupports.h" +class nsString; + +#define NS_IATOM_IID \ +{ 0x3d1b15b0, 0x93b4, 0x11d1, \ + {0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } + +/** + * A globally unique identfier. nsIAtom's can be compared for + * equality by using operator '=='. These objects are reference + * counted like other nsISupports objects. When you are done with + * the atom, NS_RELEASE it. + */ +class nsIAtom : public nsISupports { +public: + /** + * Translate the unicode string into the stringbuf. + */ + virtual void ToString(nsString& aString) const = 0; + + /** + * Return a pointer to a zero terminated unicode string. + */ + virtual const PRUnichar* GetUnicode() const = 0; +}; + +/** + * Find an atom that matches the given iso-latin1 C string. The + * C string is translated into it's unicode equivalent. + */ +extern NS_BASE nsIAtom* NS_NewAtom(const char* isolatin1); + +/** + * Find an atom that matches the given unicode string. The string is assumed + * to be zero terminated. + */ +extern NS_BASE nsIAtom* NS_NewAtom(const PRUnichar* unicode); + +/** + * Find an atom that matches the given string. + */ +extern NS_BASE nsIAtom* NS_NewAtom(const nsString& aString); + +/** + * Return a count of the total number of atoms currently + * alive in the system. + */ +extern NS_BASE nsrefcnt NS_GetNumberOfAtoms(void); + +#endif /* nsIAtom_h___ */ diff --git a/mozilla/base/src/nsIByteBuffer.h b/mozilla/base/src/nsIByteBuffer.h new file mode 100644 index 00000000000..74561b69a47 --- /dev/null +++ b/mozilla/base/src/nsIByteBuffer.h @@ -0,0 +1,56 @@ +/* -*- 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. + */ +#ifndef nsIByteBuffer_h___ +#define nsIByteBuffer_h___ + +#include "nscore.h" +#include "nsISupports.h" + +class nsIInputStream; + +#define NS_IBYTE_BUFFER_IID \ +{ 0xe4a6e4b0, 0x93b4, 0x11d1, \ + {0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } + +/** Interface to a buffer that holds bytes */ +class nsIByteBuffer : public nsISupports { +public: + /** @return length of buffer, i.e. how many bytes are currently in it. */ + virtual PRInt32 GetLength() const = 0; + + /** @return number of bytes allocated in the buffer */ + virtual PRInt32 GetBufferSize() const = 0; + + /** @return the buffer */ + virtual char* GetBuffer() const = 0; + + /** Grow buffer to aNewSize bytes. */ + virtual PRBool Grow(PRInt32 aNewSize) = 0; + + /** Fill the buffer with data from aStream. Don't grow the buffer, only + * read until length of buffer equals buffer size. */ + virtual PRInt32 Fill(PRInt32* aErrorCode, nsIInputStream* aStream, + PRInt32 aKeep) = 0; +}; + +/** Create a new byte buffer using the given buffer size. */ +extern NS_BASE nsresult NS_NewByteBuffer(nsIByteBuffer** aInstancePtrResult, + nsISupports* aOuter, + PRInt32 aBufferSize = 0); + +#endif /* nsIByteBuffer_h___ */ diff --git a/mozilla/base/src/nsIInputStream.h b/mozilla/base/src/nsIInputStream.h new file mode 100644 index 00000000000..d9459267f1e --- /dev/null +++ b/mozilla/base/src/nsIInputStream.h @@ -0,0 +1,74 @@ +/* -*- 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. + */ +#ifndef nsIInputStream_h___ +#define nsIInputStream_h___ + +#include "nscore.h" +#include "nsISupports.h" + +#define NS_IINPUTSTREAM_IID \ +{ 0x022396f0, 0x93b5, 0x11d1, \ + {0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } + +/** Abstract byte input stream */ +class nsIInputStream : public nsISupports { +public: + /** Read data from the stream. + * @param aErrorCode the error code if an error occurs + * @param aBuf the buffer into which the data is read + * @param aOffset the start offset of the data + * @param aCount the maximum number of bytes to read + * @return number of bytes read or -1 if error + */ + virtual PRInt32 Read(PRInt32* aErrorCode, + char* aBuf, + PRInt32 aOffset, + PRInt32 aCount) = 0; + + /** Close the stream. */ + virtual void Close() = 0; +}; + +/** Error codes */ +//@{ +// XXX fix up the values to work with nsqresult +/// End of file +#define NS_INPUTSTREAM_EOF 1 +/// Stream closed +#define NS_INPUTSTREAM_CLOSED 2 +/// Error from the operating system +#define NS_INPUTSTREAM_OSERROR 3 +/// Illegal arguments +#define NS_INPUTSTREAM_ILLEGAL_ARGS 4 +/// For unichar streams +#define NS_INPUTSTREAM_NO_CONVERTER 5 +/// For unichar streams +#define NS_INPUTSTREAM_BAD_CONVERSION 6 +//@} + +/** Open a file using a local file name. Return an input stream that + can read the file. Use an implementation of nsIByteBuffer to do + buffered reading of the stream. */ +extern NS_BASE nsresult NS_OpenFile(nsIInputStream** aInstancePtrResult, + const char* aLocalFileName); + +/** Open a stream from a resource file name. Need two sents? */ +extern NS_BASE nsresult NS_OpenResource(nsIInputStream** aInstancePtrResult, + const char* aResourceFileName); + +#endif /* nsInputStream_h___ */ diff --git a/mozilla/base/src/nsITimer.h b/mozilla/base/src/nsITimer.h new file mode 100644 index 00000000000..b4bbf48e562 --- /dev/null +++ b/mozilla/base/src/nsITimer.h @@ -0,0 +1,62 @@ +/* -*- 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. + */ +#ifndef nsITimer_h___ +#define nsITimer_h___ + +#include "nscore.h" +#include "nsISupports.h" + +class nsITimer; +class nsITimerCallback; + +/// Signature of timer callback function +typedef void +(*nsTimerCallbackFunc) (nsITimer *aTimer, void *aClosure); + +/// Interface IID for nsITimer +#define NS_ITIMER_IID \ +{ 0x497eed20, 0xb740, 0x11d1, \ +{ 0x9b, 0xc3, 0x00, 0x60, 0x08, 0x8c, 0xa6, 0xb3 } } + +/** + * Timer class, used to invoke a function or method after a fixed + * millisecond interval. + */ +class nsITimer : public nsISupports { +public: + virtual nsresult Init(nsTimerCallbackFunc aFunc, + void *aClosure, +// PRBool aRepeat, + PRUint32 aDelay)=0; + + virtual nsresult Init(nsITimerCallback *aCallback, +// PRBool aRepeat, + PRUint32 aDelay)=0; + + /// Cancels the timeout + virtual void Cancel()=0; + + virtual PRUint32 GetDelay()=0; + + virtual void SetDelay(PRUint32 aDelay)=0; +}; + +/** Factory method for creating an nsITimer */ +extern NS_BASE nsresult NS_NewTimer(nsITimer** aInstancePtrResult); + +#endif diff --git a/mozilla/base/src/nsITimerCallback.h b/mozilla/base/src/nsITimerCallback.h new file mode 100644 index 00000000000..9772c3e3f46 --- /dev/null +++ b/mozilla/base/src/nsITimerCallback.h @@ -0,0 +1,41 @@ +/* -*- 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. + */ +#ifndef nsITimerCallback_h___ +#define nsITimerCallback_h___ + +#include "nscore.h" +#include "nsISupports.h" + +class nsITimer; + +/// Interface IID for nsITimerCallback +#define NS_ITIMERCALLBACK_IID \ +{ 0x5079b3a0, 0xb743, 0x11d1, \ +{ 0x9b, 0xc3, 0x00, 0x60, 0x08, 0x8c, 0xa6, 0xb3 } } + +/** + * Interface implemented by users of the nsITimer class. An instance + * of this interface is passed in when creating a timer. The Notify() + * method of that instance is invoked after the specified delay. + */ +class nsITimerCallback : public nsISupports { +public: + virtual void Notify(nsITimer *timer)=0; +}; + +#endif diff --git a/mozilla/base/src/nsIURL.h b/mozilla/base/src/nsIURL.h new file mode 100644 index 00000000000..7126b8a0357 --- /dev/null +++ b/mozilla/base/src/nsIURL.h @@ -0,0 +1,90 @@ +/* -*- 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. + */ +#ifndef nsIURL_h___ +#define nsIURL_h___ + +#include "nscore.h" +#include "nsISupports.h" +class nsIInputStream; +class nsString; + +#define NS_IURL_IID \ +{ 0x6ecb2900, 0x93b5, 0x11d1, \ + {0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } + +/** + * TEMPORARY INTERFACE; this will will be + * going away + */ +class nsIURL : public nsISupports { +public: + /** Open the url for reading and return a new input stream for the + * url. The caller must release the input stream when done with it. + */ + virtual nsIInputStream* Open(PRInt32* aErrorCode) const = 0; + + /** Equality operator */ + virtual PRBool operator==(const nsIURL& aURL) const = 0; + + + /** Accessors */ + //@{ + /** + @return protocol part of the URL */ + virtual const char* GetProtocol() const = 0; + + /** @return host part of the URL */ + virtual const char* GetHost() const = 0; + + /** @return file part of the URL */ + virtual const char* GetFile() const = 0; + + /** @return ref part of the URL */ + virtual const char* GetRef() const = 0; + + /** @return string originally used to construct the URL */ + virtual const char* GetSpec() const = 0; + + /** @return ref part of the URL */ + virtual PRInt32 GetPort() const = 0; + //@} + + /** Write the URL to aString, overwriting previous contents. */ + virtual void ToString(nsString& aString) const = 0; +}; + +/** Create a new URL from aSpec. */ +extern NS_BASE nsresult NS_NewURL(nsIURL** aInstancePtrResult, + const nsString& aSpec); + +/** Create a new URL, interpreting aSpec as relative to aURL. */ +extern NS_BASE nsresult NS_NewURL(nsIURL** aInstancePtrResult, + const nsIURL* aURL, + const nsString& aSpec); + +/** + * Utility routine to take a url (may be nsnull) and a base url (may + * be empty), and a url spec and combine them properly into a new + * absolute url. + */ +extern NS_BASE nsresult NS_MakeAbsoluteURL(nsIURL* aURL, + const nsString& aBaseURL, + const nsString& aSpec, + nsString& aResult); + +#endif /* nsIURL_h___ */ diff --git a/mozilla/base/src/nsIUnicharBuffer.h b/mozilla/base/src/nsIUnicharBuffer.h new file mode 100644 index 00000000000..17bf8e74a3a --- /dev/null +++ b/mozilla/base/src/nsIUnicharBuffer.h @@ -0,0 +1,46 @@ +/* -*- 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. + */ +#ifndef nsIUnicharBuffer_h___ +#define nsIUnicharBuffer_h___ + +#include "nscore.h" +#include "nsISupports.h" +class nsIUnicharInputStream; + +#define NS_IUNICHAR_BUFFER_IID \ +{ 0x14cf6970, 0x93b5, 0x11d1, \ + {0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } + +/// Interface to a buffer that holds unicode characters +class nsIUnicharBuffer : public nsISupports { +public: + virtual PRInt32 GetLength() const = 0; + virtual PRInt32 GetBufferSize() const = 0; + virtual PRUnichar* GetBuffer() const = 0; + virtual PRBool Grow(PRInt32 aNewSize) = 0; + virtual PRInt32 Fill(PRInt32* aErrorCode, nsIUnicharInputStream* aStream, + PRInt32 aKeep) = 0; +}; + +/// Factory method for nsIUnicharBuffer. +extern NS_BASE nsresult + NS_NewUnicharBuffer(nsIUnicharBuffer** aInstancePtrResult, + nsISupports* aOuter, + PRInt32 aBufferSize = 0); + +#endif /* nsIUnicharBuffer_h___ */ diff --git a/mozilla/base/src/nsIUnicharInputStream.h b/mozilla/base/src/nsIUnicharInputStream.h new file mode 100644 index 00000000000..4d892e5a7aa --- /dev/null +++ b/mozilla/base/src/nsIUnicharInputStream.h @@ -0,0 +1,98 @@ +/* -*- 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. + */ +#ifndef nsIUnicharInputStream_h___ +#define nsIUnicharInputStream_h___ + +#include "nsIInputStream.h" +class nsString; + +#define NS_IUNICHAR_INPUT_STREAM_IID \ +{ 0x2d97fbf0, 0x93b5, 0x11d1, \ + {0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } + +#define NS_IB2UCONVERTER_IID \ +{ 0x35e40290, 0x93b5, 0x11d1, \ + {0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } + +/// Enumeration of character set ids. +enum nsCharSetID { + eCharSetID_IsoLatin1 = 0, + eCharSetID_UTF8, + eCharSetID_ShiftJis, + // XXX more i'm sure... +}; + +/** Abstract unicode character input stream + * @see nsIInputStream + */ +class nsIUnicharInputStream : public nsISupports { +public: + virtual PRInt32 Read(PRInt32* aErrorCode, + PRUnichar* aBuf, + PRInt32 aOffset, + PRInt32 aCount) = 0; + virtual void Close() = 0; +}; + +/** + * Create a nsIUnicharInputStream that wraps up a string. Data is fed + * from the string out until the done. When this object is destroyed + * it destroyes the string (so make a copy if you don't want it doing + * that) + */ +extern NS_BASE nsresult + NS_NewStringUnicharInputStream(nsIUnicharInputStream** aInstancePtrResult, + nsString* aString); + +/// Abstract interface for converting from bytes to unicode characters +class nsIB2UConverter : public nsISupports { +public: + /** aDstLen is updated to indicate how much data was translated into + * aDst; aSrcLen is updated to indicate how much data was used in + * the source buffer. + */ + virtual PRInt32 Convert(PRUnichar* aDst, + PRInt32 aDstOffset, + PRInt32& aDstLen, + const char* aSrc, + PRInt32 aSrcOffset, + PRInt32& aSrcLen) = 0; +}; + +/** Create a new nsUnicharInputStream that provides a converter for the + * byte input stream aStreamToWrap. If no converter can be found then + * nsnull is returned and the error code is set to + * NS_INPUTSTREAM_NO_CONVERTER. + */ +extern NS_BASE nsresult + NS_NewConverterStream(nsIUnicharInputStream** aInstancePtrResult, + nsISupports* aOuter, + nsIInputStream* aStreamToWrap, + PRInt32 aBufferSize = 0, + nsCharSetID aCharSet = eCharSetID_IsoLatin1); + +/** Create a new nsB2UConverter for the given character set. When given + * nsnull, the converter for iso-latin1 to unicode is provided. If no + * converter can be found, nsnull is returned. + */ +extern NS_BASE nsresult + NS_NewB2UConverter(nsIB2UConverter** aInstancePtrResult, + nsISupports* aOuter, + nsCharSetID aCharSet = eCharSetID_IsoLatin1); + +#endif /* nsUnicharInputStream_h___ */ diff --git a/mozilla/base/src/nsInputStream.cpp b/mozilla/base/src/nsInputStream.cpp new file mode 100644 index 00000000000..ba15de987ad --- /dev/null +++ b/mozilla/base/src/nsInputStream.cpp @@ -0,0 +1,191 @@ +/* -*- 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 "nsIInputStream.h" +#include "prprf.h" +#include +#ifdef XP_PC +#include +#else +#include +#endif +#include + +// File input stream class +class FileInputStream : public nsIInputStream { +public: + FileInputStream(PRInt32 aFD); + + NS_DECL_ISUPPORTS + virtual PRInt32 Read(PRInt32* aErrorCode, + char* aBuf, + PRInt32 aOffset, + PRInt32 aCount); + virtual void Close(); + +protected: + ~FileInputStream(); + + PRInt32 mFD; +}; + +FileInputStream::FileInputStream(PRInt32 aFD) +{ + NS_INIT_REFCNT(); + mFD = aFD; +} + +NS_DEFINE_IID(kIInputStreamIID, NS_IINPUTSTREAM_IID); +NS_IMPL_ISUPPORTS(FileInputStream,kIInputStreamIID); + +FileInputStream::~FileInputStream() +{ + Close(); +} + +PRInt32 FileInputStream::Read(PRInt32* aErrorCode, + char* aBuf, + PRInt32 aOffset, + PRInt32 aCount) +{ + NS_PRECONDITION(aOffset >= 0, "illegal offset"); + NS_PRECONDITION(aCount >= 0, "illegal count"); + NS_PRECONDITION(mFD != -1, "closed"); + if ((aOffset < 0) || (aCount < 0)) { + *aErrorCode = NS_INPUTSTREAM_ILLEGAL_ARGS; + return -1; + } + if (mFD == -1) { + *aErrorCode = NS_INPUTSTREAM_CLOSED; + return -1; + } + PRInt32 nb = PRInt32( ::read(mFD, aBuf + aOffset, aCount) ); + if (nb <= 0) { + if (nb < 0) { + *aErrorCode = NS_INPUTSTREAM_OSERROR; + return -1; + } + *aErrorCode = NS_INPUTSTREAM_EOF; + } + return nb; +} + +void FileInputStream::Close() +{ + if (-1 != mFD) { + ::close(mFD); + mFD = -1; + } +} + +NS_BASE nsresult NS_OpenFile(nsIInputStream** aInstancePtrResult, + const char* aLocalFileName) +{ +#ifdef XP_PC + char* lfn = strdup(aLocalFileName); + char* cp = lfn; + while ((cp = strchr(cp, '/')) != 0) { + *cp = '\\'; + cp++; + } +#endif + +#ifdef XP_PC + PRInt32 fd = ::open(lfn, O_RDONLY | O_BINARY); + free(lfn); +#else + +#ifdef NS_WIN32 + PRInt32 fd = ::open(aLocalFileName, O_RDONLY | O_BINARY); +#endif +#ifdef XP_UNIX + PRInt32 fd = ::open(aLocalFileName, O_RDONLY); +#endif + +#endif //XP_PC + + if (fd == -1) { + return NS_INPUTSTREAM_OSERROR; + } + FileInputStream* it = new FileInputStream(fd); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIInputStreamIID, (void**)aInstancePtrResult); +} + +NS_BASE nsresult NS_OpenResource(nsIInputStream** aInstancePtrResult, + const char* aResourceFileName) +{ + // XXX For now, resources are not in jar files + // Find base path name to the resource file + char* resourceBase; + char* cp; + +#ifdef XP_PC + // XXX For now, all resources are relative to the .exe file + resourceBase = new char[2000]; + DWORD mfnLen = GetModuleFileName(NULL, resourceBase, 2000); + cp = strrchr(resourceBase, '\\'); + if (nsnull != cp) { + *cp = '\0'; + } +#endif +#ifdef XP_UNIX + // FIX ME: write me!; +#endif + + // Join base path to resource name + if (aResourceFileName[0] == '/') { + aResourceFileName++; + } + PRInt32 baseLen = strlen(resourceBase); + PRInt32 resLen = strlen(aResourceFileName); + PRInt32 totalLen = baseLen + 1 + resLen + 1; + char* fileName = new char[totalLen]; + PR_snprintf(fileName, totalLen, "%s/%s", resourceBase, aResourceFileName); + +#ifdef XP_PC + while ((cp = strchr(fileName, '/')) != 0) { + *cp = '\\'; + cp++; + } +#endif + + // Get +#ifdef NS_WIN32 + PRInt32 fd = ::open(fileName, O_RDONLY | O_BINARY); +#endif +#ifdef XP_UNIX + PRInt32 fd = ::open(fileName, O_RDONLY); +#endif + + delete fileName; + +#ifdef XP_PC + delete resourceBase; +#endif + + if (fd == -1) { + return NS_INPUTSTREAM_OSERROR; + } + FileInputStream* it = new FileInputStream(fd); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIInputStreamIID, (void**)aInstancePtrResult); +} diff --git a/mozilla/base/src/nsString.cpp b/mozilla/base/src/nsString.cpp new file mode 100644 index 00000000000..9f5ada26569 --- /dev/null +++ b/mozilla/base/src/nsString.cpp @@ -0,0 +1,1979 @@ +/* -*- 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 +#include +#include +#include +#include "nsString.h" +#include "nsCRT.h" +#include "nsDebug.h" +#include "prprf.h" +#include "prdtoa.h" + + +const PRInt32 kGrowthDelta = 8; +const PRInt32 kNotFound = -1; +PRUnichar gBadChar = 0; +const char* kOutOfBoundsError = "Error: out of bounds"; +const char* kNullPointerError = "Error: unexpected null ptr"; + +//********************************************** +//NOTE: Our buffer always hold capacity+1 bytes. +//********************************************** + + +PRInt32 nsString::mInstanceCount=0; + +/**------------------------------------------------------- + * Default constructor + * + * @update gess 3/31/98 + * @param + * @return + *------------------------------------------------------*/ +nsString::nsString(const char* anISOLatin1/*=""*/) { + mLength=mCapacity=0; + mStr=0; + PRInt32 len=strlen(anISOLatin1); + EnsureCapacityFor(len); + this->SetString(anISOLatin1,len); + if(++mInstanceCount==1) + SelfTest(); +} + +/*------------------------------------------------------- + * constructor from string + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsString::nsString(const nsString &aString) { + mLength=mCapacity=0; + mStr=0; + EnsureCapacityFor(aString.mLength); + this->SetString(aString.mStr,aString.mLength); + if(++mInstanceCount==1) + SelfTest(); +} + +/*------------------------------------------------------- + * constructor from unicode string + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsString::nsString(const PRUnichar* aUnicodeStr){ + mLength=mCapacity=0; + mStr=0; + PRInt32 len=(aUnicodeStr) ? nsCRT::strlen(aUnicodeStr) : 0; + EnsureCapacityFor(len); + this->SetString(aUnicodeStr,len); + if(++mInstanceCount==1) + SelfTest(); +} + +/*------------------------------------------------------- + * standard destructor + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsString::~nsString() +{ + delete [] mStr; + mStr=0; + mCapacity=mLength=0; +} + +/*------------------------------------------------------- + * This method gets called when the internal buffer needs + * to grow to a given size. + * @update gess 3/30/98 + * @param aNewLength -- new capacity of string + * @return void + *------------------------------------------------------*/ +void nsString::EnsureCapacityFor(PRInt32 aNewLength) +{ + PRInt32 newCapacity; + + if (mCapacity > 64) { + // When the string starts getting large, double the capacity as we + // grow. + newCapacity = mCapacity * 2; + if (newCapacity < aNewLength) { + newCapacity = mCapacity + aNewLength; + } + } else { + // When the string is small, keep it's capacity a multiple of + // kGrowthDelta + PRInt32 size =aNewLength+kGrowthDelta; + newCapacity=size-(size % kGrowthDelta); + } + + if(mCapacity 0) { + nsCRT::memcpy(temp, mStr, mLength * sizeof(chartype)); + } + if(mStr) + delete [] mStr; + mStr = temp; + mStr[mLength]=0; + } +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +void nsString::SetLength(PRInt32 aLength) { +// NS_WARNING("Depricated method -- not longer required with dynamic strings. Use Truncate() instead."); + EnsureCapacityFor(aLength); + if (aLength > mLength) { + nsCRT::zero(mStr + mLength, (aLength - mLength) * sizeof(chartype)); + } + mLength=aLength; +} + +/*------------------------------------------------------- + * This method truncates this string to given length. + * + * @update gess 3/27/98 + * @param anIndex -- new length of string + * @return nada + *------------------------------------------------------*/ +void nsString::Truncate(PRInt32 anIndex) { + if((anIndex>-1) && (anIndex= 'A') && (ch <= 'Z')) { + *cp = 'a' + (ch - 'A'); + } + cp++; + } +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +void nsString::ToUpperCase() +{ + chartype* cp = mStr; + chartype* end = cp + mLength; + while (cp < end) { + chartype ch = *cp; + if ((ch >= 'a') && (ch <= 'z')) { + *cp = 'A' + (ch - 'a'); + } + cp++; + } +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +void nsString::ToLowerCase(nsString& aOut) const +{ + aOut.SetLength(mLength); + chartype* to = aOut.mStr; + chartype* from = mStr; + chartype* end = from + mLength; + while (from < end) { + chartype ch = *from++; + if ((ch >= 'A') && (ch <= 'Z')) { + ch = 'a' + (ch - 'A'); + } + *to++ = ch; + } + *to = 0; +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +void nsString::ToUpperCase(nsString& aOut) const +{ + aOut.SetLength(mLength); + chartype* to = aOut.mStr; + chartype* from = mStr; + chartype* end = from + mLength; + while (from < end) { + chartype ch = *from++; + if ((ch >= 'a') && (ch <= 'z')) { + ch = 'A' + (ch - 'a'); + } + *to++ = ch; + } + *to = 0; +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsString* nsString::ToNewString() const { + return new nsString(mStr); +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +char* nsString::ToNewCString() const +{ + char* rv = new char[mLength + 1]; + return ToCString(rv,mLength+1); +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRUnichar* nsString::ToNewUnicode() const +{ + PRInt32 len = mLength; + chartype* rv = new chartype[len + 1]; + chartype* to = rv; + chartype* from = mStr; + while (--len >= 0) { + *to++ = *from++; + } + *to++ = 0; + return rv; +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +void nsString::ToString(nsString& aString) const +{ + aString.SetLength(0); + aString.Append(mStr, mLength); +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +char* nsString::ToCString(char* aBuf, PRInt32 aBufLength) const +{ + aBufLength--; // leave room for the \0 + PRInt32 len = mLength; + if (len > aBufLength) { + len = aBufLength; + } + char* to = aBuf; + chartype* from = mStr; + while (--len >= 0) { + *to++ = char(*from++); + } + *to++ = '\0'; + return aBuf; +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +float nsString::ToFloat(PRInt32* aErrorCode) const +{ + char buf[40]; + if (mLength > sizeof(buf)-1) { + *aErrorCode = NS_ERROR_ILLEGAL_VALUE; + return 0.0f; + } + char* cp = ToCString(buf, sizeof(buf)); + float f = (float) PR_strtod(cp, &cp); + if (*cp != 0) { + *aErrorCode = NS_ERROR_ILLEGAL_VALUE; + } + return f; +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::ToInteger(PRInt32* aErrorCode) const { + PRInt32 rv = 0; + PRUnichar* cp = mStr; + PRUnichar* end = mStr + mLength; + + // Skip leading whitespace + while (cp < end) { + PRUnichar ch = *cp; + if (!IsSpace(ch)) { + break; + } + cp++; + } + if (cp == end) { + *aErrorCode = NS_ERROR_ILLEGAL_VALUE; + return rv; + } + + // Check for sign + PRUnichar sign = '+'; + if ((*cp == '+') || (*cp == '-')) { + sign = *cp++; + } + if (cp == end) { + *aErrorCode = NS_ERROR_ILLEGAL_VALUE; + return rv; + } + + // Convert the number + while (cp < end) { + PRUnichar ch = *cp++; + if ((ch < '0') || (ch > '9')) { + *aErrorCode = NS_ERROR_ILLEGAL_VALUE; + break; + } + rv = rv * 10 + (ch - '0'); + } + + if (sign == '-') { + rv = -rv; + } + return rv; +} + + +/*------------------------------------------------------- + * assign given string to this one + * @update gess 3/27/98 + * @param aString: string to be added to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator=(const nsString& aString) { + return this->SetString(aString.mStr,aString.mLength); +} + + +/*------------------------------------------------------- + * assign given char* to this string + * @update gess 3/27/98 + * @param anISOLatin1: buffer to be assigned to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator=(const char* anISOLatin1) { + return SetString(anISOLatin1); +} + + +/*------------------------------------------------------- + * assign given char to this string + * @update gess 3/27/98 + * @param aChar: char to be assignd to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator=(char aChar) { + return Append(PRUnichar(aChar)); +} + +/*------------------------------------------------------- + * assign given PRUnichar* to this string + * @update gess 3/27/98 + * @param anISOLatin1: buffer to be assigned to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::SetString(const PRUnichar* aStr,PRInt32 aLength) { + if(aStr!=0) { + PRInt32 len=(kNotFound==aLength) ? nsCRT::strlen(aStr) : aLength; + if(mCapacity< len ) + EnsureCapacityFor(len); + nsCRT::memcpy(mStr,aStr,len*sizeof(chartype)); + mLength=len; + mStr[mLength]=0; + } + else { + mLength=0; //This little bit of code handles the case + mStr[0]=0; //where some blockhead hands us a null string + } + return *this; +} + + +/*------------------------------------------------------- + * assign given char* to this string + * @update gess 3/27/98 + * @param anISOLatin1: buffer to be assigned to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::SetString(const char* anISOLatin1,PRInt32 aLength) { + if(anISOLatin1!=0) { + PRInt32 len=(kNotFound==aLength) ? nsCRT::strlen(anISOLatin1) : aLength; + if(mCapacitySetString(aStr); +} + + +/*------------------------------------------------------- + * assign given char to this string + * @update gess 3/27/98 + * @param aChar: char to be assignd to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator=(PRUnichar aChar) { + mLength=1; + if(mCapacity<1) + EnsureCapacityFor(kGrowthDelta); + mStr[0]=aChar; + mStr[1]=0; + return *this; +} + +/*------------------------------------------------------- + * append given string to this string + * @update gess 3/27/98 + * @param aString : string to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::Append(const nsString& aString,PRInt32 aLength) { + return Append(aString.mStr,aString.mLength); +} + +/*------------------------------------------------------- + * append given string to this string + * @update gess 3/27/98 + * @param aString : string to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::Append(const char* anISOLatin1,PRInt32 aLength) { + if(anISOLatin1!=0) { + PRInt32 len=(kNotFound==aLength) ? strlen(anISOLatin1) : aLength; + if(mLength+len > mCapacity) { + EnsureCapacityFor(mLength+len); + } + for(int i=0;i mCapacity) { + EnsureCapacityFor(mLength+len); + } + if(len>0) + nsCRT::memcpy(&mStr[mLength],aString,len*sizeof(chartype)); + mLength+=len; + mStr[mLength]=0; + } + return *this; +} + +/*------------------------------------------------------- + * append given string to this string + * @update gess 3/27/98 + * @param aString : string to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::Append(PRUnichar aChar) { + if(mLength < mCapacity) { + mStr[mLength++]=aChar; // the new string len < capacity, so just copy + mStr[mLength]=0; + } + else { // The new string exceeds our capacity + EnsureCapacityFor(mLength+1); + mStr[mLength++]=aChar; + mStr[mLength]=0; + } + return *this; +} + + +/*------------------------------------------------------- + * append given string to this string + * @update gess 3/27/98 + * @param aString : string to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator+=(const nsString &aString) { + return this->Append(aString.mStr,aString.mLength); +} + + +/*------------------------------------------------------- + * append given buffer to this string + * @update gess 3/27/98 + * @param anISOLatin1: buffer to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator+=(const char* anISOLatin1) { + return Append(anISOLatin1); +} + + +/*------------------------------------------------------- + * append given buffer to this string + * @update gess 3/27/98 + * @param aBuffer: buffer to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator+=(const PRUnichar* aBuffer) { + return Append(aBuffer); +} + + +/*------------------------------------------------------- + * append given char to this string + * @update gess 3/27/98 + * @param aChar: char to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator+=(PRUnichar aChar) { + return Append(aChar); +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsString& nsString::Append(PRInt32 aInteger,PRInt32 aRadix) { + char* fmt = "%d"; + if (8 == aRadix) { + fmt = "%o"; + } else if (16 == aRadix) { + fmt = "%x"; + } + char buf[40]; + PR_snprintf(buf, sizeof(buf), fmt, aInteger); + Append(buf); + return *this; +} + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsString& nsString::Append(float aFloat){ + char buf[40]; + PR_snprintf(buf, sizeof(buf), "%g", aFloat); + Append(buf); + return *this; +} + + + +/**------------------------------------------------------- + * Copies n characters from this string to given string, + * starting at the leftmost offset. + * + * + * @update gess 4/1/98 + * @param aCopy -- Receiving string + * @param aCount -- number of chars to copy + * @return number of chars copied + *------------------------------------------------------*/ +PRInt32 nsString::Left(nsString& aCopy,PRInt32 aCount) { + return Mid(aCopy,0,aCount); +} + +/**------------------------------------------------------- + * Copies n characters from this string to given string, + * starting at the given offset. + * + * + * @update gess 4/1/98 + * @param aCopy -- Receiving string + * @param aCount -- number of chars to copy + * @param anOffset -- position where copying begins + * @return number of chars copied + *------------------------------------------------------*/ +PRInt32 nsString::Mid(nsString& aCopy,PRInt32 anOffset,PRInt32 aCount) { + if(anOffsetaCopy.mLength) ? aCopy.mLength : aCount; //don't try to copy more than you are given + if(aCount>0) { + + //1st optimization: If you're inserting at end, then simply append! + if(anOffset>=mLength){ + Append(aCopy,aCopy.mLength); + return aCopy.mLength; + } + + if(mLength+aCount > mCapacity) { + EnsureCapacityFor(mLength+aCount); + } + + PRUnichar* last = mStr + mLength; + PRUnichar* first = mStr + anOffset-1; + PRUnichar* next = mStr + mLength + aCount; + + //Copy rightmost chars, up to offset+aCount... + while(first=0) && (anOffset= 'A') && (ch <= 'Z')) || ((ch >= 'a') && (ch <= 'z'))) { + return PR_TRUE; + } + return PR_FALSE; +} + +/**------------------------------------------------------- + * + * + * @update gess 3/31/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool nsString::IsSpace(PRUnichar ch) { + // XXX i18n + if ((ch == ' ') || (ch == '\r') || (ch == '\n') || (ch == '\t')) { + return PR_TRUE; + } + return PR_FALSE; +} + +/**------------------------------------------------------- + * This method trims characters found in aTrimSet from + * either end of the underlying string. + * + * @update gess 3/31/98 + * @param aTrimSet -- contains chars to be trimmed from + * both ends + * @return this + *------------------------------------------------------*/ +nsString& nsString::Trim(const char* aTrimSet, + PRBool aEliminateLeading, + PRBool aEliminateTrailing) +{ + PRUnichar* from = mStr; + PRUnichar* end = mStr + mLength-1; + PRUnichar* to = mStr; + + //begin by find the first char not in aTrimSet + if(aEliminateLeading) { + while (from < end) { + PRUnichar ch = *from; + if(!strchr(aTrimSet,char(ch))) { + break; + } + from++; + } + } + + //Now, find last char not in aTrimSet + if(aEliminateTrailing) { + while(end> from) { + PRUnichar ch = *end; + if(!strchr(aTrimSet,char(ch))) { + break; + } + end--; + } + } + + //now rewrite your string without unwanted + //leading or trailing characters. + while (from <= end) { + *to++ = *from++; + } + + *to = '\0'; + mLength = to - mStr; + return *this; +} + +/**------------------------------------------------------- + * + * + * @update gess 3/31/98 + * @param + * @return + *------------------------------------------------------*/ +nsString& nsString::CompressWhitespace( PRBool aEliminateLeading, + PRBool aEliminateTrailing) +{ + PRUnichar* from = mStr; + PRUnichar* end = mStr + mLength; + PRUnichar* to = from; + + Trim(" \r\n\t",aEliminateLeading,aEliminateTrailing); + + //this code converts /n, /t, /r into normal space ' '; + //it also eliminates runs of whitespace... + while (from < end) { + PRUnichar ch = *from++; + if (IsSpace(ch)) { + *to++ = ' '; + while (from < end) { + ch = *from++; + if (!IsSpace(ch)) { + *to++ = ch; + break; + } + } + } else { + *to++ = ch; + } + } + + *to = '\0'; + mLength = to - mStr; + return *this; +} + +/**------------------------------------------------------- + * XXX This is used by bina all over the place; not sure + * it belongs here though + * + * @update gess 3/31/98 + * @param + * @return + *------------------------------------------------------*/ +nsString& nsString::StripWhitespace() +{ + Trim(" \r\n\t"); + return StripChars("\r\t\n"); +} + + +/**------------------------------------------------------- + * Search for given buffer within this string + * + * @update gess 3/25/98 + * @param anISOLatin1Buf - charstr to be found + * @return offset in string, or -1 (kNotFound) + *------------------------------------------------------*/ +PRInt32 nsString::Find(const char* anISOLatin1Buf) const{ + NS_ASSERTION(0!=anISOLatin1Buf,kNullPointerError); + PRInt32 result=-1; + if(anISOLatin1Buf) { + PRInt32 len=strlen(anISOLatin1Buf); + if(len<=mLength) { //only enter if abuffer length is <= mStr length. + for(PRInt32 offset=0;offset0;i--){ + char* pos=strchr(anISOLatin1Set,char(mStr[i])); + if(pos) + return i; + } + } + return kNotFound; +} + +/**------------------------------------------------------- + * + * + * @update gess 3/25/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::FindLastCharInSet(nsString& aSet,PRInt32 anOffset) const{ + if(aSet.Length()) { + for(PRInt32 i=mLength-1;i>0;i--){ + PRInt32 pos=aSet.Find(mStr[i]); + if(kNotFound!=pos) + return i; + } + } + return kNotFound; +} + +/**------------------------------------------------------- + * + * + * @update gess 3/25/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::RFind(const PRUnichar* aString,PRBool aIgnoreCase) const{ + NS_ASSERTION(0!=aString,kNullPointerError); + + if(aString) { + PRInt32 len=nsCRT::strlen(aString); + if((len) && (len<=mLength)) { //only enter if abuffer length is <= mStr length. + for(PRInt32 offset=mLength-len;offset>=0;offset--) { + PRInt32 result=0; + if(aIgnoreCase) + result=nsCRT::strncasecmp(&mStr[offset],aString,len); + else result=nsCRT::strncmp(&mStr[offset],aString,len); + if(0==result) + return offset; //in this case, 0 means they match + } + } + } + return kNotFound; +} + +/**------------------------------------------------------- + * + * + * @update gess 3/25/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::RFind(const nsString& aString,PRBool aIgnoreCase) const{ + PRInt32 len=aString.mLength; + if((len) && (len<=mLength)) { //only enter if abuffer length is <= mStr length. + for(PRInt32 offset=mLength-len;offset>=0;offset--) { + PRInt32 result=0; + if(aIgnoreCase) + result=nsCRT::strncasecmp(&mStr[offset],aString.mStr,len); + else result=nsCRT::strncmp(&mStr[offset],aString.mStr,len); + if(0==result) + return offset; //in this case, 0 means they match + } + } + return kNotFound; +} + +/**------------------------------------------------------- + * + * + * @update gess 3/25/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::RFind(const char* anISOLatin1Set,PRBool aIgnoreCase) const{ + NS_ASSERTION(0!=anISOLatin1Set,kNullPointerError); + + if(anISOLatin1Set) { + PRInt32 len=strlen(anISOLatin1Set); + if((len) && (len<=mLength)) { //only enter if abuffer length is <= mStr length. + for(PRInt32 offset=mLength-len;offset>=0;offset--) { + PRInt32 result=0; + if(aIgnoreCase) + result=nsCRT::strncasecmp(&mStr[offset],anISOLatin1Set,len); + else result=nsCRT::strncmp(&mStr[offset],anISOLatin1Set,len); + if(0==result) + return offset; //in this case, 0 means they match + } + } + } + return kNotFound; +} + + +/**------------------------------------------------------- + * Scans this string backwards for first occurance of + * the given char. + * + * @update gess 3/25/98 + * @param + * @return offset of char in string, or -1 (kNotFound) + *------------------------------------------------------*/ +PRInt32 nsString::RFind(PRUnichar aChar,PRBool aIgnoreCase) const{ + chartype uc=nsCRT::ToUpper(aChar); + for(PRInt32 offset=mLength-1;offset>0;offset--) + if(aIgnoreCase) { + if(nsCRT::ToUpper(mStr[offset])==uc) + return offset; + } + else if(mStr[offset]==aChar) + return offset; //in this case, 0 means they match + return kNotFound; + +} + + //****** comparision methods... ******* + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::Compare(const char *anISOLatin1,PRBool aIgnoreCase) const { + if (aIgnoreCase) { + return nsCRT::strcasecmp(mStr,anISOLatin1); + } + return nsCRT::strcmp(mStr,anISOLatin1); +} + +/*------------------------------------------------------- + * LAST MODS: gess + * + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::Compare(const nsString &S,PRBool aIgnoreCase) const { + if (aIgnoreCase) { + return nsCRT::strcasecmp(mStr,S.mStr); + } + return nsCRT::strcmp(mStr,S.mStr); +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::Compare(const PRUnichar* aString,PRBool aIgnoreCase) const { + if (aIgnoreCase) { + return nsCRT::strcasecmp(mStr,aString); + } + return nsCRT::strcmp(mStr,aString); +} + + +PRInt32 nsString::operator==(const nsString &S) const {return Compare(S)==0;} +PRInt32 nsString::operator==(const char *s) const {return Compare(s)==0;} +PRInt32 nsString::operator==(const PRUnichar *s) const {return Compare(s)==0;} +PRInt32 nsString::operator!=(const nsString &S) const {return Compare(S)!=0;} +PRInt32 nsString::operator!=(const char *s ) const {return Compare(s)!=0;} +PRInt32 nsString::operator!=(const PRUnichar *s) const {return Compare(s)==0;} +PRInt32 nsString::operator<(const nsString &S) const {return Compare(S)<0;} +PRInt32 nsString::operator<(const char *s) const {return Compare(s)<0;} +PRInt32 nsString::operator<(const PRUnichar *s) const {return Compare(s)==0;} +PRInt32 nsString::operator>(const nsString &S) const {return Compare(S)>0;} +PRInt32 nsString::operator>(const char *s) const {return Compare(s)>0;} +PRInt32 nsString::operator>(const PRUnichar *s) const {return Compare(s)==0;} +PRInt32 nsString::operator<=(const nsString &S) const {return Compare(S)<=0;} +PRInt32 nsString::operator<=(const char *s) const {return Compare(s)<=0;} +PRInt32 nsString::operator<=(const PRUnichar *s) const {return Compare(s)==0;} +PRInt32 nsString::operator>=(const nsString &S) const {return Compare(S)>=0;} +PRInt32 nsString::operator>=(const char *s) const {return Compare(s)>=0;} +PRInt32 nsString::operator>=(const PRUnichar *s) const {return Compare(s)==0;} + + + +/*------------------------------------------------------- + * Compare this to given string + * @update gess 3/27/98 + * @param aString -- string to compare to this + * @return TRUE if equal + *------------------------------------------------------*/ +PRBool nsString::Equals(const nsString& aString) const { + PRInt32 result=nsCRT::strcmp(mStr,aString.mStr); + return PRBool(0==result); +} + + +/*------------------------------------------------------- + * Compare this to given string + * @update gess 3/27/98 + * @param aCString -- Cstr to compare to this + * @return TRUE if equal + *------------------------------------------------------*/ +PRBool nsString::Equals(const char* aCString) const{ + NS_ASSERTION(0!=aCString,kNullPointerError); + PRInt32 result=nsCRT::strcmp(mStr,aCString); + return PRBool(0==result); +} + + +/*------------------------------------------------------- + * Compare this to given atom + * @update gess 3/27/98 + * @param aAtom -- atom to compare to this + * @return TRUE if equal + *------------------------------------------------------*/ +PRBool nsString::Equals(const nsIAtom* aAtom) const +{ + NS_ASSERTION(0!=aAtom,kNullPointerError); + PRInt32 result=nsCRT::strcmp(mStr,aAtom->GetUnicode()); + return PRBool(0==result); +} + + +/*------------------------------------------------------- + * Compare given strings + * @update gess 3/27/98 + * @param s1 -- first string to be compared + * @param s2 -- second string to be compared + * @return TRUE if equal + *------------------------------------------------------*/ +PRBool nsString::Equals(const PRUnichar* s1, const PRUnichar* s2) const { + NS_ASSERTION(0!=s1,kNullPointerError); + NS_ASSERTION(0!=s2,kNullPointerError); + PRBool result=PR_FALSE; + if((s1) && (s2)){ + PRInt32 cmp=nsCRT::strcmp(s1,s2); + result=PRBool(0==cmp); + } + return result; +} + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool nsString::EqualsIgnoreCase(const nsString& aString) const{ + PRInt32 result=nsCRT::strcasecmp(mStr,aString.mStr); + return PRBool(0==result); +} + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool nsString::EqualsIgnoreCase(const nsIAtom *aAtom) const{ + NS_ASSERTION(0!=aAtom,kNullPointerError); + PRBool result=PR_FALSE; + if(aAtom){ + PRInt32 cmp=nsCRT::strcasecmp(mStr,aAtom->GetUnicode()); + result=PRBool(0==cmp); + } + return result; +} + + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool nsString::EqualsIgnoreCase(const PRUnichar* s1, const PRUnichar* s2) const { + NS_ASSERTION(0!=s1,kNullPointerError); + NS_ASSERTION(0!=s2,kNullPointerError); + PRBool result=PR_FALSE; + if((s1) && (s2)){ + PRInt32 cmp=nsCRT::strcasecmp(s1,s2); + result=PRBool(0==cmp); + } + return result; +} + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool nsString::EqualsIgnoreCase(const char* aCString) const { + NS_ASSERTION(0!=aCString,kNullPointerError); + PRBool result=PR_FALSE; + if(aCString){ + PRInt32 cmp=nsCRT::strcasecmp(mStr,aCString); + result=PRBool(0==cmp); + } + return result; +} + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +void nsString::DebugDump(ostream& aStream) const { + for(int i=0;itemp3.Length(),"constructor error!"); //should be char longer + + nsString* es1=temp2.ToNewString(); //this should make us a new string + char* es2=temp2.ToNewCString(); + for(i=0;itemp8,"Error: Comparision (>) routine"); + NS_ASSERTION(temp9>aaaa,"Error: Comparision (>) routine"); + + NS_ASSERTION(temp8<=temp8,"Error: Comparision (<=) routine"); + NS_ASSERTION(temp8<=temp9,"Error: Comparision (<=) routine"); + NS_ASSERTION(temp8<=bbbb,"Error: Comparision (<=) routine"); + + NS_ASSERTION(temp9>=temp9,"Error: Comparision (<=) routine"); + NS_ASSERTION(temp9>=temp8,"Error: Comparision (<=) routine"); + NS_ASSERTION(temp9>=aaaa,"Error: Comparision (<=) routine"); + + NS_ASSERTION(temp8.Equals(temp8),"Equals error"); + NS_ASSERTION(temp8.Equals(aaaa),"Equals error"); + + nsString temp10(temp8); + temp10.ToUpperCase(); + NS_ASSERTION(temp8.EqualsIgnoreCase(temp10),"Equals error"); + NS_ASSERTION(temp8.EqualsIgnoreCase("AAAA"),"Equals error"); + + + //********************************************** + //Now let's test a few string MANIPULATORS... + //********************************************** + + nsAutoString ab("ab"); + nsString abcde("cde"); + abcde.Insert(ab,0,2); + nsAutoString xxx("xxx"); + abcde.Insert(xxx,2,3); + + temp2.ToUpperCase(); + for(i=0;i mCapacity) { + PRInt32 size = mCapacity * 2; + if (size < aNewLength) { + size = mCapacity + aNewLength; + } + mCapacity=size; + chartype* temp = new chartype[mCapacity+1]; + if (mLength > 0) { + nsCRT::memcpy(temp, mStr, mLength * sizeof(chartype)); + } + mStr = temp; + } +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsAutoString::nsAutoString(const PRUnichar* unicode, PRInt32 uslen) { + mStr = mBuf; + mCapacity = sizeof(mBuf) / sizeof(chartype); + if (0 == uslen) { + uslen = nsCRT::strlen(unicode); + } + Append(unicode, uslen); +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsAutoString::~nsAutoString() +{ + if (mStr == mBuf) { + // Force to null so that baseclass dtor doesn't do damage + mStr = nsnull; + } +} + + +/**------------------------------------------------------- + * + * + * @update gess 3/31/98 + * @param + * @return + *------------------------------------------------------*/ +void nsAutoString::SelfTest(){ + nsAutoString xas("Hello there"); + xas.Append("this string exceeds the max size"); + xas.DebugDump(cout); +} + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +NS_BASE int fputs(const nsString& aString, FILE* out) +{ + char buf[100]; + char* cp = buf; + PRInt32 len = aString.Length(); + if (len >= sizeof(buf)) { + cp = aString.ToNewCString(); + } else { + aString.ToCString(cp, len + 1); + } + ::fwrite(cp, 1, len, out); + if (cp != buf) { + delete cp; + } + return (int) len; +} + diff --git a/mozilla/base/src/nsString.h b/mozilla/base/src/nsString.h new file mode 100644 index 00000000000..dc26545c53b --- /dev/null +++ b/mozilla/base/src/nsString.h @@ -0,0 +1,233 @@ +/* -*- 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. + */ + +/** + * MODULE NOTES: + * LAST MODS: gess 28Feb98 + * + * This very simple string class that knows how to do + * efficient (dynamic) resizing. It offers almost no + * i18n support, and will undoubtedly have to be replaced. + * + */ + +#ifndef _NSSTRING +#define _NSSTRING + + +#include "prtypes.h" +#include "nscore.h" +#include "nsIAtom.h" +#include +#include + + +class NS_BASE nsString { + public: + + nsString(const char* anISOLatin1=""); + nsString(const nsString&); + nsString(const PRUnichar* aUnicode); + virtual ~nsString(); + + PRInt32 Length() const { return mLength; } + + void SetLength(PRInt32 aLength); + void Truncate(PRInt32 anIndex=0); + virtual void EnsureCapacityFor(PRInt32 aNewLength); + + ///accessor methods + //@{ + PRUnichar* GetUnicode(void) const; + operator PRUnichar*() const; + +#if 0 + // This is NOT allowed because it has to do a malloc to + // create the iso-latin-1 version of the unicode string + operator char*() const; +#endif + + PRUnichar* operator()() const; + PRUnichar operator()(PRInt32 i) const; + PRUnichar& operator[](PRInt32 i) const; + PRUnichar& CharAt(PRInt32 anIndex) const; + PRUnichar& First() const; + PRUnichar& Last() const; + + //string creation methods... + nsString operator+(const nsString& aString); + nsString operator+(const char* anISOLatin1); + nsString operator+(char aChar); + nsString operator+(const PRUnichar* aBuffer); + nsString operator+(PRUnichar aChar); + + void ToLowerCase(); + void ToLowerCase(nsString& aString) const; + void ToUpperCase(); + void ToUpperCase(nsString& aString) const; + + nsString* ToNewString() const; + char* ToNewCString() const; + + char* ToCString(char* aBuf,PRInt32 aBufLength) const; + void ToString(nsString& aString) const; + + PRUnichar* ToNewUnicode() const; + float ToFloat(PRInt32* aErrorCode) const; + PRInt32 ToInteger(PRInt32* aErrorCode) const; + //@} + + ///string manipulation methods... + //@{ + nsString& operator=(const nsString& aString); + nsString& operator=(const char* anISOLatin1); + nsString& operator=(char aChar); + nsString& operator=(const PRUnichar* aBuffer); + nsString& operator=(PRUnichar aChar); + nsString& SetString(const PRUnichar* aStr,PRInt32 aLength=-1); + nsString& SetString(const char* anISOLatin1,PRInt32 aLength=-1); + + nsString& operator+=(const nsString& aString); + nsString& operator+=(const char* anISOLatin1); + nsString& operator+=(const PRUnichar* aBuffer); + nsString& operator+=(PRUnichar aChar); + nsString& Append(const nsString& aString,PRInt32 aLength=-1); + nsString& Append(const char* anISOLatin1,PRInt32 aLength=-1); + nsString& Append(char aChar); + nsString& Append(const PRUnichar* aBuffer,PRInt32 aLength=-1); + nsString& Append(PRUnichar aChar); + nsString& Append(PRInt32 aInteger,PRInt32 aRadix); //radix=8,10 or 16 + nsString& Append(float aFloat); + + PRInt32 Left(nsString& aCopy,PRInt32 aCount); + PRInt32 Mid(nsString& aCopy,PRInt32 anOffset,PRInt32 aCount); + PRInt32 Right(nsString& aCopy,PRInt32 aCount); + PRInt32 Insert(nsString& aCopy,PRInt32 anOffset,PRInt32 aCount=-1); + + nsString& Cut(PRInt32 anOffset,PRInt32 aCount); + nsString& StripChars(const char* aSet); + nsString& StripWhitespace(); + nsString& Trim( const char* aSet, + PRBool aEliminateLeading=PR_TRUE, + PRBool aEliminateTrailing=PR_TRUE); + nsString& CompressWhitespace( PRBool aEliminateLeading=PR_TRUE, + PRBool aEliminateTrailing=PR_TRUE); + static PRBool IsSpace(PRUnichar ch); + static PRBool IsAlpha(PRUnichar ch); + //@} + + ///searching methods... + //@{ + PRInt32 Find(const char* anISOLatin1) const; + PRInt32 Find(const PRUnichar* aString) const; + PRInt32 Find(PRUnichar aChar,PRInt32 offset=0) const; + PRInt32 Find(const nsString& aString) const; + PRInt32 FindFirstCharInSet(const char* anISOLatin1Set,PRInt32 offset=0) const; + PRInt32 FindFirstCharInSet(nsString& aString,PRInt32 offset=0) const; + PRInt32 FindLastCharInSet(const char* anISOLatin1Set,PRInt32 offset=0) const; + PRInt32 FindLastCharInSet(nsString& aString,PRInt32 offset=0) const; + PRInt32 RFind(const char* anISOLatin1,PRBool aIgnoreCase=PR_FALSE) const; + PRInt32 RFind(const PRUnichar* aString,PRBool aIgnoreCase=PR_FALSE) const; + PRInt32 RFind(const nsString& aString,PRBool aIgnoreCase=PR_FALSE) const; + PRInt32 RFind(PRUnichar aChar,PRBool aIgnoreCase=PR_FALSE) const; + //@} + + ///comparision methods... + //@{ + virtual PRInt32 Compare(const nsString &S,PRBool aIgnoreCase=PR_FALSE) const; + virtual PRInt32 Compare(const char *anISOLatin1,PRBool aIgnoreCase=PR_FALSE) const; + virtual PRInt32 Compare(const PRUnichar *aString,PRBool aIgnoreCase=PR_FALSE) const; + + PRInt32 operator==(const nsString &S) const; + PRInt32 operator==(const char *anISOLatin1) const; + PRInt32 operator==(const PRUnichar* aString) const; + PRInt32 operator!=(const nsString &S) const; + PRInt32 operator!=(const char *anISOLatin1) const; + PRInt32 operator!=(const PRUnichar* aString) const; + PRInt32 operator<(const nsString &S) const; + PRInt32 operator<(const char *anISOLatin1) const; + PRInt32 operator<(const PRUnichar* aString) const; + PRInt32 operator>(const nsString &S) const; + PRInt32 operator>(const char *anISOLatin1) const; + PRInt32 operator>(const PRUnichar* aString) const; + PRInt32 operator<=(const nsString &S) const; + PRInt32 operator<=(const char *anISOLatin1) const; + PRInt32 operator<=(const PRUnichar* aString) const; + PRInt32 operator>=(const nsString &S) const; + PRInt32 operator>=(const char *anISOLatin1) const; + PRInt32 operator>=(const PRUnichar* aString) const; + + PRBool Equals(const nsString& aString) const; + PRBool Equals(const char* anISOLatin1) const; + PRBool Equals(const nsIAtom *aAtom) const; + PRBool Equals(const PRUnichar* s1, const PRUnichar* s2) const; + + PRBool EqualsIgnoreCase(const nsString& aString) const; + PRBool EqualsIgnoreCase(const char* anISOLatin1) const; + PRBool EqualsIgnoreCase(const nsIAtom *aAtom) const; + PRBool EqualsIgnoreCase(const PRUnichar* s1, const PRUnichar* s2) const; + //@} + + static void SelfTest(); + virtual void DebugDump(ostream& aStream) const; + + protected: + +typedef PRUnichar chartype; + + chartype* mStr; + PRInt32 mLength; + PRInt32 mCapacity; + static PRInt32 mInstanceCount; +}; + +extern NS_BASE int fputs(const nsString& aString, FILE* out); + +//---------------------------------------------------------------------- + +/** + * A version of nsString which is designed to be used as an automatic + * variable. It attempts to operate out of a fixed size internal + * buffer until too much data is added; then a dynamic buffer is + * allocated and grown as necessary. + */ +// XXX template this with a parameter for the size of the buffer? +class NS_BASE nsAutoString : public nsString { +public: + nsAutoString(); + nsAutoString(const nsString& other); + nsAutoString(const nsAutoString& other); + nsAutoString(PRUnichar aChar); + nsAutoString(const char* isolatin1); + nsAutoString(const PRUnichar* us, PRInt32 uslen = -1); + virtual ~nsAutoString(); + + static void SelfTest(); + +protected: + virtual void EnsureCapacityFor(PRInt32 aNewLength); + + PRUnichar mBuf[32]; + +private: + // XXX these need writing I suppose + nsAutoString& operator=(const nsAutoString& other); +}; + +#endif + diff --git a/mozilla/base/src/nsURL.cpp b/mozilla/base/src/nsURL.cpp new file mode 100644 index 00000000000..3f3827955d5 --- /dev/null +++ b/mozilla/base/src/nsURL.cpp @@ -0,0 +1,344 @@ +/* -*- 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 "nsIURL.h" +#include "nsIInputStream.h" +#include "nsINetService.h" +#include "nsString.h" +#include + +#include /* XXX */ +#include "plstr.h" + +class URLImpl : public nsIURL { +public: + URLImpl(const nsString& aSpec); + URLImpl(const nsIURL* aURL, const nsString& aSpec); + ~URLImpl(); + + NS_DECL_ISUPPORTS + + virtual PRBool operator==(const nsIURL& aURL) const; + virtual nsIInputStream* Open(PRInt32* aErrorCode) const; + virtual const char* GetProtocol() const; + virtual const char* GetHost() const; + virtual const char* GetFile() const; + virtual const char* GetRef() const; + virtual const char* GetSpec() const; + virtual PRInt32 GetPort() const; + + virtual void ToString(nsString& aString) const; + + char* mSpec; + char* mProtocol; + char* mHost; + char* mFile; + char* mRef; + PRInt32 mPort; + PRBool mOK; + + nsresult ParseURL(const nsIURL* aURL, const nsString& aSpec); +}; + +URLImpl::URLImpl(const nsString& aSpec) +{ + NS_INIT_REFCNT(); + ParseURL(nsnull, aSpec); +} + +URLImpl::URLImpl(const nsIURL* aURL, const nsString& aSpec) +{ + NS_INIT_REFCNT(); + ParseURL(aURL, aSpec); +} + +NS_DEFINE_IID(kURLIID, NS_IURL_IID); + +NS_IMPL_ISUPPORTS(URLImpl, kURLIID) + +URLImpl::~URLImpl() +{ + free(mSpec); + free(mProtocol); + free(mHost); + free(mFile); + free(mRef); +} + +PRBool URLImpl::operator==(const nsIURL& aURL) const +{ + URLImpl& other = (URLImpl&)aURL; // XXX ? + return PRBool((0 == PL_strcmp(mProtocol, other.mProtocol)) && + (0 == PL_strcasecmp(mHost, other.mHost)) && + (0 == PL_strcmp(mFile, other.mFile))); +} + +const char* URLImpl::GetProtocol() const +{ + return mProtocol; +} + +const char* URLImpl::GetHost() const +{ + return mHost; +} + +const char* URLImpl::GetFile() const +{ + return mFile; +} + +const char* URLImpl::GetSpec() const +{ + return mSpec; +} + +const char* URLImpl::GetRef() const +{ + return mRef; +} + +PRInt32 URLImpl::GetPort() const +{ + return mPort; +} + + +void URLImpl::ToString(nsString& aString) const +{ + aString.SetLength(0); + aString.Append(mProtocol); + aString.Append("://"); + if (nsnull != mHost) { + aString.Append(mHost); + if (0 < mPort) { + aString.Append(':'); + aString.Append(mPort, 10); + } + } + aString.Append(mFile); + if (nsnull != mRef) { + aString.Append('#'); + aString.Append(mRef); + } +} + +// XXX recode to use nsString api's + +// XXX don't bother with port numbers +// XXX don't bother with ref's +// XXX null pointer checks are incomplete +nsresult URLImpl::ParseURL(const nsIURL* aURL, const nsString& aSpec) +{ + // XXX hack! + char* cSpec = aSpec.ToNewCString(); + + const char* uProtocol = nsnull; + const char* uHost = nsnull; + const char* uFile = nsnull; + PRInt32 uPort = -1; + if (nsnull != aURL) { + uProtocol = aURL->GetProtocol(); + uHost = aURL->GetHost(); + uFile = aURL->GetFile(); + uPort = aURL->GetPort(); + } + + mProtocol = nsnull; + mHost = nsnull; + mFile = nsnull; + mRef = nsnull; + mPort = -1; + mSpec = nsnull; + + if (nsnull == cSpec) { + delete cSpec; + if (nsnull == aURL) { + delete cSpec; + return NS_ERROR_ILLEGAL_VALUE; + } + mProtocol = (nsnull != uProtocol) ? PL_strdup(uProtocol) : nsnull; + mHost = (nsnull != uHost) ? PL_strdup(uHost) : nsnull; + mPort = uPort; + mFile = (nsnull != uFile) ? PL_strdup(uFile) : nsnull; + delete cSpec; + return NS_OK; + } + + mSpec = PL_strdup(cSpec); + const char* cp = PL_strchr(cSpec, ':'); + if (nsnull == cp) { + // relative spec + if (nsnull == aURL) { + delete cSpec; + return NS_ERROR_ILLEGAL_VALUE; + } + + // keep protocol and host + mProtocol = (nsnull != uProtocol) ? PL_strdup(uProtocol) : nsnull; + mHost = (nsnull != uHost) ? PL_strdup(uHost) : nsnull; + mPort = uPort; + + // figure out file name + PRInt32 len = PL_strlen(cSpec) + 1; + if ((len > 1) && (cSpec[0] == '/')) { + // Relative spec is absolute to the server + mFile = PL_strdup(cSpec); + } else { + char* dp = PL_strrchr(uFile, '/'); + PRInt32 dirlen = (dp + 1) - uFile; + mFile = (char*) malloc(dirlen + len); + PL_strncpy(mFile, uFile, dirlen); + PL_strcpy(mFile + dirlen, cSpec); + } + } else { + // absolute spec + + // get protocol first + PRInt32 plen = cp - cSpec; + mProtocol = (char*) malloc(plen + 1); + PL_strncpy(mProtocol, cSpec, plen); + mProtocol[plen] = 0; + cp++; // eat : in protocol + + // skip over one, two or three slashes + if (*cp == '/') { + cp++; + if (*cp == '/') { + cp++; + if (*cp == '/') { + cp++; + } + } + } else { + delete cSpec; + return NS_ERROR_ILLEGAL_VALUE; + } + + const char* cp0 = cp; + if ((PL_strcmp(mProtocol, "resource") == 0) || + (PL_strcmp(mProtocol, "file") == 0)) { + // resource/file url's do not have host names. + // The remainder of the string is the file name + PRInt32 flen = PL_strlen(cp); + mFile = (char*) malloc(flen + 1); + PL_strcpy(mFile, cp); + +#ifdef NS_WIN32 + if (PL_strcmp(mProtocol, "file") == 0) { + // If the filename starts with a "x|" where is an single + // character then we assume it's a drive name and change the + // vertical bar back to a ":" + if ((flen >= 2) && (mFile[1] == '|')) { + mFile[1] = ':'; + } + } +#endif + } else { + // Host name follows protocol for http style urls + cp = PL_strchr(cp, '/'); + if (nsnull == cp) { + // There is no file name, only a host name + PRInt32 hlen = PL_strlen(cp0); + mHost = (char*) malloc(hlen + 1); + PL_strcpy(mHost, cp0); + + // Set filename to "/" + mFile = (char*) malloc(2); + mFile[0] = '/'; + mFile[1] = 0; + } + else { + PRInt32 hlen = cp - cp0; + mHost = (char*) malloc(hlen + 1); + PL_strncpy(mHost, cp0, hlen); + mHost[hlen] = 0; + + // The rest is the file name + PRInt32 flen = PL_strlen(cp); + mFile = (char*) malloc(flen + 1); + PL_strcpy(mFile, cp); + } + } + } + +//printf("protocol='%s' host='%s' file='%s'\n", mProtocol, mHost, mFile); + delete cSpec; + return NS_OK; +} + +nsIInputStream* URLImpl::Open(PRInt32* aErrorCode) const +{ + nsresult rv; + nsIInputStream* in = nsnull; + + if (PL_strcmp(mProtocol, "file") == 0) { + rv = NS_OpenFile(&in, mFile); + } else if (PL_strcmp(mProtocol, "resource") == 0) { + rv = NS_OpenResource(&in, mFile); + } else { + nsINetService *inet; + + rv = NS_NewINetService(&inet, nsnull); + if (NS_OK == rv) { + rv = inet->OpenBlockingStream(mSpec, NULL, &in); + } + } + *aErrorCode = rv; + return in; +} + +NS_BASE nsresult NS_NewURL(nsIURL** aInstancePtrResult, + const nsString& aSpec) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + URLImpl* it = new URLImpl(aSpec); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kURLIID, (void **) aInstancePtrResult); +} + +NS_BASE nsresult NS_NewURL(nsIURL** aInstancePtrResult, + const nsIURL* aURL, + const nsString& aSpec) +{ + URLImpl* it = new URLImpl(aURL, aSpec); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kURLIID, (void **) aInstancePtrResult); +} + +NS_BASE nsresult NS_MakeAbsoluteURL(nsIURL* aURL, + const nsString& aBaseURL, + const nsString& aSpec, + nsString& aResult) +{ + if (0 < aBaseURL.Length()) { + URLImpl base(aBaseURL); + URLImpl url(&base, aSpec); + url.ToString(aResult); + } else { + URLImpl url(aURL, aSpec); + url.ToString(aResult); + } + return NS_OK; +} diff --git a/mozilla/base/src/nsUnicharBuffer.cpp b/mozilla/base/src/nsUnicharBuffer.cpp new file mode 100644 index 00000000000..8c001afe069 --- /dev/null +++ b/mozilla/base/src/nsUnicharBuffer.cpp @@ -0,0 +1,137 @@ +/* -*- 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 "nsIUnicharBuffer.h" +#include "nsIUnicharInputStream.h" +#include "nsCRT.h" + +#define MIN_BUFFER_SIZE 32 + +class UnicharBufferImpl : public nsIUnicharBuffer { +public: + UnicharBufferImpl(PRInt32 aBufferSize); + ~UnicharBufferImpl(); + + NS_DECL_ISUPPORTS + virtual PRInt32 GetLength() const; + virtual PRInt32 GetBufferSize() const; + virtual PRUnichar* GetBuffer() const; + virtual PRBool Grow(PRInt32 aNewSize); + virtual PRInt32 Fill(PRInt32* aErrorCode, nsIUnicharInputStream* aStream, + PRInt32 aKeep); + + PRUnichar* mBuffer; + PRInt32 mSpace; + PRInt32 mLength; +}; + +UnicharBufferImpl::UnicharBufferImpl(PRInt32 aBufferSize) +{ + if (PRUint32(aBufferSize) < MIN_BUFFER_SIZE) { + aBufferSize = MIN_BUFFER_SIZE; + } + mSpace = aBufferSize; + mBuffer = new PRUnichar[aBufferSize]; + mLength = 0; + NS_INIT_REFCNT(); +} + +NS_DEFINE_IID(kUnicharBufferIID, NS_IUNICHAR_BUFFER_IID); +NS_IMPL_ISUPPORTS(UnicharBufferImpl,kUnicharBufferIID) + +UnicharBufferImpl::~UnicharBufferImpl() +{ + if (nsnull != mBuffer) { + delete mBuffer; + mBuffer = nsnull; + } + mLength = 0; +} + +PRInt32 UnicharBufferImpl::GetLength() const +{ + return mLength; +} + +PRInt32 UnicharBufferImpl::GetBufferSize() const +{ + return mSpace; +} + +PRUnichar* UnicharBufferImpl::GetBuffer() const +{ + return mBuffer; +} + +PRBool UnicharBufferImpl::Grow(PRInt32 aNewSize) +{ + if (PRUint32(aNewSize) < MIN_BUFFER_SIZE) { + aNewSize = MIN_BUFFER_SIZE; + } + PRUnichar* newbuf = new PRUnichar[aNewSize]; + if (nsnull != newbuf) { + if (0 != mLength) { + nsCRT::memcpy(newbuf, mBuffer, mLength * sizeof(PRUnichar)); + } + delete mBuffer; + mBuffer = newbuf; + return PR_TRUE; + } + return PR_FALSE; +} + +PRInt32 UnicharBufferImpl::Fill(PRInt32* aErrorCode, + nsIUnicharInputStream* aStream, + PRInt32 aKeep) +{ + NS_PRECONDITION(nsnull != aStream, "null stream"); + NS_PRECONDITION(PRUint32(aKeep) < PRUint32(mLength), "illegal keep count"); + if ((nsnull == aStream) || (PRUint32(aKeep) >= PRUint32(mLength))) { + // whoops + *aErrorCode = NS_INPUTSTREAM_ILLEGAL_ARGS; + return -1; + } + + if (0 != aKeep) { + // Slide over kept data + nsCRT::memmove(mBuffer, mBuffer + (mLength - aKeep), + aKeep * sizeof(PRUnichar)); + } + + // Read in some new data + mLength = aKeep; + PRInt32 amount = mSpace - aKeep; + PRInt32 nb = aStream->Read(aErrorCode, mBuffer, aKeep, amount); + if (nb > 0) { + mLength += nb; + } + return nb; +} + +NS_BASE nsresult NS_NewUnicharBuffer(nsIUnicharBuffer** aInstancePtrResult, + nsISupports* aOuter, + PRInt32 aBufferSize) +{ + if (nsnull != aOuter) { + return NS_ERROR_NO_AGGREGATION; + } + UnicharBufferImpl* it = new UnicharBufferImpl(aBufferSize); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kUnicharBufferIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/base/src/nsUnicharInputStream.cpp b/mozilla/base/src/nsUnicharInputStream.cpp new file mode 100644 index 00000000000..24a7ec84981 --- /dev/null +++ b/mozilla/base/src/nsUnicharInputStream.cpp @@ -0,0 +1,328 @@ +/* -*- 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 "nsIUnicharInputStream.h" +#include "nsIByteBuffer.h" +#include "nsIUnicharBuffer.h" +#include "nsString.h" +#include "nsCRT.h" +#include +#ifdef NS_WIN32 +#include +#else +#include +#endif + +static NS_DEFINE_IID(kIUnicharInputStreamIID, NS_IUNICHAR_INPUT_STREAM_IID); + +class StringUnicharInputStream : public nsIUnicharInputStream { +public: + StringUnicharInputStream(nsString* aString); + ~StringUnicharInputStream(); + + NS_DECL_ISUPPORTS + + virtual PRInt32 Read(PRInt32* aErrorCode, + PRUnichar* aBuf, + PRInt32 aOffset, + PRInt32 aCount); + virtual void Close(); + + nsString* mString; + PRInt32 mPos; + PRInt32 mLen; +}; + +StringUnicharInputStream::StringUnicharInputStream(nsString* aString) +{ + mString = aString; + mPos = 0; + mLen = aString->Length(); +} + +StringUnicharInputStream::~StringUnicharInputStream() +{ + if (nsnull != mString) { + delete mString; + } +} + +PRInt32 StringUnicharInputStream::Read(PRInt32* aErrorCode, + PRUnichar* aBuf, + PRInt32 aOffset, + PRInt32 aCount) +{ + if (mPos >= mLen) { + return -1; + } + const PRUnichar* us = mString->GetUnicode(); + PRInt32 amount = mLen - mPos; + if (amount > aCount) { + amount = aCount; + } + nsCRT::memcpy(aBuf + aOffset, us + mPos, sizeof(PRUnichar) * amount); + mPos += amount; + return amount; +} + +void StringUnicharInputStream::Close() +{ + mPos = mLen; + if (nsnull != mString) { + delete mString; + } +} + +NS_IMPL_ISUPPORTS(StringUnicharInputStream, kIUnicharInputStreamIID); + +NS_BASE nsresult +NS_NewStringUnicharInputStream(nsIUnicharInputStream** aInstancePtrResult, + nsString* aString) +{ + NS_PRECONDITION(nsnull != aString, "null ptr"); + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if ((nsnull == aString) || (nsnull == aInstancePtrResult)) { + return NS_ERROR_NULL_POINTER; + } + + StringUnicharInputStream* it = new StringUnicharInputStream(aString); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(kIUnicharInputStreamIID, + (void**) aInstancePtrResult); +} + +//---------------------------------------------------------------------- + +class IsoLatin1Converter : public nsIB2UConverter { +public: + IsoLatin1Converter(); + + NS_DECL_ISUPPORTS + virtual PRInt32 Convert(PRUnichar* aDst, + PRInt32 aDstOffset, + PRInt32& aDstLen, + const char* aSrc, + PRInt32 aSrcOffset, + PRInt32& aSrcLen); +}; + +IsoLatin1Converter::IsoLatin1Converter() +{ + NS_INIT_REFCNT(); +} + +NS_DEFINE_IID(kIB2UConverterIID, NS_IB2UCONVERTER_IID); +NS_IMPL_ISUPPORTS(IsoLatin1Converter,kIB2UConverterIID); + +PRInt32 IsoLatin1Converter::Convert(PRUnichar* aDst, + PRInt32 aDstOffset, + PRInt32& aDstLen, + const char* aSrc, + PRInt32 aSrcOffset, + PRInt32& aSrcLen) +{ + PRInt32 amount = aSrcLen; + if (aSrcLen > aDstLen) { + amount = aDstLen; + } + const char* end = aSrc + amount; + while (aSrc < end) { + PRUint8 isoLatin1 = PRUint8(*aSrc++); + /* XXX insert table based lookup converter here */ + *aDst++ = isoLatin1; + } + aDstLen = amount; + aSrcLen = amount; + return NS_OK; +} + +NS_BASE nsresult +NS_NewB2UConverter(nsIB2UConverter** aInstancePtrResult, + nsISupports* aOuter, + nsCharSetID aCharSet) +{ + if (nsnull != aOuter) { + return NS_ERROR_NO_AGGREGATION; + } + if (eCharSetID_IsoLatin1 != aCharSet) { + return NS_INPUTSTREAM_NO_CONVERTER; + } + IsoLatin1Converter* it = new IsoLatin1Converter(); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIB2UConverterIID, (void**)aInstancePtrResult); +} + +//---------------------------------------------------------------------- + +class ConverterInputStream : public nsIUnicharInputStream { +public: + ConverterInputStream(nsIInputStream* aStream, + nsIB2UConverter* aConverter, + PRInt32 aBufSize); + ~ConverterInputStream(); + + NS_DECL_ISUPPORTS + virtual PRInt32 Read(PRInt32* aErrorCode, + PRUnichar* aBuf, + PRInt32 aOffset, + PRInt32 aCount); + virtual void Close(); + +protected: + PRInt32 Fill(PRInt32* aErrorCode); + + nsIInputStream* mInput; + nsIB2UConverter* mConverter; + nsIByteBuffer* mByteData; + PRInt32 mByteDataOffset; + nsIUnicharBuffer* mUnicharData; + PRInt32 mUnicharDataOffset; + PRInt32 mUnicharDataLength; +}; + +ConverterInputStream::ConverterInputStream(nsIInputStream* aStream, + nsIB2UConverter* aConverter, + PRInt32 aBufferSize) +{ + NS_INIT_REFCNT(); + mInput = aStream; aStream->AddRef(); + mConverter = aConverter; aConverter->AddRef(); + if (aBufferSize == 0) { + aBufferSize = 8192; + } + nsresult rv1 = NS_NewByteBuffer(&mByteData, nsnull, aBufferSize); + nsresult rv2 = NS_NewUnicharBuffer(&mUnicharData, nsnull, aBufferSize); + mByteDataOffset = 0; + mUnicharDataOffset = 0; + mUnicharDataLength = 0; +} + +NS_IMPL_ISUPPORTS(ConverterInputStream,kIUnicharInputStreamIID); + +ConverterInputStream::~ConverterInputStream() +{ + Close(); +} + +void ConverterInputStream::Close() +{ + if (nsnull != mInput) { + mInput->Release(); + mInput = nsnull; + } + if (nsnull != mConverter) { + mConverter->Release(); + mConverter = nsnull; + } + if (nsnull != mByteData) { + mByteData->Release(); + mByteData = nsnull; + } + if (nsnull != mUnicharData) { + mUnicharData->Release(); + mUnicharData = nsnull; + } +} + +PRInt32 ConverterInputStream::Read(PRInt32* aErrorCode, + PRUnichar* aBuf, + PRInt32 aOffset, + PRInt32 aCount) +{ + PRInt32 rv = mUnicharDataLength - mUnicharDataOffset; + if (0 == rv) { + // Fill the unichar buffer + rv = Fill(aErrorCode); + if (rv <= 0) { + return rv; + } + } + if (rv > aCount) { + rv = aCount; + } + nsCRT::memcpy(aBuf + aOffset, mUnicharData->GetBuffer() + mUnicharDataOffset, + rv * sizeof(PRUnichar)); + mUnicharDataOffset += rv; + return rv; +} + +PRInt32 ConverterInputStream::Fill(PRInt32* aErrorCode) +{ + if (nsnull == mInput) { + // We already closed the stream! + *aErrorCode = NS_INPUTSTREAM_CLOSED; + return -1; + } + + PRInt32 remainder = mByteData->GetLength() - mByteDataOffset; + mByteDataOffset = remainder; + PRInt32 nb = mByteData->Fill(aErrorCode, mInput, remainder); + if (nb <= 0) { + // Because we assume a many to one conversion, the lingering data + // in the byte buffer must be a partial conversion + // fragment. Because we know that we have recieved no more new + // data to add to it, we can't convert it. Therefore, we discard + // it. + return nb; + } + NS_ASSERTION(remainder + nb == mByteData->GetLength(), "bad nb"); + + // Now convert as much of the byte buffer to unicode as possible + PRInt32 dstLen = mUnicharData->GetBufferSize(); + PRInt32 srcLen = remainder + nb; + *aErrorCode = mConverter->Convert(mUnicharData->GetBuffer(), 0, dstLen, + mByteData->GetBuffer(), 0, srcLen); + mUnicharDataOffset = 0; + mUnicharDataLength = dstLen; + mByteDataOffset += srcLen; + return dstLen; +} + +// XXX hook up auto-detect here (do we need more info, like the url?) +NS_BASE nsresult +NS_NewConverterStream(nsIUnicharInputStream** aInstancePtrResult, + nsISupports* aOuter, + nsIInputStream* aStreamToWrap, + PRInt32 aBufferSize, + nsCharSetID aCharSet) +{ + if (nsnull != aOuter) { + return NS_ERROR_NO_AGGREGATION; + } + + // Create converter + nsIB2UConverter* converter; + nsresult rv = NS_NewB2UConverter(&converter, nsnull, aCharSet); + if (NS_OK != rv) { + return rv; + } + + // Create converter input stream + ConverterInputStream* it = + new ConverterInputStream(aStreamToWrap, converter, aBufferSize); + converter->Release(); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIUnicharInputStreamIID, + (void **) aInstancePtrResult); +} diff --git a/mozilla/base/src/nsUnitConversion.h b/mozilla/base/src/nsUnitConversion.h new file mode 100644 index 00000000000..14a579326f2 --- /dev/null +++ b/mozilla/base/src/nsUnitConversion.h @@ -0,0 +1,71 @@ +/* -*- 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. + */ +#ifndef nsUnitConversion_h__ +#define nsUnitConversion_h__ + +#include "nscore.h" +#include + +/// Unit conversion macros +//@{ +#define TWIPS_CONST 20 +#define TWIPS_CONST_FLOAT 20.0f + +#define NS_POINTS_TO_TWIPS_INT(x) ((PRInt32)(TWIPS_CONST * (x))) +#define NS_TWIPS_TO_POINTS_INT(x) ((PRInt32)((x) / TWIPS_CONST)) + +#define NS_POINTS_TO_TWIPS_FLOAT(x) (TWIPS_CONST_FLOAT * (x)) +#define NS_TWIPS_TO_POINTS_FLOAT(x) ((x) / TWIPS_CONST_FLOAT) + +#define NS_INCHES_TO_TWIPS(x) (72.0f * TWIPS_CONST_FLOAT * (x)) // 72 points per inch +#define NS_FEET_TO_TWIPS(x) (72.0f * 12.0f * TWIPS_CONST_FLOAT * (x)) +#define NS_MILES_TO_TWIPS(x) (72.0f * 12.0f * 5280.0f * TWIPS_CONST_FLOAT * (x)) + +#define NS_MILLIMETERS_TO_TWIPS(x) (72.0f * 0.03937f * TWIPS_CONST_FLOAT * (x)) +#define NS_CENTIMETERS_TO_TWIPS(x) (72.0f * 0.3937f * TWIPS_CONST_FLOAT * (x)) +#define NS_METERS_TO_TWIPS(x) (72.0f * 39.37f * TWIPS_CONST_FLOAT * (x)) +#define NS_KILOMETERS_TO_TWIPS(x) (72.0f * 39370.0f * TWIPS_CONST_FLOAT * (x)) + +#define NS_PICAS_TO_TWIPS(x) (12.0f * TWIPS_CONST_FLOAT * (x)) // 12 points per pica +#define NS_DIDOTS_TO_TWIPS(x) ((16.0f / 15.0f) * TWIPS_CONST_FLOAT * (x)) // 15 didots per 16 points +#define NS_CICEROS_TO_TWIPS(x) ((12.0f * 16.0f / 15.0f) * TWIPS_CONST_FLOAT * (x)) // 12 didots per cicero + +#define NS_TWIPS_TO_INCHES(x) ((1.0f / (72.0f * TWIPS_CONST_FLOAT)) * (x)) +#define NS_TWIPS_TO_FEET(x) ((1.0f / (72.0f * 12.0f * TWIPS_CONST_FLOAT)) * (x)) +#define NS_TWIPS_TO_MILES(x) ((1.0f / (72.0f * 12.0f * 5280.0f * TWIPS_CONST_FLOAT)) * (x)) + +#define NS_TWIPS_TO_MILLIMETERS(x) ((1.0f / (72.0f * 0.03937f * TWIPS_CONST_FLOAT)) * (x)) +#define NS_TWIPS_TO_CENTIMETERS(x) ((1.0f / (72.0f * 0.3937f * TWIPS_CONST_FLOAT)) * (x)) +#define NS_TWIPS_TO_METERS(x) ((1.0f / (72.0f * 39.37f * TWIPS_CONST_FLOAT)) * (x)) +#define NS_TWIPS_TO_KILOMETERS(x) ((1.0f / (72.0f * 39370.0f * TWIPS_CONST_FLOAT)) * (x)) + +#define NS_TWIPS_TO_PICAS(x) ((1.0f / (12.0f * TWIPS_CONST_FLOAT)) * (x)) +#define NS_TWIPS_TO_DIDOTS(x) ((1.0f / ((16.0f / 15.0f) * TWIPS_CONST_FLOAT)) * (x)) +#define NS_TWIPS_TO_CICEROS(x) ((1.0f / ((12.0f * 16.0f / 15.0f) * TWIPS_CONST_FLOAT)) * (x)) +//@} + + +/// use these for all of your rounding needs... +//@{ + +#define NS_TO_INT_FLOOR(x) ((PRInt32)floor(x)) +#define NS_TO_INT_CEIL(x) ((PRInt32)ceil(x)) +#define NS_TO_INT_ROUND(x) ((PRInt32)floor((x) + 0.5)) +#define NS_TO_INT_ROUND_EXCLUSIVE(x) ((PRInt32)floor((x) + 0.4999999999999999)) +//@} +#endif diff --git a/mozilla/base/src/nsVoidArray.cpp b/mozilla/base/src/nsVoidArray.cpp new file mode 100644 index 00000000000..7f52d1fe1c1 --- /dev/null +++ b/mozilla/base/src/nsVoidArray.cpp @@ -0,0 +1,172 @@ +/* -*- 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 "nsVoidArray.h" +#include "nsCRT.h" + +static PRInt32 kGrowArrayBy = 8; + +nsVoidArray::nsVoidArray() +{ + mArray = nsnull; + mArraySize = 0; + mCount = 0; +} + +nsVoidArray& nsVoidArray::operator=(const nsVoidArray& other) +{ + if (nsnull != mArray) { + delete mArray; + } + PRInt32 otherCount = other.mCount; + mArraySize = otherCount; + mCount = otherCount; + if (otherCount != 0) { + mArray = new void*[otherCount]; + nsCRT::memcpy(mArray, other.mArray, otherCount * sizeof(void*)); + } else { + mArray = nsnull; + } + return *this; +} + +nsVoidArray::~nsVoidArray() +{ + if (nsnull != mArray) { + delete mArray; + } +} + +void* nsVoidArray::ElementAt(PRInt32 aIndex) const +{ + if (PRUint32(aIndex) >= PRUint32(mCount)) { + return nsnull; + } + return mArray[aIndex]; +} + +PRInt32 nsVoidArray::IndexOf(void* aPossibleElement) const +{ + void** ap = mArray; + void** end = ap + mCount; + while (ap < end) { + if (*ap == aPossibleElement) { + return ap - mArray; + } + ap++; + } + return -1; +} + +PRBool nsVoidArray::InsertElementAt(void* aElement, PRInt32 aIndex) +{ + PRInt32 oldCount = mCount; + if (PRUint32(aIndex) > PRUint32(oldCount)) { + // An invalid index causes the insertion to fail + return PR_FALSE; + } + + if (oldCount + 1 > mArraySize) { + // We have to grow the array + PRInt32 newCount = oldCount + kGrowArrayBy; + void** newArray = new void*[newCount]; + if (mArray != nsnull && aIndex != 0) + nsCRT::memcpy(newArray, mArray, aIndex * sizeof(void*)); + PRInt32 slide = oldCount - aIndex; + if (0 != slide) { + // Slide data over to make room for the insertion + nsCRT::memcpy(newArray + aIndex + 1, mArray + aIndex, + slide * sizeof(void*)); + } + if (mArray != nsnull) + delete mArray; + mArray = newArray; + mArraySize = newCount; + } else { + // The array is already large enough + PRInt32 slide = oldCount - aIndex; + if (0 != slide) { + // Slide data over to make room for the insertion + nsCRT::memmove(mArray + aIndex + 1, mArray + aIndex, + slide * sizeof(void*)); + } + } + mArray[aIndex] = aElement; + mCount++; + + return PR_TRUE; +} + +PRBool nsVoidArray::ReplaceElementAt(void* aElement, PRInt32 aIndex) +{ + if (PRUint32(aIndex) >= PRUint32(mCount)) { + // An invalid index causes the replace to fail + return PR_FALSE; + } + mArray[aIndex] = aElement; + return PR_TRUE; +} + +PRBool nsVoidArray::RemoveElementAt(PRInt32 aIndex) +{ + PRInt32 oldCount = mCount; + if (PRUint32(aIndex) >= PRUint32(oldCount)) { + // An invalid index causes the replace to fail + return PR_FALSE; + } + + // We don't need to move any elements if we're removing the + // last element in the array + if (aIndex < (oldCount - 1)) { + nsCRT::memmove(mArray + aIndex, mArray + aIndex + 1, + (oldCount - 1 - aIndex) * sizeof(void*)); + } + + mCount--; + return PR_TRUE; +} + +PRBool nsVoidArray::RemoveElement(void* aElement) +{ + void** ep = mArray; + void** end = ep + mCount; + while (ep < end) { + void* e = *ep++; + if (e == aElement) { + ep--; + return RemoveElementAt(PRInt32(ep - mArray)); + } + } + return PR_FALSE; +} + +void nsVoidArray::Clear() +{ + mCount = 0; +} + +void nsVoidArray::Compact() +{ + PRInt32 count = mCount; + if (mArraySize != count) { + void** newArray = new void*[count]; + nsCRT::memcpy(newArray, mArray, count * sizeof(void*)); + delete mArray; + mArray = newArray; + mArraySize = count; + } +} diff --git a/mozilla/base/src/nsVoidArray.h b/mozilla/base/src/nsVoidArray.h new file mode 100644 index 00000000000..40394ff3b3e --- /dev/null +++ b/mozilla/base/src/nsVoidArray.h @@ -0,0 +1,64 @@ +/* -*- 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. + */ +#ifndef nsVoidArray_h___ +#define nsVoidArray_h___ + +#include "nscore.h" + +/// A basic zero-based array of void*'s that manages its own memory +class NS_BASE nsVoidArray { +public: + nsVoidArray(); + ~nsVoidArray(); + + nsVoidArray& operator=(const nsVoidArray& other); + + PRInt32 Count() const { + return mCount; + } + + void* ElementAt(PRInt32 aIndex) const; + void* operator[](PRInt32 aIndex) const { return ElementAt(aIndex); } + + PRInt32 IndexOf(void* aPossibleElement) const; + + PRBool InsertElementAt(void* aElement, PRInt32 aIndex); + + PRBool ReplaceElementAt(void* aElement, PRInt32 aIndex); + + PRBool AppendElement(void* aElement) { + return InsertElementAt(aElement, mCount); + } + + PRBool RemoveElement(void* aElement); + PRBool RemoveElementAt(PRInt32 aIndex); + void Clear(); + + void Compact(); + +protected: + void** mArray; + PRInt32 mArraySize; + PRInt32 mCount; + +private: + /// Copy constructors are not allowed + nsVoidArray(const nsVoidArray& other); +}; + +#endif /* nsVoidArray_h___ */ diff --git a/mozilla/base/src/nscore.h b/mozilla/base/src/nscore.h new file mode 100644 index 00000000000..25c08e06961 --- /dev/null +++ b/mozilla/base/src/nscore.h @@ -0,0 +1,100 @@ +/* -*- 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. + */ +#ifndef nscore_h___ +#define nscore_h___ + +#ifdef _WIN32 +#define NS_WIN32 1 +#endif + +#include "prtypes.h" +#include "nsDebug.h" + +/** ucs2 datatype for 2 byte unicode characters */ +typedef PRUint16 PRUcs2; + +/** ucs4 datatype for 4 byte unicode characters */ +typedef PRUint32 PRUcs4; + +#ifdef NS_UCS4 +typedef PRUcs4 PRUnichar; +#else +typedef PRUcs2 PRUnichar; +#endif + +/// The preferred symbol for null. +#define nsnull 0 + +/* Define brackets for protecting C code from C++ */ +#ifdef __cplusplus +#define NS_BEGIN_EXTERN_C extern "C" { +#define NS_END_EXTERN_C } +#else +#define NS_BEGIN_EXTERN_C +#define NS_END_EXTERN_C +#endif + +/*----------------------------------------------------------------------*/ +/* Import/export defines */ + +#ifdef NS_WIN32 +#define NS_IMPORT _declspec(dllimport) +#define NS_EXPORT _declspec(dllexport) +#else +/* XXX do something useful? */ +#define NS_IMPORT +#define NS_EXPORT +#endif + +#ifdef _IMPL_NS_BASE +#define NS_BASE NS_EXPORT +#else +#define NS_BASE NS_IMPORT +#endif + +#ifdef _IMPL_NS_DOM +#define NS_DOM NS_EXPORT +#else +#define NS_DOM NS_IMPORT +#endif + +#ifdef _IMPL_NS_WIDGET +#define NS_WIDGET NS_EXPORT +#else +#define NS_WIDGET NS_IMPORT +#endif + +#ifdef _IMPL_NS_VIEW +#define NS_VIEW NS_EXPORT +#else +#define NS_VIEW NS_IMPORT +#endif + +#ifdef _IMPL_NS_GFXNONXP +#define NS_GFXNONXP NS_EXPORT +#else +#define NS_GFXNONXP NS_IMPORT +#endif + +#ifdef _IMPL_NS_GFX +#define NS_GFX NS_EXPORT +#else +#define NS_GFX NS_IMPORT +#endif + +#endif /* nscore_h___ */ diff --git a/mozilla/base/src/windows/makefile.win b/mozilla/base/src/windows/makefile.win new file mode 100644 index 00000000000..b2b0ca66af7 --- /dev/null +++ b/mozilla/base/src/windows/makefile.win @@ -0,0 +1,40 @@ +#!nmake +# +# 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. + +DEPTH=..\..\.. +IGNORE_MANIFEST=1 + +DEFINES=-D_IMPL_NS_BASE +LIBRARY_NAME=gmbase +MODULE=raptor +REQUIRES=xpcom raptor + +CPPSRCS=nsTimer.cpp + +CPP_OBJS=.\$(OBJDIR)\nsTimer.obj + +LINCS=-I$(XPDIST)\public\xpcom -I$(XPDIST)\public\raptor + +LCFLAGS = \ + $(LCFLAGS) \ + -D_IMPL_NS_BASE \ + $(NULL) + +include <$(DEPTH)\config\rules.mak> + +libs:: $(OBJS) + $(MAKE_INSTALL) $(OBJDIR)\nsTimer.obj ..\$(OBJDIR) diff --git a/mozilla/base/src/windows/nsTimer.cpp b/mozilla/base/src/windows/nsTimer.cpp new file mode 100644 index 00000000000..ed7bb8deeed --- /dev/null +++ b/mozilla/base/src/windows/nsTimer.cpp @@ -0,0 +1,364 @@ +/* -*- 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 "nsITimer.h" +#include "nsITimerCallback.h" +#include "nsCRT.h" +#include "prlog.h" +#include +#include +#include + +static NS_DEFINE_IID(kITimerIID, NS_ITIMER_IID); + +/* + * Implementation of timers lifted from Windows front-end file timer.cpp + */ +class TimerImpl : public nsITimer { +public: + static TimerImpl *gTimerList; + static UINT gWindowsTimer; + static DWORD gNextFire; + static DWORD gSyncHack; + + static void ProcessTimeouts(DWORD aNow); + static void SyncTimeoutPeriod(DWORD aTickCount); + +public: + TimerImpl(); + ~TimerImpl(); + + virtual nsresult Init(nsTimerCallbackFunc aFunc, + void *aClosure, +// PRBool aRepeat, + PRUint32 aDelay); + + virtual nsresult Init(nsITimerCallback *aCallback, +// PRBool aRepeat, + PRUint32 aDelay); + + NS_DECL_ISUPPORTS + + virtual void Cancel(); + void Fire(DWORD aNow); + + virtual PRUint32 GetDelay() { return mDelay; } + virtual void SetDelay(PRUint32 aDelay) {}; + +private: + nsresult Init(PRUint32 aDelay); + + PRUint32 mDelay; + nsTimerCallbackFunc mFunc; + void *mClosure; + nsITimerCallback *mCallback; + DWORD mFireTime; + // PRBool mRepeat; + TimerImpl *mNext; +}; + +TimerImpl *TimerImpl::gTimerList = NULL; +UINT TimerImpl::gWindowsTimer = 0; +DWORD TimerImpl::gNextFire = (DWORD)-1; +DWORD TimerImpl::gSyncHack = 0; + +void CALLBACK FireTimeout(HWND aWindow, + UINT aMessage, + UINT aTimerID, + DWORD aTime) +{ + static BOOL bCanEnter = TRUE; + + // Don't allow old timer messages in here. + if(aMessage != WM_TIMER) { + PR_ASSERT(0); + return; + } + + if(aTimerID != TimerImpl::gWindowsTimer) { + return; + } + + // Block only one entry into this function, or else. + if(bCanEnter) { + bCanEnter = FALSE; + // see if we need to fork off any timeout functions + if(TimerImpl::gTimerList) { + TimerImpl::ProcessTimeouts(aTime); + } + bCanEnter = TRUE; + } +} + +// Function to correctly have the timer be set. +void +TimerImpl::SyncTimeoutPeriod(DWORD aTickCount) +{ + // May want us to set tick count ourselves. + if(aTickCount == 0) { + if(gSyncHack == 0) { + aTickCount = ::GetTickCount(); + } + else { + aTickCount = gSyncHack; + } + } + + // If there's no list, we should clear the timer. + if(!gTimerList) { + if(gWindowsTimer) { + ::KillTimer(NULL, gWindowsTimer); + gWindowsTimer = 0; + gNextFire = (DWORD)-1; + } + } + else { + // See if we need to clear the current timer. + // Curcumstances are that if the timer will not + // fire on time for the next timeout. + BOOL bSetTimer = FALSE; + TimerImpl *pTimeout = gTimerList; + if(gWindowsTimer) { + if(pTimeout->mFireTime != gNextFire) { + ::KillTimer(NULL, gWindowsTimer); + gWindowsTimer = 0; + gNextFire = (DWORD)-1; + + // Set the timer. + bSetTimer = TRUE; + } + } + else { + // No timer set, attempt. + bSetTimer = TRUE; + } + + if(bSetTimer) { + DWORD dwFireWhen = pTimeout->mFireTime > aTickCount ? + pTimeout->mFireTime - aTickCount : 0; + if(dwFireWhen > UINT_MAX) { + dwFireWhen = UINT_MAX; + } + UINT uFireWhen = (UINT)dwFireWhen; + + PR_ASSERT(gWindowsTimer == 0); + gWindowsTimer = ::SetTimer(NULL, 0, uFireWhen, (TIMERPROC)FireTimeout); + + if(gWindowsTimer) { + // Set the fire time. + gNextFire = pTimeout->mFireTime; + } + } + } +} + +// Walk down the timeout list and launch anyone appropriate +void +TimerImpl::ProcessTimeouts(DWORD aNow) +{ + TimerImpl *p = gTimerList; + if(aNow == 0) { + aNow = ::GetTickCount(); + } + + BOOL bCalledSync = FALSE; + + // Set the hack, such that when FE_ClearTimeout + // calls SyncTimeoutPeriod, that GetTickCount() + // overhead is not incurred. + gSyncHack = aNow; + + // loop over all entries + while(p) { + // send it + if(p->mFireTime < aNow) { + p->Fire(aNow); + + // Clear the timer. + // Period synced. + p->Cancel(); + bCalledSync = TRUE; + + // Reset the loop (can't look at p->pNext now, and called + // code may have added/cleared timers). + // (could do this by going recursive and returning). + p = gTimerList; + } else { + // Make sure we fire an timer. + // Also, we need to check to see if things are backing up (they + // may be asking to be fired long before we ever get to them, + // and we don't want to pass in negative values to the real + // timer code, or it takes days to fire.... + if(bCalledSync == FALSE) { + SyncTimeoutPeriod(aNow); + bCalledSync = TRUE; + } + // Get next timer. + p = p->mNext; + } + } + gSyncHack = 0; +} + + +TimerImpl::TimerImpl() +{ + NS_INIT_REFCNT(); + mFunc = NULL; + mCallback = NULL; + mNext = NULL; +} + +TimerImpl::~TimerImpl() +{ +} + +nsresult +TimerImpl::Init(nsTimerCallbackFunc aFunc, + void *aClosure, +// PRBool aRepeat, + PRUint32 aDelay) +{ + mFunc = aFunc; + mClosure = aClosure; + // mRepeat = aRepeat; + + return Init(aDelay); +} + +nsresult +TimerImpl::Init(nsITimerCallback *aCallback, +// PRBool aRepeat, + PRUint32 aDelay) +{ + mCallback = aCallback; + // mRepeat = aRepeat; + + return Init(aDelay); +} + +nsresult +TimerImpl::Init(PRUint32 aDelay) +{ + DWORD dwNow = ::GetTickCount(); + + mDelay = aDelay; + mFireTime = (DWORD) aDelay + dwNow; + mNext = NULL; + + // add it to the list + if(!gTimerList) { + // no list add it + gTimerList = this; + } + else { + + // is it before everything else on the list? + if(mFireTime < gTimerList->mFireTime) { + + mNext = gTimerList; + gTimerList = this; + + } else { + + TimerImpl * pPrev = gTimerList; + TimerImpl * pCurrent = gTimerList; + + while(pCurrent && (pCurrent->mFireTime <= mFireTime)) { + pPrev = pCurrent; + pCurrent = pCurrent->mNext; + } + + PR_ASSERT(pPrev); + + // insert it after pPrev (this could be at the end of the list) + mNext = pPrev->mNext; + pPrev->mNext = this; + + } + + } + + NS_ADDREF(this); + + // Sync the timer fire period. + SyncTimeoutPeriod(dwNow); + + return NS_OK; +} + +NS_IMPL_ISUPPORTS(TimerImpl, kITimerIID) + +void +TimerImpl::Fire(DWORD aNow) +{ + if (mFunc != NULL) { + (*mFunc)(this, mClosure); + } + else if (mCallback != NULL) { + mCallback->Notify(this); + } +} + +void +TimerImpl::Cancel() +{ + TimerImpl *me = this; + + if(gTimerList == this) { + + // first element in the list lossage + gTimerList = mNext; + + } else { + + // walk until no next pointer + for(TimerImpl * p = gTimerList; p && p->mNext && (p->mNext != this); p = p->mNext) + ; + + // if we found something valid pull it out of the list + if(p && p->mNext && p->mNext == this) { + p->mNext = mNext; + + } else { + // get out before we delete something that looks bogus + return; + } + + } + + // if we got here it must have been a valid element so trash it + NS_RELEASE(me); + + // If there's now no be sure to clear the timer. + SyncTimeoutPeriod(0); +} + +NS_BASE nsresult NS_NewTimer(nsITimer** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + + TimerImpl *timer = new TimerImpl(); + if (nsnull == timer) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return timer->QueryInterface(kITimerIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/base/tests/CvtURL.cpp b/mozilla/base/tests/CvtURL.cpp new file mode 100644 index 00000000000..365b687431a --- /dev/null +++ b/mozilla/base/tests/CvtURL.cpp @@ -0,0 +1,104 @@ +/* -*- 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 +#include "nsIUnicharInputStream.h" +#include "nsIURL.h" +#include "nsCRT.h" +#include "nsString.h" +#include "prprf.h" +#include "prtime.h" + +static nsCharSetID ConvertCharacterSetName(const char* aName) +{ + if (nsCRT::strcasecmp(aName, "iso-latin-1") == 0) { + return eCharSetID_IsoLatin1; + } + return (nsCharSetID) -1; +} + +int main(int argc, char** argv) +{ + if (3 != argc) { + printf("usage: CvtURL url character-set-name\n"); + return -1; + } + + char* characterSetName = argv[2]; + nsCharSetID cset = ConvertCharacterSetName(characterSetName); + if (PRInt32(cset) < 0) { + printf("illegal character set name: '%s'\n", characterSetName); + return -1; + } + + // Create url object + char* urlName = argv[1]; + nsIURL* url; + nsresult rv = NS_NewURL(&url, urlName); + if (NS_OK != rv) { + printf("invalid URL: '%s'\n", urlName); + return -1; + } + + // Get an input stream from the url + PRInt32 ec; + nsIInputStream* in = url->Open(&ec); + if (nsnull == in) { + printf("open of url('%s') failed: error=%x\n", urlName, ec); + return -1; + } + + // Translate the input using the argument character set id into unicode + nsIUnicharInputStream* uin; + rv = NS_NewConverterStream(&uin, nsnull, in, 0, cset); + if (NS_OK != rv) { + printf("can't create converter input stream: %d\n", rv); + return -1; + } + + // Read the input and write some output + PRTime start = PR_Now(); + PRInt32 count = 0; + for (;;) { + PRUnichar buf[1000]; + PRInt32 nb = uin->Read(&ec, buf, 0, 1000); + if (nb <= 0) { + if (nb < 0) { + printf("i/o error: %d\n", ec); + } + break; + } + count += nb; + } + PRTime end = PR_Now(); + PRTime conversion, ustoms; + LL_I2L(ustoms, 1000); + LL_SUB(conversion, end, start); + LL_DIV(conversion, conversion, ustoms); + char buf[500]; + PR_snprintf(buf, sizeof(buf), + "converting and discarding %d bytes took %lldms", + count, conversion); + puts(buf); + + // Release the objects + in->Release(); + uin->Release(); + url->Release(); + + return 0; +} diff --git a/mozilla/base/tests/Makefile b/mozilla/base/tests/Makefile new file mode 100644 index 00000000000..ba8b5ee84ff --- /dev/null +++ b/mozilla/base/tests/Makefile @@ -0,0 +1,55 @@ +#!gmake +# +# 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. + +DEPTH=../../.. + +include $(DEPTH)/config/config.mk + +CPPSRCS = \ + TestAtoms.cpp \ + TestCRT.cpp \ + $(NULL) + +INCLUDES+=-I../src -I$(PUBLIC)/xpcom + +OBJS = $(CPPSRCS:.cpp=.o) + +EX_LIBS = \ + $(DIST)/lib/libraptorbase.a \ + $(DIST)/lib/libxpcom.a \ + $(DIST)/lib/libplc21.a \ + $(DIST)/lib/libplds21.a \ + $(DIST)/lib/libnspr21.a \ + $(NULL) + +PROGS = $(addprefix $(OBJDIR)/, $(CPPSRCS:.cpp=)) + +TARGETS = $(PROGS) + +include $(DEPTH)/config/rules.mk + +$(OBJDIR)/%.o: %.cpp + @$(MAKE_OBJDIR) + $(CCC) -o $@ $(CFLAGS) -c $*.cpp + +$(PROGS):$(OBJDIR)/%: $(OBJDIR)/%.o $(EX_LIBS) + @$(MAKE_OBJDIR) + $(CCC) -o $@ $@.o $(LDFLAGS) $(EX_LIBS) $(OS_LIBS) + +install:: $(TARGETS) + $(INSTALL) $(TARGETS) $(DIST)/bin + diff --git a/mozilla/base/tests/TestAtoms.cpp b/mozilla/base/tests/TestAtoms.cpp new file mode 100644 index 00000000000..745a424a4ec --- /dev/null +++ b/mozilla/base/tests/TestAtoms.cpp @@ -0,0 +1,108 @@ +/* -*- 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 "nsIAtom.h" +#include "nsString.h" +#include "prprf.h" +#include "prtime.h" +#include + +extern "C" int _CrtSetDbgFlag(int); + +int main(int argc, char** argv) +{ + FILE* fp = fopen("words.txt", "r"); + if (nsnull == fp) { + printf("can't open words.txt\n"); + return -1; + } + + PRInt32 count = 0; + PRUnichar** strings = new PRUnichar*[60000]; + nsIAtom** ids = new nsIAtom*[60000]; + nsAutoString s1, s2; + PRTime start = PR_Now(); + for (PRInt32 i = 0; i < 60000; i++) { + char buf[1000]; + char* s = fgets(buf, sizeof(buf), fp); + if (nsnull == s) { + break; + } + nsAutoString sb(buf); + strings[count++] = sb.ToNewUnicode(); + sb.ToUpperCase(); + strings[count++] = sb.ToNewUnicode(); + } + PRTime end0 = PR_Now(); + + // Find and create idents + for (i = 0; i < count; i++) { + ids[i] = NS_NewAtom(strings[i]); + } + PRUnichar qqs[1]; qqs[0] = 0; + nsIAtom* qq = NS_NewAtom(qqs); + PRTime end1 = PR_Now(); + + // Now make sure we can find all the idents we just made + for (i = 0; i < count; i++) { + nsIAtom* id = NS_NewAtom(ids[i]->GetUnicode()); + if (id != ids[i]) { + id->ToString(s1); + ids[i]->ToString(s2); + printf("find failed: id='%s' ids[%d]='%s'\n", + s1.ToNewCString(), i, s2.ToNewCString()); + return -1; + } + NS_RELEASE(id); + } + PRTime end2 = PR_Now(); + + // Destroy all the atoms we just made + NS_RELEASE(qq); + for (i = 0; i < count; i++) { + NS_RELEASE(ids[i]); + } + + // Print out timings + PRTime end3 = PR_Now(); + PRTime creates, finds, lookups, dtor, ustoms; + LL_I2L(ustoms, 1000); + LL_SUB(creates, end0, start); + LL_DIV(creates, creates, ustoms); + LL_SUB(finds, end1, end0); + LL_DIV(finds, finds, ustoms); + LL_SUB(lookups, end2, end1); + LL_DIV(lookups, lookups, ustoms); + LL_SUB(dtor, end3, end2); + char buf[500]; + PR_snprintf(buf, sizeof(buf), "making %d ident strings took %lldms", + count, creates); + puts(buf); + PR_snprintf(buf, sizeof(buf), "%d new idents took %lldms", + count, finds); + puts(buf); + PR_snprintf(buf, sizeof(buf), "%d ident lookups took %lldms", + count, lookups); + puts(buf); + PR_snprintf(buf, sizeof(buf), "dtor took %lldusec", dtor); + puts(buf); + + printf("%d live atoms\n", NS_GetNumberOfAtoms()); + NS_POSTCONDITION(0 == NS_GetNumberOfAtoms(), "dangling atoms"); + + return 0; +} diff --git a/mozilla/base/tests/TestCRT.cpp b/mozilla/base/tests/TestCRT.cpp new file mode 100644 index 00000000000..951a3a741cf --- /dev/null +++ b/mozilla/base/tests/TestCRT.cpp @@ -0,0 +1,89 @@ +/* -*- 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 "nsCRT.h" +#include "nsString.h" +#include "plstr.h" +#include + +// Verify that nsCRT versions of string comparison routines get the +// same answers as the native non-unicode versions. We only pass in +// iso-latin-1 strings, so the comparision must be valid. +static void Check(const char* s1, const char* s2, PRIntn n) +{ + PRIntn clib = PL_strcmp(s1, s2); + PRIntn clib_n = PL_strncmp(s1, s2, n); + PRIntn clib_case = PL_strcasecmp(s1, s2); + PRIntn clib_case_n = PL_strncasecmp(s1, s2, n); + + nsAutoString t1(s1), t2(s2); + PRUnichar* us1 = t1.GetUnicode(); + PRUnichar* us2 = t2.GetUnicode(); + + PRIntn u = nsCRT::strcmp(us1, s2); + PRIntn u_n = nsCRT::strncmp(us1, s2, n); + PRIntn u_case = nsCRT::strcasecmp(us1, s2); + PRIntn u_case_n = nsCRT::strncasecmp(us1, s2, n); + + PRIntn u2 = nsCRT::strcmp(us1, us2); + PRIntn u2_n = nsCRT::strncmp(us1, us2, n); + PRIntn u2_case = nsCRT::strcasecmp(us1, us2); + PRIntn u2_case_n = nsCRT::strncasecmp(us1, us2, n); + + NS_ASSERTION(clib == u, "strcmp"); + NS_ASSERTION(clib_n == u_n, "strncmp"); + NS_ASSERTION(clib_case == u_case, "strcasecmp"); + NS_ASSERTION(clib_case_n == u_case_n, "strncasecmp"); + + NS_ASSERTION(clib == u2, "strcmp"); + NS_ASSERTION(clib_n == u2_n, "strncmp"); + NS_ASSERTION(clib_case == u2_case, "strcasecmp"); + NS_ASSERTION(clib_case_n == u2_case_n, "strncasecmp"); +} + +struct Test { + const char* s1; + const char* s2; + PRIntn n; +}; + +static Test tests[] = { + { "foo", "foo", 3 }, + { "foo", "fo", 3 }, + + { "foo", "bar", 3 }, + { "foo", "ba", 3 }, + + { "foo", "zap", 3 }, + { "foo", "za", 3 }, + + { "bar", "foo", 3 }, + { "bar", "fo", 3 }, + + { "bar", "foo", 3 }, + { "bar", "fo", 3 }, +}; +#define NUM_TESTS (sizeof(tests) / sizeof(tests[0])) + +void main() +{ + Test* tp = tests; + for (PRIntn i = 0; i < NUM_TESTS; i++, tp++) { + Check(tp->s1, tp->s2, tp->n); + } +} diff --git a/mozilla/base/tests/TimerTest.cpp b/mozilla/base/tests/TimerTest.cpp new file mode 100644 index 00000000000..49d9daea022 --- /dev/null +++ b/mozilla/base/tests/TimerTest.cpp @@ -0,0 +1,200 @@ +/* -*- 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 "prtypes.h" +#include "nsVoidArray.h" +#include "nsITimer.h" +#include "nsITimerCallback.h" +#include +#include +#include "resources.h" + +static char* class1Name = "TimerTest"; + +static HANDLE gInstance, gPrevInstance; +static nsVoidArray *gTimeouts = NULL; + +static void CreateRepeat(PRUint32 aDelay); + +void +MyCallback (nsITimer *aTimer, void *aClosure) +{ + printf("Timer executed with delay %d\n", (int)aClosure); + + if (gTimeouts->RemoveElement(aTimer) == PR_TRUE) { + NS_RELEASE(aTimer); + } +} + +void +MyRepeatCallback (nsITimer *aTimer, void *aClosure) +{ + printf("Timer executed with delay %d\n", (int)aClosure); + + if (gTimeouts->RemoveElement(aTimer) == PR_TRUE) { + NS_RELEASE(aTimer); + } + + CreateRepeat((PRUint32)aClosure); +} + +static void +CreateOneShot(PRUint32 aDelay) +{ + nsITimer *timer; + + NS_NewTimer(&timer); + timer->Init(MyCallback, (void *)aDelay, aDelay); + + gTimeouts->AppendElement(timer); +} + +static void +CreateRepeat(PRUint32 aDelay) +{ + nsITimer *timer; + + NS_NewTimer(&timer); + timer->Init(MyRepeatCallback, (void *)aDelay, aDelay); + + gTimeouts->AppendElement(timer); +} + +static void +CancelAll() +{ + int i, count = gTimeouts->Count(); + + for (i=0; i < count; i++) { + nsITimer *timer = (nsITimer *)gTimeouts->ElementAt(i); + + if (timer != NULL) { + timer->Cancel(); + NS_RELEASE(timer); + } + } + + gTimeouts->Clear(); +} + +long PASCAL +WndProc(HWND hWnd, UINT msg, WPARAM param, LPARAM lparam) +{ + HMENU hMenu; + + switch (msg) { + case WM_COMMAND: + hMenu = GetMenu(hWnd); + + switch (LOWORD(param)) { + case TIMER_EXIT: + ::DestroyWindow(hWnd); + exit(0); + + case TIMER_1SECOND: + CreateOneShot(1000); + break; + case TIMER_5SECOND: + CreateOneShot(5000); + break; + case TIMER_10SECOND: + CreateOneShot(10000); + break; + + case TIMER_1REPEAT: + CreateRepeat(1000); + break; + case TIMER_5REPEAT: + CreateRepeat(5000); + break; + case TIMER_10REPEAT: + CreateRepeat(10000); + break; + + case TIMER_CANCEL: + CancelAll(); + break; + + default: + break; + } + + default: + break; + } + + return DefWindowProc(hWnd, msg, param, lparam); +} + +static HWND CreateTopLevel(const char* clazz, const char* title, + int aWidth, int aHeight) +{ + // Create a simple top level window + HWND window = ::CreateWindowEx(WS_EX_CLIENTEDGE, + clazz, title, + WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN, + CW_USEDEFAULT, CW_USEDEFAULT, + aWidth, aHeight, + HWND_DESKTOP, + NULL, + gInstance, + NULL); + + ::ShowWindow(window, SW_SHOW); + ::UpdateWindow(window); + return window; +} + +int PASCAL +WinMain(HANDLE instance, HANDLE prevInstance, LPSTR cmdParam, int nCmdShow) +{ + gInstance = instance; + + if (!prevInstance) { + WNDCLASS wndClass; + wndClass.style = 0; + wndClass.lpfnWndProc = WndProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = 0; + wndClass.hInstance = gInstance; + wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); + wndClass.hbrBackground = (HBRUSH) GetStockObject(LTGRAY_BRUSH); + wndClass.lpszMenuName = class1Name; + wndClass.lpszClassName = class1Name; + RegisterClass(&wndClass); + } + + // Create our first top level window + HWND window = CreateTopLevel(class1Name, "Raptor HTML Viewer", 620, 400); + + gTimeouts = new nsVoidArray(); + + // Process messages + MSG msg; + while (GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return msg.wParam; +} + +void main(int argc, char **argv) +{ + WinMain(GetModuleHandle(NULL), NULL, 0, SW_SHOW); +} diff --git a/mozilla/base/tests/makefile.win b/mozilla/base/tests/makefile.win new file mode 100644 index 00000000000..98ea5a77d26 --- /dev/null +++ b/mozilla/base/tests/makefile.win @@ -0,0 +1,75 @@ +#!nmake +# +# 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. + +DEPTH=..\.. + +MAKE_OBJ_TYPE = EXE +PROG0 = .\$(OBJDIR)\TimerTest.exe +PROG1 = .\$(OBJDIR)\TestAtoms.exe +PROG2 = .\$(OBJDIR)\CvtURL.exe +PROG3 = .\$(OBJDIR)\TestCRT.exe +RESFILE = timer.res +PROGRAMS = $(PROG0) $(PROG1) $(PROG2) $(PROG3) + +LINCS=-I..\src -I$(PUBLIC)\xpcom + +LLIBS= \ + $(DIST)\lib\xpcom32.lib \ + $(DIST)\lib\raptorbase.lib \ + $(DIST)\lib\netlib.lib \ + $(LIBNSPR) \ + $(DIST)\lib\libplc21.lib \ + $(RESFILE) + +include <$(DEPTH)\config\rules.mak> + +install:: $(PROGRAMS) + $(MAKE_INSTALL) $(PROG0) $(DIST)\bin + $(MAKE_INSTALL) $(PROG1) $(DIST)\bin + $(MAKE_INSTALL) $(PROG2) $(DIST)\bin + $(MAKE_INSTALL) $(PROG3) $(DIST)\bin + +clobber:: + rm -f $(DIST)\bin\TimerTest.exe + rm -f $(DIST)\bin\TestAtoms.exe + rm -f $(DIST)\bin\CvtURL.exe + rm -f $(DIST)\bin\TestCRT.exe + +# Move this into config/obj.inc when it's allowed +.cpp{.\$(OBJDIR)\}.exe: + $(CC) @<<$(CFGFILE) + $(CFLAGS) + $(LCFLAGS) + $(LINCS) + $(LINCS_1) + $(INCS) + $(LLIBS) + $(OS_LIBS) + -Fd$(PBDFILE) + -Fe.\$(OBJDIR)\ + -Fo.\$(OBJDIR)\ + $(CURDIR)$(*B).cpp +< +#include "nslayout.h" +#include "nsISupports.h" +class nsIAtom; +class nsIContentDelegate; +class nsIDocument; +class nsIPresContext; +class nsISizeofHandler; +class nsString; +class nsString; +class nsVoidArray; + +// IID for the nsIContent interface +#define NS_ICONTENT_IID \ +{ 0x78030220, 0x9447, 0x11d1, \ + {0x93, 0x23, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +/** + * Content attribute states + */ +enum nsContentAttr { + // Attribute does not exist on the piece of content + eContentAttr_NotThere, + + // Attribute exists, but has no value, e.g. "BORDER" in + eContentAttr_NoValue, + + // Attribute exists and has a value. However, value may be the + // empty string. e.g.
or
+ eContentAttr_HasValue, +}; + +// A node of content in a documents content model. This interface +// is supported by all content objects. +class nsIContent : public nsISupports +{ +public: + virtual nsIDocument* GetDocument() const = 0; + virtual void SetDocument(nsIDocument* aDocument) = 0; + + virtual nsIContent* GetParent() const = 0; + virtual void SetParent(nsIContent* aParent) = 0; + + virtual PRBool CanContainChildren() const = 0; + virtual PRInt32 ChildCount() const = 0; + virtual nsIContent* ChildAt(PRInt32 aIndex) const = 0; + virtual PRInt32 IndexOf(nsIContent* aPossibleChild) const = 0; + virtual PRBool InsertChildAt(nsIContent* aKid, PRInt32 aIndex) = 0; + virtual PRBool ReplaceChildAt(nsIContent* aKid, PRInt32 aIndex) = 0; + virtual PRBool AppendChild(nsIContent* aKid) = 0; + virtual PRBool RemoveChildAt(PRInt32 aIndex) = 0; + + virtual nsIAtom* GetTag() const = 0; + + /** + * Set attribute values. All attribute values are assumed to have a + * canonical String representation that can be used for these + * methods. The setAttribute method is assumed to perform a translation + * of the canonical form into the underlying content specific + * form. + * + * aValue may legitimately be the empty string. + */ + virtual void SetAttribute(const nsString& aName, const nsString& aValue) = 0; + + /** + * Get the current value of the attribute. This returns a form that is + * suitable for passing back into setAttribute. + * + *
    + * + *
  • If the attribute is not set and has no default value, return + * eContentAttr_NotThere. + * + *
  • If the attribute exists, but has no value, return + * eContentAttr_NoValue. + * + *
  • If the attribute has a value, empty or otherwise, set ret to + * be the value, and return eContentAttr_HasValue. + * + *
*/ + virtual nsContentAttr GetAttribute(const nsString& aName, + nsString& aResult) const = 0; + + virtual nsIContentDelegate* GetDelegate(nsIPresContext* aCX) = 0; + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const = 0; + + /** + * Return the number of bytes consumed by this node of content and + * anything that it can reach. + */ + virtual PRUint32 SizeOf(nsISizeofHandler* aHandler) const = 0; +}; + +#endif /* nsIContent_h___ */ diff --git a/mozilla/content/base/public/nsIDocument.h b/mozilla/content/base/public/nsIDocument.h new file mode 100644 index 00000000000..a5cc20bb98e --- /dev/null +++ b/mozilla/content/base/public/nsIDocument.h @@ -0,0 +1,163 @@ +/* -*- 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. + */ +#ifndef nsIDocument_h___ +#define nsIDocument_h___ + +#include "nslayout.h" +#include "nsISupports.h" +#include "nsIUnicharInputStream.h" +class nsIArena; +class nsIContent; +class nsIDocumentContainer; +class nsIDocumentObserver; +class nsIPresContext; +class nsIPresShell; +class nsISubContent; +class nsIStyleSet; +class nsIStyleSheet; +class nsIURL; +class nsIViewManager; +class nsString; + +// IID for the nsIDocument interface +#define NS_IDOCUMENT_IID \ +{ 0x94c6ceb0, 0x9447, 0x11d1, \ + {0x93, 0x23, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +//---------------------------------------------------------------------- + +// Document interface +class nsIDocument : public nsISupports { +public: + // All documents have a memory arena associated with them which is + // used for memory allocation during document creation. This call + // returns the arena associated with this document. + virtual nsIArena* GetArena() = 0; + + virtual void LoadURL(nsIURL* aURL) = 0; + + virtual void StartDocumentLoad() = 0; + virtual void PauseDocumentLoad() = 0; + virtual void StopDocumentLoad() = 0; + virtual void WaitForDocumentLoad() = 0; + virtual PRBool IsDocumentLoaded() = 0; + + /** + * Return the title of the document. May return null. + */ + virtual const nsString* GetDocumentTitle() const = 0; + + /** + * Return the URL for the document. May return null. + */ + virtual nsIURL* GetDocumentURL() const = 0; + + /** + * Return a standard name for the document's character set. This will + * trigger a startDocumentLoad if necessary to answer the question. + */ + virtual nsCharSetID GetDocumentCharacterSet() const = 0; + virtual void SetDocumentCharacterSet(nsCharSetID aCharSetID) = 0; + + /** + * Create a new presentation shell that will use aContext for + * it's presentation context (presentation context's must not be + * shared among multiple presentation shell's). + */ + virtual nsIPresShell* CreateShell(nsIPresContext* aContext, + nsIViewManager* aViewManager, + nsIStyleSet* aStyleSet) = 0; + virtual PRBool DeleteShell(nsIPresShell* aShell) = 0; + virtual PRInt32 GetNumberOfShells() = 0; + virtual nsIPresShell* GetShellAt(PRInt32 aIndex) = 0; + + /** + * Return the parent document of this document. Will return null + * unless this document is within a compound document and has a parent. + */ + virtual nsIDocument* GetParentDocument() = 0; + virtual void SetParentDocument(nsIDocument* aParent) = 0; + virtual void AddSubDocument(nsIDocument* aSubDoc) = 0; + virtual PRInt32 GetNumberOfSubDocuments() = 0; + virtual nsIDocument* GetSubDocumentAt(PRInt32 aIndex) = 0; + + /** + * Return the root content object for this document. + */ + virtual nsIContent* GetRootContent() = 0; + virtual void SetRootContent(nsIContent* aRoot) = 0; + + /** + * Get the style sheets owned by this document. + */ + virtual PRInt32 GetNumberOfStyleSheets() = 0; + virtual nsIStyleSheet* GetStyleSheetAt(PRInt32 aIndex) = 0; + virtual void AddStyleSheet(nsIStyleSheet* aSheet) = 0; + + //---------------------------------------------------------------------- + + // Document notification API's + + /** + * Add a new observer of document change notifications. Whenever + * content is changed, appended, inserted or removed the observers are + * informed. + */ + virtual void AddObserver(nsIDocumentObserver* aObserver) = 0; + + /** + * Remove an observer of document change notifications. This will + * return false if the observer cannot be found. + */ + virtual PRBool RemoveObserver(nsIDocumentObserver* aObserver) = 0; + + // Observation hooks used by content nodes to propagate + // notifications to document observers. + virtual void ContentChanged(nsIContent* aContent, + nsISubContent* aSubContent, + PRInt32 aChangeType) = 0; + + virtual void ContentAppended(nsIContent* aContainer) = 0; + + virtual void ContentInserted(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) = 0; + + virtual void ContentReplaced(nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer) = 0; + + virtual void ContentWillBeRemoved(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) = 0; + + virtual void ContentHasBeenRemoved(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) = 0; +}; + +// XXX Belongs somewhere else +extern NS_LAYOUT nsresult + NS_NewHTMLDocument(nsIDocument** aInstancePtrResult); + +// XXX temporary - it's going away! +extern NS_LAYOUT void + NS_HackAppendContent(nsIDocument* aDoc); + +#endif /* nsIDocument_h___ */ diff --git a/mozilla/content/base/public/nsIDocumentContainer.h b/mozilla/content/base/public/nsIDocumentContainer.h new file mode 100644 index 00000000000..96862447dc2 --- /dev/null +++ b/mozilla/content/base/public/nsIDocumentContainer.h @@ -0,0 +1,71 @@ +/* -*- 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. + */ +#ifndef nsIDocumentContainer_h___ +#define nsIDocumentContainer_h___ + +#include "nsISupports.h" +class nsIScriptable; +class nsIScriptEnvironment; +class nsIURL; + +#define NS_IDOCUMENT_CONTAINER_IID \ +{ 0x8efd4470, 0x944d, 0x11d1, \ + {0x93, 0x23, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +class nIDocumentContainer : public nsISupports { +public: + /** + * Display the specified URL with the given connection. + * + * @param url the URL to display + * @param connection the connection to use. + */ + virtual void Display(nsIURL* aURL) = 0; + + /** + * Returns a script environment for the specified language and version. + * The expectation is that the script environment already has been + * set up with a container object. If a script environment has already + * been requested for the given language, the same instance should + * be returned. + * + * @param language the scripting language for the environment. If this + * is null, returns the default scripting environment. + * @param majorVersion the major version number of the language + * @param minorVersion the minor version number of the language + * @return the script environment for the language + * @see mg.magellan.script.IScriptEnvrionment + */ + virtual nsIScriptEnvironment* + GetScriptEnvironment(nsString* aLanguage, + PRInt32 aMajorVersion, + PRInt32 aMinorVersion) = 0; + + /** + * Returns the scriptable container object for the document container. + * The scriptable object will be used as the scoping object in the + * definition of scriptable classes used in the Document Object Model. + * + * @return the scriptable container for the application + * @see mg.magellan.script.IScriptable + * @see mg.magellan.script.IScriptEnvrionment + */ + virtual nsIScriptable* GetScriptableContainer() = 0; +} + +#endif /* nsIDocumentContainer_h___ */ diff --git a/mozilla/content/base/public/nsIDocumentObserver.h b/mozilla/content/base/public/nsIDocumentObserver.h new file mode 100644 index 00000000000..54fdc6ef4a2 --- /dev/null +++ b/mozilla/content/base/public/nsIDocumentObserver.h @@ -0,0 +1,160 @@ +/* -*- 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. + */ +#ifndef nsIDocumentObserver_h___ +#define nsIDocumentObserver_h___ + +#include "nsISupports.h" +class nsIContent; +class nsISubContent; +class nsIStyleSheet; +class nsString; + +#define NS_IDOCUMENTOBSERVER_IID \ +{ 0xb3f92460, 0x944c, 0x11d1, \ + {0x93, 0x23, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +// Document observer interface +class nsIDocumentObserver : public nsISupports { +public: + /** + * This is called when the documents title has arrived. + */ + NS_IMETHOD SetTitle(const nsString& aTitle) = 0; + + /** + * Notify that a content model update is beginning. This call can be + * nested. + */ + virtual void BeginUpdate() = 0; + + /** + * Notify that a content model update is finished. This call can be + * nested. + */ + virtual void EndUpdate() = 0; + + /** + * Notification that the content model has changed. This method is + * called automatically by content objects when their state is changed + * (therefore there is normally no need to invoke this method + * directly). The notification is passed to any + * IDocumentObservers. The notification is passed on to all of the + * document observers.

+ * + * This notification is not sent when a piece of content is + * added/removed from the document (the other notifications are used + * for that). + * + * @param aContent the piece of content that changed + * @param aSubContent subrange information about the piece of content + * that change + * @param aChangeType one of the change types (kLogicalChange, + * kPhysicalChange or kRenderingChange) + */ + virtual void ContentChanged(nsIContent* aContent, + nsISubContent* aSubContent, + PRInt32 aChangeType) = 0; + + /** + * Notifcation that the content model has had data appended to the + * given content object. This method is called automatically by the + * content container objects when a new content object is appended to + * the container (therefore there is normally no need to invoke this + * method directly). The notification is passed on to all of the + * document observers. + * + * @param aContainer the container that had a new child appended + */ + virtual void ContentAppended(nsIContent* aContainer) = 0; + + /** + * Notification that content has been inserted. This method is called + * automatically by the content container objects when a new content + * object is inserted in the container (therefore there is normally no + * need to invoke this method directly). The notification is passed on + * to all of the document observers. + * + * @param aContainer the container that now contains aChild + * @param aChild the child that was inserted + * @param aIndexInContainer the index of the child in the container + */ + virtual void ContentInserted(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) = 0; + + /** + * Notification that content has been replaced. This method is called + * automatically by the content container objects when a content object + * is replaced in the container (therefore there is normally no need to + * invoke this method directly). The notification is passed on to all + * of the document observers. + * + * @param aContainer the container that now contains aChild + * @param aOldChild the child that was replaced + * @param aNewChild the child that replaced aOldChild + * @param aIndexInContainer the index of the old and new child in the + * container + */ + virtual void ContentReplaced(nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer) = 0; + + /** + * Content is going to be removed immediately after this call. This + * method is called automatically by content container objects when a + * content object is about to be removed from the container (therefore + * there is normally no need to invoke this method directly). The + * notification is passed on to all of the document observers. + * + * @param aContainer the container that contains aChild + * @param aChild the child that will be removed + * @param aIndexInContainer the index of the child in the container + */ + virtual void ContentWillBeRemoved(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) = 0; + + /** + * Content has just been removed. This method is called automatically + * by content container objects when a content object has just been + * removed from the container (therefore there is normally no need to + * invoke this method directly). The notification is passed on to all + * of the document observers. + * + * @param aContainer the container that had a child removed + * @param aChild the child that was just removed + * @param aIndexInContainer the index of the child in the container + * before it was removed + */ + virtual void ContentHasBeenRemoved(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) = 0; + + /** + * A StyleSheet has just been added to the document. + * This method is called automatically when a StyleSheet gets added + * to the document. The notification is passed on to all of the + * document observers. + * + * @param aStyleSheet the StyleSheet that has been added + */ + virtual void StyleSheetAdded(nsIStyleSheet* aStyleSheet) = 0; +}; + +#endif /* nsIDocumentObserver_h___ */ diff --git a/mozilla/content/base/public/nsIStyleRule.h b/mozilla/content/base/public/nsIStyleRule.h new file mode 100644 index 00000000000..e79eff7dae8 --- /dev/null +++ b/mozilla/content/base/public/nsIStyleRule.h @@ -0,0 +1,43 @@ +/* -*- 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. + */ +#ifndef nsIStyleRule_h___ +#define nsIStyleRule_h___ + +#include + +#include "nslayout.h" +#include "nsISupports.h" + +class nsIStyleContext; +class nsIPresContext; + +// IID for the nsIStyleRule interface {40ae5c90-ad6a-11d1-8031-006008159b5a} +#define NS_ISTYLE_RULE_IID \ +{0x40ae5c90, 0xad6a, 0x11d1, {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}} + +class nsIStyleRule : public nsISupports { +public: + virtual PRBool Equals(const nsIStyleRule* aRule) const = 0; + virtual PRUint32 HashValue(void) const = 0; + + virtual void MapStyleInto(nsIStyleContext* aContext, nsIPresContext* aPresContext) = 0; + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const = 0; +}; + +#endif /* nsIStyleRule_h___ */ diff --git a/mozilla/content/base/public/nsIStyleSheet.h b/mozilla/content/base/public/nsIStyleSheet.h new file mode 100644 index 00000000000..bac20159aa0 --- /dev/null +++ b/mozilla/content/base/public/nsIStyleSheet.h @@ -0,0 +1,50 @@ +/* -*- 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. + */ +#ifndef nsIStyleSheet_h___ +#define nsIStyleSheet_h___ + +#include +#include "nsISupports.h" +class nsIAtom; +class nsIURL; +class nsIStyleRule; +class nsISupportsArray; +class nsIPresContext; +class nsIContent; +class nsIFrame; + +// IID for the nsIStyleSheet interface {8c4a80a0-ad6a-11d1-8031-006008159b5a} +#define NS_ISTYLE_SHEET_IID \ +{0x8c4a80a0, 0xad6a, 0x11d1, {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}} + +class nsIStyleSheet : public nsISupports { +public: + virtual nsIURL* GetURL(void) = 0; + + // populate void array with nsIStyleRule* + virtual PRInt32 RulesMatching(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsISupportsArray* aResults) = 0; + + // XXX style rule enumerations + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const = 0; +}; + +#endif /* nsIStyleSheet_h___ */ diff --git a/mozilla/content/base/public/nsITextContent.h b/mozilla/content/base/public/nsITextContent.h new file mode 100644 index 00000000000..fca6973fa58 --- /dev/null +++ b/mozilla/content/base/public/nsITextContent.h @@ -0,0 +1,48 @@ +/* -*- 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. + */ +#ifndef nsITextContent_h___ +#define nsITextContent_h___ + +#include "nslayout.h" +class nsString; + +// IID for the nsITextContent interface +#define NS_ITEXTCONTENT_IID \ +{ 0xdd0755d0, 0x944d, 0x11d1, \ + {0x93, 0x23, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +// Abstract interface for textual content. Note that this interface +// does not implement nsISupports (which means it's not transitive or +// reflexive). This is done for efficiency reasons. +class nsITextContent { +public: + /* + * Get the total length of the text content. + */ + virtual PRInt32 GetLength() = 0; + + /* + * Copy a subrange of the text content into aBuf starting at aOffset + * for aCount characters. aBuf's length will be reset before the + * copy occurs and it's length upon return will reflect the amount + * of data copied. + */ + virtual void GetText(nsString& aBuf, PRInt32 aOffset, PRInt32 aCount) = 0; +}; + +#endif /* nsITextContent_h___ */ diff --git a/mozilla/content/base/src/nsDocument.cpp b/mozilla/content/base/src/nsDocument.cpp new file mode 100644 index 00000000000..6f94c0a0175 --- /dev/null +++ b/mozilla/content/base/src/nsDocument.cpp @@ -0,0 +1,618 @@ +/* -*- 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 "nsDocument.h" +#include "nsIArena.h" +#include "nsIURL.h" +#include "nsString.h" +#include "nsIContent.h" +#include "nsIStyleSet.h" +#include "nsIStyleSheet.h" +#include "nsIPresShell.h" +#include "nsIDocumentObserver.h" + +static NS_DEFINE_IID(kIDocumentIID, NS_IDOCUMENT_IID); + +#include "nsIDOMElement.h" + +static NS_DEFINE_IID(kIDOMDocumentIID, NS_IDOMDOCUMENT_IID); +static NS_DEFINE_IID(kIDOMNodeIID, NS_IDOMNODE_IID); +static NS_DEFINE_IID(kIContentIID, NS_ICONTENT_IID); +static NS_DEFINE_IID(kIDOMElementIID, NS_IDOMELEMENT_IID); +static NS_DEFINE_IID(kIScriptObjectOwnerIID, NS_ISCRIPTOBJECTOWNER_IID); + + +nsDocument::nsDocument() +{ + NS_INIT_REFCNT(); + + mArena = nsnull; + mDocumentTitle = nsnull; + mDocumentURL = nsnull; + mCharacterSet = eCharSetID_IsoLatin1; + mParentDocument = nsnull; + mRootContent = nsnull; + mScriptObject = nsnull; + + Init();/* XXX */ +} + +nsDocument::~nsDocument() +{ + if (nsnull != mDocumentTitle) { + delete mDocumentTitle; + mDocumentTitle = nsnull; + } + NS_IF_RELEASE(mDocumentURL); + + mParentDocument = nsnull; + + // Delete references to sub-documents + PRInt32 index = mSubDocuments.Count(); + while (--index >= 0) { + nsIDocument* subdoc = (nsIDocument*) mSubDocuments.ElementAt(index); + NS_RELEASE(subdoc); + } + + NS_IF_RELEASE(mRootContent); + // Delete references to style sheets + index = mStyleSheets.Count(); + while (--index >= 0) { + nsIStyleSheet* sheet = (nsIStyleSheet*) mStyleSheets.ElementAt(index); + NS_RELEASE(sheet); + } + + NS_IF_RELEASE(mArena); +} + +nsresult nsDocument::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if (nsnull == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kIDocumentIID)) { + *aInstancePtr = (void*)(nsIDocument*)this; + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIDOMDocumentIID)) { + *aInstancePtr = (void*)(nsIDOMDocument*)this; + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIScriptObjectOwnerIID)) { + *aInstancePtr = (void*)(nsIScriptObjectOwner*)this; + AddRef(); + return NS_OK; + } + static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + if (aIID.Equals(kISupportsIID)) { + *aInstancePtr = (void*)(nsISupports*)(nsIDocument*)this; + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +NS_IMPL_ADDREF(nsDocument) +NS_IMPL_RELEASE(nsDocument) + +nsresult nsDocument::Init() +{ + nsresult rv = NS_NewHeapArena(&mArena, nsnull); + if (NS_OK != rv) { + return rv; + } + return NS_OK; +} + +nsIArena* nsDocument::GetArena() +{ + if (nsnull != mArena) { + NS_ADDREF(mArena); + } + return mArena; +} + +void nsDocument::StartDocumentLoad() +{ +} + +void nsDocument::PauseDocumentLoad() +{ +} + +void nsDocument::StopDocumentLoad() +{ +} + +void nsDocument::WaitForDocumentLoad() +{ +} + +PRBool nsDocument::IsDocumentLoaded() +{ + return PR_TRUE; +} + +const nsString* nsDocument::GetDocumentTitle() const +{ + return mDocumentTitle; +} + +nsIURL* nsDocument::GetDocumentURL() const +{ + NS_IF_ADDREF(mDocumentURL); + return mDocumentURL; +} + +nsCharSetID nsDocument::GetDocumentCharacterSet() const +{ + return mCharacterSet; +} + +void nsDocument::SetDocumentCharacterSet(nsCharSetID aCharSetID) +{ + mCharacterSet = aCharSetID; +} + +nsIPresShell* nsDocument::CreateShell(nsIPresContext* aContext, + nsIViewManager* aViewManager, + nsIStyleSet* aStyleSet) +{ + nsIPresShell* shell; + nsresult status = NS_NewPresShell(&shell); + if ((NS_OK == status) && + (NS_OK == shell->Init(this, aContext, aViewManager, aStyleSet))) { + // Note: we don't hold a ref to the shell (it holds a ref to us) + mPresShells.AppendElement(shell); + } + return shell; +} + +PRBool nsDocument::DeleteShell(nsIPresShell* aShell) +{ + return mPresShells.RemoveElement(aShell); +} + +PRInt32 nsDocument::GetNumberOfShells() +{ + return mPresShells.Count(); +} + +nsIPresShell* nsDocument::GetShellAt(PRInt32 aIndex) +{ + nsIPresShell* shell = (nsIPresShell*) mPresShells.ElementAt(aIndex); + if (nsnull != shell) { + NS_ADDREF(shell); + } + return shell; +} + +nsIDocument* nsDocument::GetParentDocument() +{ + if (nsnull != mParentDocument) { + NS_ADDREF(mParentDocument); + } + return mParentDocument; +} + +/** + * Note that we do *not* AddRef our parent because that would + * create a circular reference. + */ +void nsDocument::SetParentDocument(nsIDocument* aParent) +{ + mParentDocument = aParent; +} + +void nsDocument::AddSubDocument(nsIDocument* aSubDoc) +{ + NS_ADDREF(aSubDoc); + mSubDocuments.AppendElement(aSubDoc); +} + +PRInt32 nsDocument::GetNumberOfSubDocuments() +{ + return mSubDocuments.Count(); +} + +nsIDocument* nsDocument::GetSubDocumentAt(PRInt32 aIndex) +{ + nsIDocument* doc = (nsIDocument*) mSubDocuments.ElementAt(aIndex); + if (nsnull != doc) { + NS_ADDREF(doc); + } + return doc; +} + +nsIContent* nsDocument::GetRootContent() +{ + if (nsnull != mRootContent) { + NS_ADDREF(mRootContent); + } + return mRootContent; +} + +void nsDocument::SetRootContent(nsIContent* aRoot) +{ + NS_IF_RELEASE(mRootContent); + if (nsnull != aRoot) { + mRootContent = aRoot; + NS_ADDREF(aRoot); + } +} + +PRInt32 nsDocument::GetNumberOfStyleSheets() +{ + return mStyleSheets.Count(); +} + +nsIStyleSheet* nsDocument::GetStyleSheetAt(PRInt32 aIndex) +{ + nsIStyleSheet* sheet = (nsIStyleSheet*)mStyleSheets.ElementAt(aIndex); + NS_IF_ADDREF(sheet); + return sheet; +} + +void nsDocument::AddStyleSheetToSet(nsIStyleSheet* aSheet, nsIStyleSet* aSet) +{ + aSet->AppendDocStyleSheet(aSheet); +} + +void nsDocument::AddStyleSheet(nsIStyleSheet* aSheet) +{ + NS_PRECONDITION(nsnull != aSheet, "null arg"); + mStyleSheets.AppendElement(aSheet); + NS_ADDREF(aSheet); + + PRInt32 count = mPresShells.Count(); + PRInt32 index; + for (index = 0; index < count; index++) { + nsIPresShell* shell = (nsIPresShell*)mPresShells.ElementAt(index); + nsIStyleSet* set = shell->GetStyleSet(); + if (nsnull != set) { + AddStyleSheetToSet(aSheet, set); + NS_RELEASE(set); + } + } + + count = mObservers.Count(); + for (index = 0; index < count; index++) { + nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers.ElementAt(index); + observer->StyleSheetAdded(aSheet); + } +} + +// Note: We don't hold a reference to the document observer; we assume +// that it has a live reference to the document. +void nsDocument::AddObserver(nsIDocumentObserver* aObserver) +{ + mObservers.AppendElement(aObserver); +} + +PRBool nsDocument::RemoveObserver(nsIDocumentObserver* aObserver) +{ + return mObservers.RemoveElement(aObserver); +} + +void nsDocument::ContentChanged(nsIContent* aContent, + nsISubContent* aSubContent, + PRInt32 aChangeType) +{ + PRInt32 count = mObservers.Count(); + for (PRInt32 i = 0; i < count; i++) { + nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; + observer->ContentChanged(aContent, aSubContent, aChangeType); + } +} + +void nsDocument::ContentAppended(nsIContent* aContainer) +{ + PRInt32 count = mObservers.Count(); + for (PRInt32 i = 0; i < count; i++) { + nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; + observer->ContentAppended(aContainer); + } +} + +void nsDocument::ContentInserted(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) +{ + PRInt32 count = mObservers.Count(); + for (PRInt32 i = 0; i < count; i++) { + nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; + observer->ContentInserted(aContainer, aChild, aIndexInContainer); + } +} + +void nsDocument::ContentReplaced(nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer) +{ + PRInt32 count = mObservers.Count(); + for (PRInt32 i = 0; i < count; i++) { + nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; + observer->ContentReplaced(aContainer, aOldChild, aNewChild, + aIndexInContainer); + } +} + +void nsDocument::ContentWillBeRemoved(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) +{ + PRInt32 count = mObservers.Count(); + for (PRInt32 i = 0; i < count; i++) { + nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; + observer->ContentWillBeRemoved(aContainer, aChild, aIndexInContainer); + } +} + +void nsDocument::ContentHasBeenRemoved(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) +{ + PRInt32 count = mObservers.Count(); + for (PRInt32 i = 0; i < count; i++) { + nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; + observer->ContentHasBeenRemoved(aContainer, aChild, aIndexInContainer); + } +} + +nsresult nsDocument::GetScriptObject(JSContext *aContext, void** aScriptObject) +{ + nsresult res = NS_OK; + + if (nsnull == mScriptObject) { + res = NS_NewScriptDocument(aContext, this, nsnull, (JSObject**)&mScriptObject); + } + *aScriptObject = mScriptObject; + + return res; +} + +nsresult nsDocument::ResetScriptObject() +{ + mScriptObject = nsnull; + return NS_OK; +} + +// +// nsIDOMDocument interface +// +nsresult nsDocument::GetNodeType(PRInt32 *aType) +{ + *aType = nsIDOMNode::DOCUMENT; + return NS_OK; +} + +nsresult nsDocument::GetParentNode(nsIDOMNode **aNode) +{ + return NS_ERROR_FAILURE; +} + +nsresult nsDocument::GetChildNodes(nsIDOMNodeIterator **aIterator) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::HasChildNodes() +{ + if (nsnull != mRootContent) { + return NS_OK; + } + else { + return NS_ERROR_FAILURE; + } +} + +nsresult nsDocument::GetFirstChild(nsIDOMNode **aNode) +{ + if (nsnull != mRootContent) { + nsresult res = mRootContent->QueryInterface(kIDOMNodeIID, (void**)aNode); + NS_ASSERTION(NS_OK == res, "Must be a DOM Node"); + return res; + } + + return NS_ERROR_FAILURE; +} + +nsresult nsDocument::GetPreviousSibling(nsIDOMNode **aNode) +{ + // no siblings + return NS_ERROR_FAILURE; +} + +nsresult nsDocument::GetNextSibling(nsIDOMNode **aNode) +{ + // no siblings + return NS_ERROR_FAILURE; +} + +nsresult nsDocument::InsertBefore(nsIDOMNode *newChild, nsIDOMNode *refChild) +{ + // a document has only one child + return NS_ERROR_FAILURE; +} + +nsresult nsDocument::ReplaceChild(nsIDOMNode *newChild, nsIDOMNode *oldChild) +{ + NS_PRECONDITION(nsnull != newChild && nsnull != oldChild, "null arg"); + nsIContent* content; + + nsresult res = oldChild->QueryInterface(kIContentIID, (void**)&content); + if (NS_OK == res) { + // check that we are replacing the root content + if (content == mRootContent) { + nsIContent* newContent; + res = newChild->QueryInterface(kIContentIID, (void**)&newContent); + if (NS_OK == res) { + SetRootContent(newContent); + NS_RELEASE(newContent); + } + else NS_ASSERTION(0, "Must be an nsIContent"); // nsIContent not supported. Who are you? + } + + NS_RELEASE(content); + } + else NS_ASSERTION(0, "Must be an nsIContent"); // nsIContent not supported. Who are you? + + return res; +} + +nsresult nsDocument::RemoveChild(nsIDOMNode *oldChild) +{ + NS_PRECONDITION(nsnull != oldChild, "null arg"); + nsIContent* content; + + nsresult res = oldChild->QueryInterface(kIContentIID, (void**)&content); + if (NS_OK == res) { + if (content == mRootContent) { + NS_RELEASE(mRootContent); + mRootContent = nsnull; + } + } + + return res; +} + +nsresult nsDocument::GetMasterDoc(nsIDOMDocument **aDocument) +{ + AddRef(); + *aDocument = (nsIDOMDocument*)this; + return NS_OK; +} + +nsresult nsDocument::SetMasterDoc(nsIDOMDocument *aDocument) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::GetDocumentType(nsIDOMNode **aDocType) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::SetDocumentType(nsIDOMNode *aNode) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::GetDocumentElement(nsIDOMElement **aElement) +{ + nsresult res = NS_ERROR_FAILURE; + + if (nsnull != mRootContent) { + res = mRootContent->QueryInterface(kIDOMElementIID, (void**)aElement); + NS_ASSERTION(NS_OK == res, "Must be a DOM Element"); + } + + return res; +} + +nsresult nsDocument::SetDocumentElement(nsIDOMElement *aElement) +{ + NS_PRECONDITION(nsnull != aElement, "null arg"); + nsIContent* content; + + nsresult res = aElement->QueryInterface(kIContentIID, (void**)&content); + if (NS_OK == res) { + SetRootContent(content); + NS_RELEASE(content); + } + else NS_ASSERTION(0, "Must be an nsIContent"); // nsIContent not supported. Who are you? + + return res; +} + +nsresult nsDocument::GetDocumentContext(nsIDOMDocumentContext **aDocContext) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::SetDocumentContext(nsIDOMDocumentContext *aContext) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::CreateDocumentContext(nsIDOMDocumentContext **aDocContext) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::CreateElement(nsString &aTagName, + nsIDOMAttributeList *aAttributes, + nsIDOMElement **aElement) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::CreateTextNode(nsString &aData, nsIDOMText** aTextNode) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::CreateComment(nsString &aData, nsIDOMComment **aComment) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::CreatePI(nsString &aName, nsString &aData, nsIDOMPI **aPI) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::CreateAttribute(nsString &aName, + nsIDOMNode *value, + nsIDOMAttribute **aAttribute) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::CreateAttributeList(nsIDOMAttributeList **aAttributesList) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::CreateTreeIterator(nsIDOMNode **aNode, nsIDOMTreeIterator **aTreeIterator) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::GetElementsByTagName(nsIDOMNodeIterator **aIterator) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + diff --git a/mozilla/content/base/src/nsDocument.h b/mozilla/content/base/src/nsDocument.h new file mode 100644 index 00000000000..7567f3c2a5e --- /dev/null +++ b/mozilla/content/base/src/nsDocument.h @@ -0,0 +1,187 @@ +/* -*- 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. + */ +#ifndef nsDocument_h___ +#define nsDocument_h___ + +#include "nsIDocument.h" +#include "nsVoidArray.h" +#include "nsIDOMDocument.h" +#include "nsIScriptObjectOwner.h" + +// Base class for our document implementations +class nsDocument : public nsIDocument, public nsIDOMDocument, public nsIScriptObjectOwner { +public: + NS_DECL_ISUPPORTS + + virtual nsIArena* GetArena(); + + virtual void StartDocumentLoad(); + virtual void PauseDocumentLoad(); + virtual void StopDocumentLoad(); + virtual void WaitForDocumentLoad(); + virtual PRBool IsDocumentLoaded(); + + /** + * Return the title of the document. May return null. + */ + virtual const nsString* GetDocumentTitle() const; + + /** + * Return the URL for the document. May return null. + */ + virtual nsIURL* GetDocumentURL() const; + + /** + * Return a standard name for the document's character set. This will + * trigger a startDocumentLoad if necessary to answer the question. + */ + virtual nsCharSetID GetDocumentCharacterSet() const; + virtual void SetDocumentCharacterSet(nsCharSetID aCharSetID); + + /** + * Create a new presentation shell that will use aContext for + * it's presentation context (presentation context's must not be + * shared among multiple presentation shell's). + */ + virtual nsIPresShell* CreateShell(nsIPresContext* aContext, + nsIViewManager* aViewManager, + nsIStyleSet* aStyleSet); + virtual PRBool DeleteShell(nsIPresShell* aShell); + virtual PRInt32 GetNumberOfShells(); + virtual nsIPresShell* GetShellAt(PRInt32 aIndex); + + /** + * Return the parent document of this document. Will return null + * unless this document is within a compound document and has a parent. + */ + virtual nsIDocument* GetParentDocument(); + virtual void SetParentDocument(nsIDocument* aParent); + virtual void AddSubDocument(nsIDocument* aSubDoc); + virtual PRInt32 GetNumberOfSubDocuments(); + virtual nsIDocument* GetSubDocumentAt(PRInt32 aIndex); + + /** + * Return the root content object for this document. + */ + virtual nsIContent* GetRootContent(); + virtual void SetRootContent(nsIContent* aRoot); + + /** + * Get the style sheets owned by this document. + */ + virtual PRInt32 GetNumberOfStyleSheets(); + virtual nsIStyleSheet* GetStyleSheetAt(PRInt32 aIndex); + virtual void AddStyleSheet(nsIStyleSheet* aSheet); + + /** + * Add a new observer of document change notifications. Whenever + * content is changed, appended, inserted or removed the observers are + * informed. + */ + virtual void AddObserver(nsIDocumentObserver* aObserver); + + /** + * Remove an observer of document change notifications. This will + * return false if the observer cannot be found. + */ + virtual PRBool RemoveObserver(nsIDocumentObserver* aObserver); + + // Observation hooks used by content nodes to propagate + // notifications to document observers. + virtual void ContentChanged(nsIContent* aContent, + nsISubContent* aSubContent, + PRInt32 aChangeType); + + virtual void ContentAppended(nsIContent* aContainer); + + virtual void ContentInserted(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer); + + virtual void ContentReplaced(nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer); + + virtual void ContentWillBeRemoved(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer); + + virtual void ContentHasBeenRemoved(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer); + +public: + + virtual nsresult GetScriptObject(JSContext *aContext, void** aScriptObject); + virtual nsresult ResetScriptObject(); + + // nsIDOMDocument interface + virtual nsresult GetNodeType(PRInt32 *aType); + virtual nsresult GetParentNode(nsIDOMNode **aNode); + virtual nsresult GetChildNodes(nsIDOMNodeIterator **aIterator); + virtual nsresult HasChildNodes(); + virtual nsresult GetFirstChild(nsIDOMNode **aNode); + virtual nsresult GetPreviousSibling(nsIDOMNode **aNode); + virtual nsresult GetNextSibling(nsIDOMNode **aNode); + virtual nsresult InsertBefore(nsIDOMNode *newChild, nsIDOMNode *refChild); + virtual nsresult ReplaceChild(nsIDOMNode *newChild, nsIDOMNode *oldChild); + virtual nsresult RemoveChild(nsIDOMNode *oldChild); + virtual nsresult GetMasterDoc(nsIDOMDocument **aDocument); + virtual nsresult SetMasterDoc(nsIDOMDocument *aDocument); + virtual nsresult GetDocumentType(nsIDOMNode **aDocType); + virtual nsresult SetDocumentType(nsIDOMNode *aNode); + virtual nsresult GetDocumentElement(nsIDOMElement **aElement); + virtual nsresult SetDocumentElement(nsIDOMElement *aElement); + virtual nsresult GetDocumentContext(nsIDOMDocumentContext **aDocContext); + virtual nsresult SetDocumentContext(nsIDOMDocumentContext *aContext); + virtual nsresult CreateDocumentContext(nsIDOMDocumentContext **aDocContext); + virtual nsresult CreateElement(nsString &aTagName, + nsIDOMAttributeList *aAttributes, + nsIDOMElement **aElement); + virtual nsresult CreateTextNode(nsString &aData, nsIDOMText** aTextNode); + virtual nsresult CreateComment(nsString &aData, nsIDOMComment **aComment); + virtual nsresult CreatePI(nsString &aName, nsString &aData, nsIDOMPI **aPI); + virtual nsresult CreateAttribute(nsString &aName, + nsIDOMNode *value, + nsIDOMAttribute **aAttribute); + virtual nsresult CreateAttributeList(nsIDOMAttributeList **aAttributesList); + virtual nsresult CreateTreeIterator(nsIDOMNode **aNode, nsIDOMTreeIterator **aTreeIterator); + virtual nsresult GetElementsByTagName(nsIDOMNodeIterator **aIterator); + +protected: + virtual void AddStyleSheetToSet(nsIStyleSheet* aSheet, nsIStyleSet* aSet); // subclass hook + + nsDocument(); + virtual ~nsDocument(); + nsresult Init(); + + nsIArena* mArena; + nsString* mDocumentTitle; + nsIURL* mDocumentURL; + nsCharSetID mCharacterSet; + nsIDocument* mParentDocument; + nsVoidArray mSubDocuments; + nsVoidArray mPresShells; + nsIContent* mRootContent; + nsVoidArray mStyleSheets; + nsVoidArray mObservers; + void* mScriptObject; +}; + +#endif /* nsDocument_h___ */ diff --git a/mozilla/content/base/src/nsHTMLValue.cpp b/mozilla/content/base/src/nsHTMLValue.cpp new file mode 100644 index 00000000000..ed2df9aaab5 --- /dev/null +++ b/mozilla/content/base/src/nsHTMLValue.cpp @@ -0,0 +1,257 @@ +/* -*- 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 "nsHTMLValue.h" +#include "nsString.h" +#include "nsCRT.h" + +const nsHTMLValue nsHTMLValue::kNull; + +nsHTMLValue::nsHTMLValue(void) + : mUnit(eHTMLUnit_Null) +{ + mValue.mString = nsnull; +} + +nsHTMLValue::nsHTMLValue(PRInt32 aValue, nsHTMLUnit aUnit) + : mUnit(aUnit) +{ + mValue.mInt = aValue; +} + +nsHTMLValue::nsHTMLValue(float aValue, nsHTMLUnit aUnit) + : mUnit(aUnit) +{ + mValue.mFloat = aValue; +} + +nsHTMLValue::nsHTMLValue(const nsString& aValue) + : mUnit(eHTMLUnit_String) +{ + mValue.mString = aValue.ToNewString(); +} + +nsHTMLValue::nsHTMLValue(nsISupports* aValue) + : mUnit(eHTMLUnit_ISupports) +{ + mValue.mISupports = aValue; + NS_IF_ADDREF(mValue.mISupports); +} + +nsHTMLValue::nsHTMLValue(nscolor aValue) + : mUnit(eHTMLUnit_Color) +{ + mValue.mColor = aValue; +} + +nsHTMLValue::nsHTMLValue(const nsHTMLValue& aCopy) + : mUnit(aCopy.mUnit) +{ + if (eHTMLUnit_String == mUnit) { + if (nsnull != aCopy.mValue.mString) { + mValue.mString = aCopy.mValue.mString->ToNewString(); + } + else { + mValue.mString = nsnull; + } + } + else if (eHTMLUnit_ISupports == mUnit) { + mValue.mISupports = aCopy.mValue.mISupports; + NS_IF_ADDREF(mValue.mISupports); + } + else if (eHTMLUnit_Color == mUnit){ + mValue.mColor = aCopy.mValue.mColor; + } + else if (eHTMLUnit_Percent == mUnit) { + mValue.mFloat = aCopy.mValue.mFloat; + } + else { + mValue.mInt = aCopy.mValue.mInt; + } +} + +nsHTMLValue::~nsHTMLValue(void) +{ + Reset(); +} + +nsHTMLValue& nsHTMLValue::operator=(const nsHTMLValue& aCopy) +{ + Reset(); + mUnit = aCopy.mUnit; + if (eHTMLUnit_String == mUnit) { + if (nsnull != aCopy.mValue.mString) { + mValue.mString = aCopy.mValue.mString->ToNewString(); + } + } + else if (eHTMLUnit_ISupports == mUnit) { + mValue.mISupports = aCopy.mValue.mISupports; + NS_IF_ADDREF(mValue.mISupports); + } + else if (eHTMLUnit_Color == mUnit){ + mValue.mColor = aCopy.mValue.mColor; + } + else if (eHTMLUnit_Percent == mUnit) { + mValue.mFloat = aCopy.mValue.mFloat; + } + else { + mValue.mInt = aCopy.mValue.mInt; + } + return *this; +} + +PRBool nsHTMLValue::operator==(const nsHTMLValue& aOther) const +{ + if (mUnit == aOther.mUnit) { + if (eHTMLUnit_String == mUnit) { + if (nsnull == mValue.mString) { + if (nsnull == aOther.mValue.mString) { + return PR_TRUE; + } + } + else if (nsnull != aOther.mValue.mString) { + return mValue.mString->Equals(*(aOther.mValue.mString)); + } + } + else if (eHTMLUnit_ISupports == mUnit) { + return PRBool(mValue.mISupports == aOther.mValue.mISupports); + } + else if (eHTMLUnit_Color == mUnit){ + return PRBool(mValue.mColor == aOther.mValue.mColor); + } + else if (eHTMLUnit_Percent == mUnit) { + return PRBool(mValue.mFloat == aOther.mValue.mFloat); + } + else { + return PRBool(mValue.mInt == aOther.mValue.mInt); + } + } + return PR_FALSE; +} + +void nsHTMLValue::Reset(void) +{ + if (eHTMLUnit_String == mUnit) { + if (nsnull != mValue.mString) { + delete mValue.mString; + } + } + else if (eHTMLUnit_ISupports == mUnit) { + NS_IF_RELEASE(mValue.mISupports); + } + mUnit = eHTMLUnit_Null; + mValue.mString = nsnull; +} + + +void nsHTMLValue::Set(PRInt32 aValue, nsHTMLUnit aUnit) +{ + Reset(); + mUnit = aUnit; + mValue.mInt = aValue; +} + +void nsHTMLValue::Set(float aValue, nsHTMLUnit aUnit) +{ + Reset(); + mUnit = aUnit; + mValue.mFloat = aValue; +} + +void nsHTMLValue::Set(const nsString& aValue) +{ + Reset(); + mUnit = eHTMLUnit_String; + mValue.mString = aValue.ToNewString(); +} + +void nsHTMLValue::Set(nsISupports* aValue) +{ + Reset(); + mUnit = eHTMLUnit_ISupports; + mValue.mISupports = aValue; + NS_IF_ADDREF(mValue.mISupports); +} + +void nsHTMLValue::Set(nscolor aValue) +{ + Reset(); + mUnit = eHTMLUnit_Color; + mValue.mColor = aValue; +} + +void nsHTMLValue::AppendToString(nsString& aBuffer) const +{ + if (eHTMLUnit_Null == mUnit) { + return; + } + + if (eHTMLUnit_String == mUnit) { + if (nsnull != mValue.mString) { + aBuffer.Append('"'); + aBuffer.Append(*(mValue.mString)); + aBuffer.Append('"'); + } + else { + aBuffer.Append("null str"); + } + } + else if (eHTMLUnit_ISupports == mUnit) { + aBuffer.Append("0x"); + aBuffer.Append((PRInt32)mValue.mISupports, 16); + } + else if (eHTMLUnit_Color == mUnit){ + aBuffer.Append("(0x"); + aBuffer.Append(NS_GET_R(mValue.mColor), 16); + aBuffer.Append(" 0x"); + aBuffer.Append(NS_GET_G(mValue.mColor), 16); + aBuffer.Append(" 0x"); + aBuffer.Append(NS_GET_B(mValue.mColor), 16); + aBuffer.Append(" 0x"); + aBuffer.Append(NS_GET_A(mValue.mColor), 16); + aBuffer.Append(')'); + } + else if (eHTMLUnit_Percent == mUnit) { + aBuffer.Append(mValue.mFloat); + } + else { + aBuffer.Append(mValue.mInt, 10); + aBuffer.Append("[0x"); + aBuffer.Append(mValue.mInt, 16); + aBuffer.Append(']'); + } + + switch (mUnit) { + case eHTMLUnit_Null: break; + case eHTMLUnit_String: break; + case eHTMLUnit_ISupports: aBuffer.Append("ptr"); break; + case eHTMLUnit_Absolute: break; + case eHTMLUnit_Enumerated: aBuffer.Append("enum"); break; + case eHTMLUnit_Color: aBuffer.Append("rbga"); break; + case eHTMLUnit_Percent: aBuffer.Append("%"); break; + case eHTMLUnit_Pixel: aBuffer.Append("px"); break; + } + aBuffer.Append(' '); +} + +void nsHTMLValue::ToString(nsString& aBuffer) const +{ + aBuffer.SetLength(0); + AppendToString(aBuffer); +} + diff --git a/mozilla/content/base/src/nsHTMLValue.h b/mozilla/content/base/src/nsHTMLValue.h new file mode 100644 index 00000000000..a2f5309e614 --- /dev/null +++ b/mozilla/content/base/src/nsHTMLValue.h @@ -0,0 +1,138 @@ +/* -*- 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. + */ +#ifndef nsHTMLValue_h___ +#define nsHTMLValue_h___ + +#include "nscore.h" +#include "nsColor.h" +#include "nsString.h" +#include "nsISupports.h" + + +enum nsHTMLUnit { + eHTMLUnit_Null = 0, // (n/a) null unit, value is not specified + eHTMLUnit_String = 10, // (nsString) a string value + eHTMLUnit_ISupports = 20, // (nsISupports*) a ref counted interface + eHTMLUnit_Absolute = 50, // (int) simple value + eHTMLUnit_Enumerated = 51, // (int) value has enumerated meaning + eHTMLUnit_Color = 80, // (color) an RGBA value + eHTMLUnit_Percent = 90, // (float) 1.0 == 100%) value is percentage of something + + // Screen relative measure + eHTMLUnit_Pixel = 600, // (int) screen pixels +}; + +class nsHTMLValue { +public: + nsHTMLValue(void); + nsHTMLValue(PRInt32 aValue, nsHTMLUnit aUnit = eHTMLUnit_Absolute); + nsHTMLValue(float aValue, nsHTMLUnit aUnit = eHTMLUnit_Pixel); + nsHTMLValue(const nsString& aValue); + nsHTMLValue(nsISupports* aValue); + nsHTMLValue(nscolor aValue); + nsHTMLValue(const nsHTMLValue& aCopy); + ~nsHTMLValue(void); + + nsHTMLValue& operator=(const nsHTMLValue& aCopy); + PRBool operator==(const nsHTMLValue& aOther) const; + + nsHTMLUnit GetUnit(void) const { return mUnit; } + PRInt32 GetIntValue(void) const; + float GetFloatValue(void) const; + nsString& GetStringValue(nsString& aBuffer) const; + nsISupports* GetISupportsValue(void) const; + nscolor GetColorValue(void) const; + + void Reset(void); + void Set(PRInt32 aValue, nsHTMLUnit aUnit = eHTMLUnit_Absolute); + void Set(float aValue, nsHTMLUnit aUnit = eHTMLUnit_Pixel); + void Set(const nsString& aValue); + void Set(nsISupports* aValue); + void Set(nscolor aValue); + + void AppendToString(nsString& aBuffer) const; + void ToString(nsString& aBuffer) const; + +protected: + nsHTMLUnit mUnit; + union { + PRInt32 mInt; + float mFloat; + nsString* mString; + nsISupports* mISupports; + nscolor mColor; + } mValue; + +public: + static const nsHTMLValue kNull; +}; + +inline PRInt32 nsHTMLValue::GetIntValue(void) const +{ + NS_ASSERTION((mUnit == eHTMLUnit_Absolute) || + (mUnit == eHTMLUnit_Enumerated) || + (mUnit == eHTMLUnit_Pixel), "not an int value"); + if ((mUnit == eHTMLUnit_Absolute) || + (mUnit == eHTMLUnit_Enumerated) || + (mUnit == eHTMLUnit_Pixel)) { + return mValue.mInt; + } + return 0; +} + +inline float nsHTMLValue::GetFloatValue(void) const +{ + NS_ASSERTION(mUnit == eHTMLUnit_Percent, "not a float value"); + if (mUnit == eHTMLUnit_Percent) { + return mValue.mFloat; + } + return 0.0f; +} + +inline nsString& nsHTMLValue::GetStringValue(nsString& aBuffer) const +{ + NS_ASSERTION((mUnit == eHTMLUnit_String) || (mUnit == eHTMLUnit_Null), "not a string value"); + aBuffer.SetLength(0); + if ((mUnit == eHTMLUnit_String) && (nsnull != mValue.mString)) { + aBuffer.Append(*(mValue.mString)); + } + return aBuffer; +} + +inline nsISupports* nsHTMLValue::GetISupportsValue(void) const +{ + NS_ASSERTION(mUnit == eHTMLUnit_ISupports, "not an ISupports value"); + if (mUnit == eHTMLUnit_ISupports) { + NS_IF_ADDREF(mValue.mISupports); + return mValue.mISupports; + } + return nsnull; +} + +inline nscolor nsHTMLValue::GetColorValue(void) const +{ + NS_ASSERTION(mUnit == eHTMLUnit_Color, "not a color value"); + if (mUnit == eHTMLUnit_Color) { + return mValue.mColor; + } + return NS_RGB(0,0,0); +} + + +#endif /* nsHTMLValue_h___ */ + diff --git a/mozilla/content/base/src/nsStyleContext.cpp b/mozilla/content/base/src/nsStyleContext.cpp new file mode 100644 index 00000000000..bf44521a48e --- /dev/null +++ b/mozilla/content/base/src/nsStyleContext.cpp @@ -0,0 +1,613 @@ +/* -*- 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 "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsString.h" +#include "nsUnitConversion.h" +#include "nsIContent.h" +#include "nsIPresContext.h" +#include "nsIStyleRule.h" +#include "nsISupportsArray.h" +#include "nsCRT.h" + +#include "nsIFrame.h" + + +#ifdef NS_DEBUG +static PRBool gsDebug = PR_FALSE; +#else +static const PRBool gsDebug = PR_FALSE; +#endif + + +static NS_DEFINE_IID(kStyleFontSID, NS_STYLEFONT_SID); +static NS_DEFINE_IID(kStyleColorSID, NS_STYLECOLOR_SID); +static NS_DEFINE_IID(kStyleListSID, NS_STYLELIST_SID); +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); + +static NS_DEFINE_IID(kIStyleContextIID, NS_ISTYLECONTEXT_IID); + +nsStyleFont::nsStyleFont(const nsFont& aFont) + : mFont(aFont) +{ +} + +nsStyleFont::~nsStyleFont(void) +{ +} + +struct StyleFontImpl : public nsStyleFont { + StyleFontImpl(const nsFont& aFont) + : nsStyleFont(aFont) + {} + ~StyleFontImpl() + {} + + virtual const nsID& GetID(void) + { return kStyleFontSID; } + + virtual void InheritFrom(const nsStyleFont& aCopy); + +private: // These are not allowed + StyleFontImpl(const StyleFontImpl& aOther); + StyleFontImpl& operator=(const StyleFontImpl& aOther); +}; + +void StyleFontImpl::InheritFrom(const nsStyleFont& aCopy) +{ + mFont = aCopy.mFont; + mThreeD = aCopy.mThreeD; +} + +struct StyleColorImpl: public nsStyleColor { + StyleColorImpl(void) + { + mBackgroundAttachment = NS_STYLE_BG_ATTACHMENT_SCROLL; + mBackgroundFlags = NS_STYLE_BG_COLOR_TRANSPARENT; + mBackgroundRepeat = NS_STYLE_BG_REPEAT_OFF; + + mBackgroundColor = NS_RGB(192,192,192); + } + + ~StyleColorImpl(void) + {} + + virtual const nsID& GetID(void) + { return kStyleColorSID; } + + virtual void InheritFrom(const nsStyleColor& aCopy); + +private: // These are not allowed + StyleColorImpl(const StyleColorImpl& aOther); + StyleColorImpl& operator=(const StyleColorImpl& aOther); +}; + +void StyleColorImpl::InheritFrom(const nsStyleColor& aCopy) +{ + mColor = aCopy.mColor; + + mBackgroundFlags = NS_STYLE_BG_COLOR_TRANSPARENT; +} + + +struct StyleListImpl: public nsStyleList { + StyleListImpl(void) + { + mListStyleType = NS_STYLE_LIST_STYLE_BASIC; + mListStylePosition = NS_STYLE_LIST_STYLE_POSITION_OUTSIDE; + } + + ~StyleListImpl(void) + { + } + + virtual const nsID& GetID(void) + { return kStyleListSID; } + + virtual void InheritFrom(const nsStyleList& aCopy); +}; + +void StyleListImpl::InheritFrom(const nsStyleList& aCopy) +{ + mListStyleType = aCopy.mListStyleType; + mListStyleImage = aCopy.mListStyleImage; + mListStylePosition = aCopy.mListStylePosition; +} + +nsStyleMolecule::nsStyleMolecule() +{ +} + +nsStyleMolecule::~nsStyleMolecule() +{ +} + +struct StyleMoleculeImpl : public nsStyleMolecule { + StyleMoleculeImpl(void) + {} + ~StyleMoleculeImpl(void) + {} + + virtual const nsID& GetID(void) + { return kStyleMoleculeSID; } + + virtual void InheritFrom(const nsStyleMolecule& aCopy); + +private: // These are not allowed + StyleMoleculeImpl(const StyleMoleculeImpl& aOther); + StyleMoleculeImpl& operator=(const StyleMoleculeImpl& aOther); +}; + +void StyleMoleculeImpl::InheritFrom(const nsStyleMolecule& aCopy) +{ + cursor = aCopy.cursor; + direction = aCopy.direction; + + textDecoration = aCopy.textDecoration; + + textAlign = aCopy.textAlign; + whiteSpace = aCopy.whiteSpace; + +// lineHeight = aCopy.lineHeight; +} + + +//---------------------------------------------------------------------- + +class StyleContextImpl : public nsIStyleContext { +public: + StyleContextImpl(nsIStyleContext* aParent, nsISupportsArray* aRules, nsIPresContext* aPresContext); + ~StyleContextImpl(); + + void* operator new(size_t sz) { + void* rv = new char[sz]; + nsCRT::zero(rv, sz); + return rv; + } + + NS_DECL_ISUPPORTS + + virtual nsIStyleContext* GetParent(void) const; + virtual nsISupportsArray* GetStyleRules(void) const; + + virtual PRBool Equals(const nsIStyleContext* aOther) const; + virtual PRUint32 HashValue(void) const; + + virtual nsStyleStruct* GetData(const nsIID& aSID); + + virtual void InheritFrom(const StyleContextImpl& aParent); + + virtual void HackStyleFor(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aFrame); + + nsIStyleContext* mParent; + PRUint32 mHashValid: 1; + PRUint32 mHashValue: 31; + nsISupportsArray* mRules; + + // the style data... + StyleFontImpl mFont; + StyleColorImpl mColor; + StyleListImpl mList; +// xxx backward support hack + StyleMoleculeImpl mMolecule; +}; + +StyleContextImpl::StyleContextImpl(nsIStyleContext* aParent, nsISupportsArray* aRules, + nsIPresContext* aPresContext) + : mParent(aParent), // weak ref + mRules(aRules), + mFont(aPresContext->GetDefaultFont()), + mColor(), + mList(), + mMolecule() +{ + NS_INIT_REFCNT(); + NS_IF_ADDREF(mRules); + + if (nsnull != aParent) { + InheritFrom((StyleContextImpl&)*aParent); + } + + if (nsnull != mRules) { + PRInt32 index = mRules->Count(); + while (0 < index) { + nsIStyleRule* rule = (nsIStyleRule*)mRules->ElementAt(--index); + rule->MapStyleInto(this, aPresContext); + NS_RELEASE(rule); + } + } +} + +StyleContextImpl::~StyleContextImpl() +{ + mParent = nsnull; // weak ref + NS_IF_RELEASE(mRules); +} + +NS_IMPL_ISUPPORTS(StyleContextImpl, kIStyleContextIID) + +nsIStyleContext* StyleContextImpl::GetParent(void) const +{ + NS_IF_ADDREF(mParent); + return mParent; +} + +nsISupportsArray* StyleContextImpl::GetStyleRules(void) const +{ + NS_IF_ADDREF(mRules); + return mRules; +} + + +PRBool StyleContextImpl::Equals(const nsIStyleContext* aOther) const +{ + PRBool result = PR_TRUE; + const StyleContextImpl* other = (StyleContextImpl*)aOther; + + if (other != this) { + if (mParent != other->mParent) { + result = PR_FALSE; + } + else { + if ((nsnull != mRules) && (nsnull != other->mRules)) { + result = mRules->Equals(other->mRules); + } + else { + result = PRBool((nsnull == mRules) && (nsnull == other->mRules)); + } + } + } + return result; +} + +PRUint32 StyleContextImpl::HashValue(void) const +{ + if (0 == mHashValid) { + ((StyleContextImpl*)this)->mHashValue = ((nsnull != mParent) ? mParent->HashValue() : 0); + if (nsnull != mRules) { + PRInt32 index = mRules->Count(); + while (0 <= --index) { + nsIStyleRule* rule = (nsIStyleRule*)mRules->ElementAt(index); + PRUint32 hash = rule->HashValue(); + ((StyleContextImpl*)this)->mHashValue ^= (hash & 0x7FFFFFFF); + NS_RELEASE(rule); + } + } + ((StyleContextImpl*)this)->mHashValid = 1; + } + return mHashValue; +} + + +nsStyleStruct* StyleContextImpl::GetData(const nsIID& aSID) +{ + if (aSID.Equals(kStyleFontSID)) { + return &mFont; + } + if (aSID.Equals(kStyleColorSID)) { + return &mColor; + } + if (aSID.Equals(kStyleListSID)) { + return &mList; + } + if (aSID.Equals(kStyleMoleculeSID)) { + return &mMolecule; + } + return nsnull; +} + +void StyleContextImpl::InheritFrom(const StyleContextImpl& aParent) +{ + mFont.InheritFrom(aParent.mFont); + mColor.InheritFrom(aParent.mColor); + mList.InheritFrom(aParent.mList); + mMolecule.InheritFrom(aParent.mMolecule); +} + +void StyleContextImpl::HackStyleFor(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame) +{ +/* + mColor.mColor = NS_RGB(0, 0, 0); +*/ + + mMolecule.display = NS_STYLE_DISPLAY_BLOCK; + mMolecule.whiteSpace = NS_STYLE_WHITESPACE_NORMAL; + mMolecule.verticalAlign = NS_STYLE_VERTICAL_ALIGN_BASELINE; + mMolecule.textAlign = NS_STYLE_TEXT_ALIGN_LEFT; + + mMolecule.positionFlags = NS_STYLE_POSITION_STATIC; + mMolecule.floats = 0; + + // XXX If it's a B guy then make it inline + nsIAtom* tag = aContent->GetTag(); + nsAutoString buf; + if (tag != nsnull) { + tag->ToString(buf); + NS_RELEASE(tag); + if (buf.EqualsIgnoreCase("B")) { +// float p2t = aPresContext->GetPixelsToTwips(); + mMolecule.display = NS_STYLE_DISPLAY_INLINE; +// mColor.mBackgroundColor = NS_RGB(128, 128, 255); +// mColor.mBackgroundFlags = 0; +// mMolecule.border.top = nscoord(5 * p2t); +// mMolecule.border.right = nscoord(5 * p2t); +// mMolecule.border.bottom = nscoord(5 * p2t); +// mMolecule.border.left = nscoord(5 * p2t); +// for (int i = 0; i < 4; i++) { +// mMolecule.borderStyle[i] = NS_STYLE_BORDER_STYLE_INSET; +// mMolecule.borderColor[i] = NS_RGB(128, 128, 128); +// } + } else if (buf.EqualsIgnoreCase("A")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + mMolecule.cursor = NS_STYLE_CURSOR_HAND; + } else if (buf.EqualsIgnoreCase("BR")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + nsString align("CLEAR"); + nsString value; + if (eContentAttr_HasValue == aContent->GetAttribute(align, value)) { + if (0 == value.Compare("left", PR_TRUE)) { + mMolecule.clear = NS_STYLE_CLEAR_LEFT; + } else if (0 == value.Compare("right", PR_TRUE)) { + mMolecule.clear = NS_STYLE_CLEAR_RIGHT; + } else if (0 == value.Compare("all", PR_TRUE)) { + mMolecule.clear = NS_STYLE_CLEAR_BOTH; + } + } + } else if (buf.EqualsIgnoreCase("SPACER")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + } else if (buf.EqualsIgnoreCase("WBR")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + } else if (buf.EqualsIgnoreCase("INPUT")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + } else if (buf.EqualsIgnoreCase("I")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + } else if (buf.EqualsIgnoreCase("S")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + } else if (buf.EqualsIgnoreCase("PRE")) { + mMolecule.whiteSpace = NS_STYLE_WHITESPACE_PRE; + mMolecule.margin.top = NS_POINTS_TO_TWIPS_INT(3); + mMolecule.margin.bottom = NS_POINTS_TO_TWIPS_INT(3); +// mColor.mBackgroundImage = "resource:/res/gear1.gif"; +// mColor.mBackgroundRepeat = NS_STYLE_BG_REPEAT_XY; + } else if (buf.EqualsIgnoreCase("U")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + } else if (buf.EqualsIgnoreCase("FONT")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + } else if (buf.EqualsIgnoreCase("THREED")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + mFont.mThreeD = 1; + } else if (buf.EqualsIgnoreCase("TT")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; +// mFont.mFont.name.SetLength(0); +// mFont.mFont.name.Append("Courier"); +// mMolecule.positionFlags = NS_STYLE_POSITION_RELATIVE; +// mMolecule.left = -50; +// mMolecule.top = -50; + } else if (buf.EqualsIgnoreCase("IMG")) { + float p2t = aPresContext->GetPixelsToTwips(); + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + mMolecule.padding.top = nscoord(2 * p2t); + mMolecule.padding.right = nscoord(2 * p2t); + mMolecule.padding.bottom = nscoord(2 * p2t); + mMolecule.padding.left = nscoord(2 * p2t); + nsString align("ALIGN"); + nsString value; + if (eContentAttr_HasValue == aContent->GetAttribute(align, value)) { + if (0 == value.Compare("left", PR_TRUE)) { + mMolecule.floats = NS_STYLE_FLOAT_LEFT; + } else if (0 == value.Compare("right", PR_TRUE)) { + mMolecule.floats = NS_STYLE_FLOAT_RIGHT; + } + } + } else if (buf.EqualsIgnoreCase("P")) { + // mMolecule.textAlign = NS_STYLE_TEXT_ALIGN_CENTER; + mMolecule.margin.top = NS_POINTS_TO_TWIPS_INT(2); + mMolecule.margin.bottom = NS_POINTS_TO_TWIPS_INT(2); + } else if (buf.EqualsIgnoreCase("BODY")) { + float p2t = aPresContext->GetPixelsToTwips(); +// mColor.mBackgroundColor = NS_RGB(255, 255, 255); +// mColor.mBackgroundFlags = 0; + //mColor.mBackgroundFlags = 0; + //mColor.mBackgroundImage = "resource:/res/rock_gra.gif"; + //mColor.mBackgroundRepeat = NS_STYLE_BG_REPEAT_XY; + mMolecule.padding.top = nscoord(5 * p2t); + mMolecule.padding.right = nscoord(5 * p2t); + mMolecule.padding.bottom = nscoord(5 * p2t); + mMolecule.padding.left = nscoord(5 * p2t); + mMolecule.border.top = nscoord(1 * p2t); + mMolecule.border.right = nscoord(1 * p2t); + mMolecule.border.bottom = nscoord(1 * p2t); + mMolecule.border.left = nscoord(1 * p2t); + for (int i = 0; i < 4; i++) { + mMolecule.borderStyle[i] = NS_STYLE_BORDER_STYLE_SOLID; + mMolecule.borderColor[i] = NS_RGB(0, 255, 0); + } + } else if (buf.EqualsIgnoreCase("LI")) { + mMolecule.display = NS_STYLE_DISPLAY_LIST_ITEM; + } else if (buf.EqualsIgnoreCase("UL") || buf.EqualsIgnoreCase("OL")) { + float p2t = aPresContext->GetPixelsToTwips(); + mMolecule.padding.left = nscoord(40 * p2t); + mMolecule.margin.top = NS_POINTS_TO_TWIPS_INT(5); + mMolecule.margin.bottom = NS_POINTS_TO_TWIPS_INT(5); + } else if (buf.EqualsIgnoreCase("TABLE")) { // TABLE + mMolecule.border.top = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.border.bottom = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.border.right = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.border.left = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.borderStyle[0] = mMolecule.borderStyle[1] = + mMolecule.borderStyle[2] = mMolecule.borderStyle[3] = NS_STYLE_BORDER_STYLE_SOLID; + mMolecule.fixedWidth = -1; + mMolecule.proportionalWidth = 100; + nsString align("ALIGN"); + nsString value; + if (eContentAttr_HasValue == aContent->GetAttribute(align, value)) { + if (0 == value.Compare("left", PR_TRUE)) { + mMolecule.floats = NS_STYLE_FLOAT_LEFT; + } else if (0 == value.Compare("right", PR_TRUE)) { + mMolecule.floats = NS_STYLE_FLOAT_RIGHT; + } + } + } else if (buf.EqualsIgnoreCase("CAPTION")) { // CAPTION + mMolecule.verticalAlign = NS_STYLE_VERTICAL_ALIGN_TOP; + } else if (buf.EqualsIgnoreCase("TBODY")) { // TBODY + mMolecule.padding.top = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.padding.bottom = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.padding.right = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.padding.left = NS_POINTS_TO_TWIPS_INT(1); + } else if (buf.EqualsIgnoreCase("TR")) { // TROW + mMolecule.padding.top = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.padding.bottom = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.padding.right = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.padding.left = NS_POINTS_TO_TWIPS_INT(1); + } else if (buf.EqualsIgnoreCase("TD")) { // TD + float p2t = aPresContext->GetPixelsToTwips(); + + + // Set padding to twenty for testing purposes + int cellPadding = 1; + if (gsDebug==PR_TRUE) + cellPadding = 20; + mMolecule.verticalAlign = NS_STYLE_VERTICAL_ALIGN_MIDDLE; + + mMolecule.padding.top = NS_POINTS_TO_TWIPS_INT(cellPadding); + mMolecule.padding.bottom = NS_POINTS_TO_TWIPS_INT(cellPadding); + mMolecule.padding.right = NS_POINTS_TO_TWIPS_INT(cellPadding); + mMolecule.padding.left = NS_POINTS_TO_TWIPS_INT(cellPadding); +// mColor.mBackgroundColor = NS_RGB(255, 255, 0); +// mColor.mBackgroundFlags = 0; + mMolecule.border.top = nscoord(1 * p2t); + mMolecule.border.right = nscoord(1 * p2t); + mMolecule.border.bottom = nscoord(1 * p2t); + mMolecule.border.left = nscoord(1 * p2t); + for (int i = 0; i < 4; i++) { + mMolecule.borderStyle[i] = NS_STYLE_BORDER_STYLE_SOLID; + mMolecule.borderColor[i] = NS_RGB(128, 128, 128); + } + mMolecule.fixedWidth = -1; + mMolecule.proportionalWidth = -1; + mMolecule.fixedHeight = -1; + mMolecule.proportionalHeight = -1; + + } else if (buf.EqualsIgnoreCase("COL")) { + mMolecule.fixedWidth = -1; + mMolecule.proportionalWidth = -1; + mMolecule.fixedHeight = -1; + mMolecule.proportionalHeight = -1; + } + } else { + // It's text (!) + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + mMolecule.cursor = NS_STYLE_CURSOR_IBEAM; + nsIContent* content = aParentFrame->GetContent(); + nsIAtom* parentTag = content->GetTag(); + parentTag->ToString(buf); + NS_RELEASE(content); + NS_RELEASE(parentTag); + if (buf.EqualsIgnoreCase("B")) { +// mFont.mFont.size = NS_POINTS_TO_TWIPS_INT(18); +// mFont.mFont.weight = NS_FONT_WEIGHT_BOLD; + } else if (buf.EqualsIgnoreCase("A")) { +// mColor.mColor = NS_RGB(0,0,255); +// mFont.mFont.decorations = NS_FONT_DECORATION_UNDERLINE; + // This simulates a

text inheritance rule
+      // Check the parent of the A
+      nsIFrame* parentParentFrame = aParentFrame->GetGeometricParent();
+      if (nsnull != parentParentFrame) {
+        nsIContent* parentParentContent = parentParentFrame->GetContent();
+        nsIAtom* parentParentTag = parentParentContent->GetTag();
+        parentParentTag->ToString(buf);
+        NS_RELEASE(parentParentTag);
+        NS_RELEASE(parentParentContent);
+        if (buf.EqualsIgnoreCase("PRE")) {
+          mMolecule.whiteSpace = NS_STYLE_WHITESPACE_PRE;
+//          mFont.mFont.name.SetLength(0);
+//          mFont.mFont.name.Append("Courier");
+        }
+      }
+    } else if (buf.EqualsIgnoreCase("THREED")) {
+//      mFont.mFont.size = NS_POINTS_TO_TWIPS_INT(18);
+//      mFont.mFont.weight = NS_FONT_WEIGHT_BOLD;
+      mFont.mThreeD = 1;
+    } else if (buf.EqualsIgnoreCase("I")) {
+//      mFont.mFont.style = NS_FONT_STYLE_ITALIC;
+    } else if (buf.EqualsIgnoreCase("BLINK")) {
+//      mFont.mFont.decorations |= NS_STYLE_TEXT_DECORATION_BLINK;
+    } else if (buf.EqualsIgnoreCase("TT")) {
+//      mFont.mFont.name.SetLength(0);
+//      mFont.mFont.name.Append("Courier");
+    } else if (buf.EqualsIgnoreCase("S")) {
+//      mFont.mFont.decorations = NS_FONT_DECORATION_LINE_THROUGH;
+    } else if (buf.EqualsIgnoreCase("U")) {
+//      mFont.mFont.decorations = NS_FONT_DECORATION_UNDERLINE;
+    } else if (buf.EqualsIgnoreCase("PRE")) {
+      mMolecule.whiteSpace = NS_STYLE_WHITESPACE_PRE;
+//      mFont.mFont.name.SetLength(0);
+//      mFont.mFont.name.Append("Courier");
+    }
+  }
+
+#if 0
+  if ((NS_STYLE_DISPLAY_BLOCK == mMolecule.display) ||
+      (NS_STYLE_DISPLAY_LIST_ITEM == mMolecule.display)) {
+    // Always justify text (take that ie)
+    mMolecule.textAlign = NS_STYLE_TEXT_ALIGN_JUSTIFY;
+  }
+#endif
+
+  mMolecule.borderPadding.top =
+    mMolecule.border.top + mMolecule.padding.top;
+  mMolecule.borderPadding.right =
+    mMolecule.border.right + mMolecule.padding.right;
+  mMolecule.borderPadding.bottom =
+    mMolecule.border.bottom + mMolecule.padding.bottom;
+  mMolecule.borderPadding.left =
+    mMolecule.border.left + mMolecule.padding.left;
+
+}
+
+NS_LAYOUT nsresult
+NS_NewStyleContext(nsIStyleContext** aInstancePtrResult,
+                   nsISupportsArray* aRules,
+                   nsIPresContext* aPresContext,
+                   nsIContent* aContent,
+                   nsIFrame* aParentFrame)
+{
+  NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr");
+  if (nsnull == aInstancePtrResult) {
+    return NS_ERROR_NULL_POINTER;
+  }
+
+  nsIStyleContext* parent = nsnull;
+  if (nsnull != aParentFrame) {
+    parent = aParentFrame->GetStyleContext(aPresContext);
+    NS_ASSERTION(nsnull != parent, "parent frame must have style context");
+  }
+
+  StyleContextImpl* context = new StyleContextImpl(parent, aRules, aPresContext);
+  NS_IF_RELEASE(parent);
+  if (nsnull == context) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  context->HackStyleFor(aPresContext, aContent, aParentFrame);
+
+  return context->QueryInterface(kIStyleContextIID, (void **) aInstancePtrResult);
+}
diff --git a/mozilla/content/base/src/nsStyleSet.cpp b/mozilla/content/base/src/nsStyleSet.cpp
new file mode 100644
index 00000000000..156e68bea3c
--- /dev/null
+++ b/mozilla/content/base/src/nsStyleSet.cpp
@@ -0,0 +1,530 @@
+/* -*- 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 "nsIStyleSet.h"
+#include "nsIStyleSheet.h"
+#include "nsIStyleRule.h"
+#include "nsIStyleContext.h"
+#include "nsISupportsArray.h"
+#include "nsIFrame.h"
+#include "nsHashtable.h"
+
+
+static NS_DEFINE_IID(kIStyleSetIID, NS_ISTYLE_SET_IID);
+
+class ContextKey : public nsHashKey {
+public:
+  ContextKey(nsIStyleContext* aContext);
+  ContextKey(nsIStyleContext* aParent, nsISupportsArray* aRules);
+  ~ContextKey(void);
+
+  void        SetContext(nsIStyleContext* aContext);
+
+  PRBool      Equals(const nsHashKey* aOther) const;
+  PRUint32    HashValue(void) const;
+  nsHashKey*  Clone(void) const;
+
+private:
+  ContextKey(void);
+  ContextKey(const ContextKey& aCopy);
+  ContextKey& operator=(const ContextKey& aCopy) const;
+
+protected:
+  nsIStyleContext* mContext;
+  nsIStyleContext* mParent;
+  nsISupportsArray* mRules;
+};
+
+ContextKey::ContextKey(nsIStyleContext* aContext)
+  : mContext(aContext),
+    mParent(nsnull),
+    mRules(nsnull)
+{
+  NS_IF_ADDREF(mContext);
+}
+
+ContextKey::ContextKey(nsIStyleContext* aParent, nsISupportsArray* aRules)
+  : mContext(nsnull),
+    mParent(aParent),
+    mRules(aRules)
+{
+  NS_IF_ADDREF(mParent);
+  NS_IF_ADDREF(mRules);
+}
+
+ContextKey::ContextKey(const ContextKey& aCopy)
+  : mContext(aCopy.mContext),
+    mParent(aCopy.mParent),
+    mRules(aCopy.mRules)
+{
+  NS_IF_ADDREF(mContext);
+  NS_IF_ADDREF(mParent);
+  NS_IF_ADDREF(mRules);
+}
+
+ContextKey::~ContextKey(void)
+{
+  NS_IF_RELEASE(mContext);
+  NS_IF_RELEASE(mParent);
+  NS_IF_RELEASE(mRules);
+}
+
+void ContextKey::SetContext(nsIStyleContext* aContext)
+{
+  if (aContext != mContext) {
+    NS_IF_RELEASE(mContext);
+    mContext = aContext;
+    NS_IF_ADDREF(mContext);
+  }
+  NS_IF_RELEASE(mParent);
+  NS_IF_RELEASE(mRules);
+}
+
+PRBool ContextKey::Equals(const nsHashKey* aOther) const
+{
+  PRBool result = PR_TRUE;
+  const ContextKey* other = (const ContextKey*)aOther;
+
+  if (other != this) {
+    if ((nsnull == mContext) || (nsnull == other->mContext) || (mContext != other->mContext)) {
+      nsIStyleContext* otherParent = other->mParent;
+      if ((nsnull == otherParent) && (nsnull != other->mContext)) {
+        otherParent = other->mContext->GetParent();
+      }
+      else {
+        NS_IF_ADDREF(otherParent);  // simulate the above addref
+      }
+
+      if (mParent == otherParent) {
+        nsISupportsArray* otherRules = other->mRules;
+        if ((nsnull == otherRules) && (nsnull != other->mContext)) {
+          otherRules = other->mContext->GetStyleRules();
+        }
+        else {
+          NS_IF_ADDREF(otherRules); // simulate the above addref
+        }
+        if ((nsnull != mRules) && (nsnull != otherRules)) {
+          result = mRules->Equals(otherRules);
+        }
+        else {
+          result = PRBool((nsnull == mRules) && (nsnull == otherRules));
+        }
+        NS_IF_RELEASE(otherRules);
+      }
+      else {
+        result = PR_FALSE;
+      }
+      NS_IF_RELEASE(otherParent);
+    }
+  }
+  return result;
+}
+
+PRUint32 ContextKey::HashValue(void) const
+{
+  if (nsnull != mContext) {
+    return mContext->HashValue();
+  }
+  // we don't have a context yet, compute it like it would
+  PRUint32 hashValue = ((nsnull != mParent) ? mParent->HashValue() : 0);
+  if (nsnull != mRules) {
+    PRInt32 index = mRules->Count();
+    while (0 <= --index) {
+      nsIStyleRule* rule = (nsIStyleRule*)mRules->ElementAt(index);
+      PRUint32 hash = rule->HashValue();
+      hashValue ^= (hash & 0x7FFFFFFF);
+      NS_RELEASE(rule);
+    }
+  }
+  return hashValue;
+}
+
+nsHashKey* ContextKey::Clone(void) const
+{
+  return new ContextKey(*this);
+}
+
+
+class StyleSetImpl : public nsIStyleSet {
+public:
+  StyleSetImpl();
+
+  NS_DECL_ISUPPORTS
+
+  virtual void AppendOverrideStyleSheet(nsIStyleSheet* aSheet);
+  virtual void InsertOverrideStyleSheetAfter(nsIStyleSheet* aSheet,
+                                             nsIStyleSheet* aAfterSheet);
+  virtual void InsertOverrideStyleSheetBefore(nsIStyleSheet* aSheet,
+                                              nsIStyleSheet* aBeforeSheet);
+  virtual void RemoveOverrideStyleSheet(nsIStyleSheet* aSheet);
+  virtual PRInt32 GetNumberOfOverrideStyleSheets();
+  virtual nsIStyleSheet* GetOverrideStyleSheetAt(PRInt32 aIndex);
+
+  virtual void AppendDocStyleSheet(nsIStyleSheet* aSheet);
+  virtual void InsertDocStyleSheetAfter(nsIStyleSheet* aSheet,
+                                        nsIStyleSheet* aAfterSheet);
+  virtual void InsertDocStyleSheetBefore(nsIStyleSheet* aSheet,
+                                         nsIStyleSheet* aBeforeSheet);
+  virtual void RemoveDocStyleSheet(nsIStyleSheet* aSheet);
+  virtual PRInt32 GetNumberOfDocStyleSheets();
+  virtual nsIStyleSheet* GetDocStyleSheetAt(PRInt32 aIndex);
+
+  virtual void AppendBackstopStyleSheet(nsIStyleSheet* aSheet);
+  virtual void InsertBackstopStyleSheetAfter(nsIStyleSheet* aSheet,
+                                             nsIStyleSheet* aAfterSheet);
+  virtual void InsertBackstopStyleSheetBefore(nsIStyleSheet* aSheet,
+                                              nsIStyleSheet* aBeforeSheet);
+  virtual void RemoveBackstopStyleSheet(nsIStyleSheet* aSheet);
+  virtual PRInt32 GetNumberOfBackstopStyleSheets();
+  virtual nsIStyleSheet* GetBackstopStyleSheetAt(PRInt32 aIndex);
+
+  virtual nsIStyleContext* ResolveStyleFor(nsIPresContext* aPresContext,
+                                           nsIContent* aContent,
+                                           nsIFrame* aParentFrame);
+
+  // xxx style rules enumeration
+
+  virtual void List(FILE* out = stdout, PRInt32 aIndent = 0);
+
+private:
+  // These are not supported and are not implemented!
+  StyleSetImpl(const StyleSetImpl& aCopy);
+  StyleSetImpl& operator=(const StyleSetImpl& aCopy);
+
+protected:
+  virtual ~StyleSetImpl();
+  PRBool EnsureArray(nsISupportsArray** aArray);
+  PRInt32 RulesMatching(nsISupportsArray* aSheets,
+                        nsIPresContext* aPresContext,
+                        nsIContent* aContent,
+                        nsIFrame* aParentFrame,
+                        nsISupportsArray* aResults);
+  void  List(FILE* out, PRInt32 aIndent, nsISupportsArray* aSheets);
+
+  nsISupportsArray* mOverrideSheets;
+  nsISupportsArray* mDocSheets;
+  nsISupportsArray* mBackstopSheets;
+  nsHashtable mStyleContexts;
+};
+
+
+StyleSetImpl::StyleSetImpl()
+  : mOverrideSheets(nsnull),
+    mDocSheets(nsnull),
+    mBackstopSheets(nsnull)
+{
+  NS_INIT_REFCNT();
+}
+
+PRBool ReleaseContext(nsHashKey *aKey, void *aData)
+{
+  ((nsIStyleContext*)aData)->Release();
+  return PR_TRUE;
+}
+
+StyleSetImpl::~StyleSetImpl()
+{
+  NS_IF_RELEASE(mOverrideSheets);
+  NS_IF_RELEASE(mDocSheets);
+  NS_IF_RELEASE(mBackstopSheets);
+  mStyleContexts.Enumerate(ReleaseContext);
+}
+
+NS_IMPL_ISUPPORTS(StyleSetImpl, kIStyleSetIID)
+
+PRBool StyleSetImpl::EnsureArray(nsISupportsArray** aArray)
+{
+  if (nsnull == *aArray) {
+    if (NS_OK != NS_NewISupportsArray(aArray)) {
+      return PR_FALSE;
+    }
+  }
+  return PR_TRUE;
+}
+
+// ----- Override sheets
+
+void StyleSetImpl::AppendOverrideStyleSheet(nsIStyleSheet* aSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null arg");
+  if (EnsureArray(&mOverrideSheets)) {
+    mOverrideSheets->AppendElement(aSheet);
+  }
+}
+
+void StyleSetImpl::InsertOverrideStyleSheetAfter(nsIStyleSheet* aSheet,
+                                                 nsIStyleSheet* aAfterSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null arg");
+  if (EnsureArray(&mOverrideSheets)) {
+    PRInt32 index = mOverrideSheets->IndexOf(aAfterSheet);
+    mOverrideSheets->InsertElementAt(aSheet, ++index);
+  }
+}
+
+void StyleSetImpl::InsertOverrideStyleSheetBefore(nsIStyleSheet* aSheet,
+                                                  nsIStyleSheet* aBeforeSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null arg");
+  if (EnsureArray(&mOverrideSheets)) {
+    PRInt32 index = mOverrideSheets->IndexOf(aBeforeSheet);
+    mOverrideSheets->InsertElementAt(aSheet, ((-1 < index) ? index : 0));
+  }
+}
+
+void StyleSetImpl::RemoveOverrideStyleSheet(nsIStyleSheet* aSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null arg");
+
+  if (nsnull != mOverrideSheets) {
+    mOverrideSheets->RemoveElement(aSheet);
+  }
+}
+
+PRInt32 StyleSetImpl::GetNumberOfOverrideStyleSheets()
+{
+  if (nsnull != mOverrideSheets) {
+    return mOverrideSheets->Count();
+  }
+  return 0;
+}
+
+nsIStyleSheet* StyleSetImpl::GetOverrideStyleSheetAt(PRInt32 aIndex)
+{
+  nsIStyleSheet* sheet = nsnull;
+  if (nsnull == mOverrideSheets) {
+    sheet = (nsIStyleSheet*)mOverrideSheets->ElementAt(aIndex);
+  }
+  return sheet;
+}
+
+// -------- Doc Sheets
+
+void StyleSetImpl::AppendDocStyleSheet(nsIStyleSheet* aSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null arg");
+  if (EnsureArray(&mDocSheets)) {
+    mDocSheets->AppendElement(aSheet);
+  }
+}
+
+void StyleSetImpl::InsertDocStyleSheetAfter(nsIStyleSheet* aSheet,
+                                         nsIStyleSheet* aAfterSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null arg");
+  if (EnsureArray(&mDocSheets)) {
+    PRInt32 index = mDocSheets->IndexOf(aAfterSheet);
+    mDocSheets->InsertElementAt(aSheet, ++index);
+  }
+}
+
+void StyleSetImpl::InsertDocStyleSheetBefore(nsIStyleSheet* aSheet,
+                                          nsIStyleSheet* aBeforeSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null arg");
+  if (EnsureArray(&mDocSheets)) {
+    PRInt32 index = mDocSheets->IndexOf(aBeforeSheet);
+    mDocSheets->InsertElementAt(aSheet, ((-1 < index) ? index : 0));
+  }
+}
+
+void StyleSetImpl::RemoveDocStyleSheet(nsIStyleSheet* aSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null arg");
+
+  if (nsnull != mDocSheets) {
+    mDocSheets->RemoveElement(aSheet);
+  }
+}
+
+PRInt32 StyleSetImpl::GetNumberOfDocStyleSheets()
+{
+  if (nsnull != mDocSheets) {
+    return mDocSheets->Count();
+  }
+  return 0;
+}
+
+nsIStyleSheet* StyleSetImpl::GetDocStyleSheetAt(PRInt32 aIndex)
+{
+  nsIStyleSheet* sheet = nsnull;
+  if (nsnull == mDocSheets) {
+    sheet = (nsIStyleSheet*)mDocSheets->ElementAt(aIndex);
+  }
+  return sheet;
+}
+
+// ------ backstop sheets
+
+void StyleSetImpl::AppendBackstopStyleSheet(nsIStyleSheet* aSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null arg");
+  if (EnsureArray(&mBackstopSheets)) {
+    mBackstopSheets->AppendElement(aSheet);
+  }
+}
+
+void StyleSetImpl::InsertBackstopStyleSheetAfter(nsIStyleSheet* aSheet,
+                                                 nsIStyleSheet* aAfterSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null arg");
+  if (EnsureArray(&mBackstopSheets)) {
+    PRInt32 index = mBackstopSheets->IndexOf(aAfterSheet);
+    mBackstopSheets->InsertElementAt(aSheet, ++index);
+  }
+}
+
+void StyleSetImpl::InsertBackstopStyleSheetBefore(nsIStyleSheet* aSheet,
+                                                  nsIStyleSheet* aBeforeSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null arg");
+  if (EnsureArray(&mBackstopSheets)) {
+    PRInt32 index = mBackstopSheets->IndexOf(aBeforeSheet);
+    mBackstopSheets->InsertElementAt(aSheet, ((-1 < index) ? index : 0));
+  }
+}
+
+void StyleSetImpl::RemoveBackstopStyleSheet(nsIStyleSheet* aSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null arg");
+
+  if (nsnull != mBackstopSheets) {
+    mBackstopSheets->RemoveElement(aSheet);
+  }
+}
+
+PRInt32 StyleSetImpl::GetNumberOfBackstopStyleSheets()
+{
+  if (nsnull != mBackstopSheets) {
+    return mBackstopSheets->Count();
+  }
+  return 0;
+}
+
+nsIStyleSheet* StyleSetImpl::GetBackstopStyleSheetAt(PRInt32 aIndex)
+{
+  nsIStyleSheet* sheet = nsnull;
+  if (nsnull == mBackstopSheets) {
+    sheet = (nsIStyleSheet*)mBackstopSheets->ElementAt(aIndex);
+  }
+  return sheet;
+}
+
+PRInt32 StyleSetImpl::RulesMatching(nsISupportsArray* aSheets,
+                                    nsIPresContext* aPresContext,
+                                    nsIContent* aContent,
+                                    nsIFrame* aParentFrame,
+                                    nsISupportsArray* aResults)
+{
+  PRInt32 ruleCount = 0;
+
+  if (nsnull != aSheets) {
+    PRInt32 sheetCount = aSheets->Count();
+    PRInt32 index;
+    for (index = 0; index < sheetCount; index++) {
+      nsIStyleSheet* sheet = (nsIStyleSheet*)aSheets->ElementAt(index);
+      ruleCount += sheet->RulesMatching(aPresContext, aContent, aParentFrame,
+                                        aResults);
+      NS_RELEASE(sheet);
+    }
+  }
+  return ruleCount;
+}
+
+nsIStyleContext* StyleSetImpl::ResolveStyleFor(nsIPresContext* aPresContext,
+                                               nsIContent* aContent,
+                                               nsIFrame* aParentFrame)
+{
+  nsIStyleContext*  result = nsnull;
+
+  nsIStyleContext* parentContext = nsnull;
+  
+  if (nsnull != aParentFrame) {
+    parentContext = aParentFrame->GetStyleContext(aPresContext);
+    NS_ASSERTION(nsnull != parentContext, "parent must have style context");
+  }
+
+  // want to check parent frame's context for cached child context first
+
+  // then do a brute force rule search
+
+  nsISupportsArray*  rules = nsnull;
+  if (NS_OK == NS_NewISupportsArray(&rules)) {
+    PRInt32 ruleCount = RulesMatching(mOverrideSheets, aPresContext, aContent, aParentFrame, rules);
+    ruleCount += RulesMatching(mDocSheets, aPresContext, aContent, aParentFrame, rules);
+    ruleCount += RulesMatching(mBackstopSheets, aPresContext, aContent, aParentFrame, rules);
+
+    // then check for cached ruleSet to context or create
+    ContextKey tempKey(parentContext, rules);
+    result = (nsIStyleContext*)mStyleContexts.Get(&tempKey);
+    if (nsnull == result) {
+      if (NS_OK == NS_NewStyleContext(&result, rules, aPresContext, aContent, aParentFrame)) {
+        tempKey.SetContext(result);
+        mStyleContexts.Put(&tempKey, result);  // hashtable clones key, so this is OK (table gets first ref)
+        NS_ADDREF(result);  // add ref for the caller
+//fprintf(stdout, "+");
+      }
+    }
+    else {
+      NS_ADDREF(result);
+//fprintf(stdout, "-");
+    }
+    NS_RELEASE(rules);
+  }
+
+  NS_IF_RELEASE(parentContext);
+
+  return result;
+}
+
+// xxx style rules enumeration
+
+void StyleSetImpl::List(FILE* out, PRInt32 aIndent, nsISupportsArray* aSheets)
+{
+  PRInt32 count = ((nsnull != aSheets) ? aSheets->Count() : 0);
+
+  for (PRInt32 index = 0; index < count; index++) {
+    nsIStyleSheet* sheet = (nsIStyleSheet*)aSheets->ElementAt(index);
+    sheet->List(out, aIndent);
+    fputs("\n", out);
+    NS_RELEASE(sheet);
+  }
+}
+
+void StyleSetImpl::List(FILE* out, PRInt32 aIndent)
+{
+  List(out, aIndent, mOverrideSheets);
+  List(out, aIndent, mDocSheets);
+  List(out, aIndent, mBackstopSheets);
+}
+
+
+NS_LAYOUT nsresult
+NS_NewStyleSet(nsIStyleSet** aInstancePtrResult)
+{
+  if (aInstancePtrResult == nsnull) {
+    return NS_ERROR_NULL_POINTER;
+  }
+
+  StyleSetImpl  *it = new StyleSetImpl();
+
+  if (nsnull == it) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  return it->QueryInterface(kIStyleSetIID, (void **) aInstancePtrResult);
+}
diff --git a/mozilla/content/html/content/public/nsIHTMLContent.h b/mozilla/content/html/content/public/nsIHTMLContent.h
new file mode 100644
index 00000000000..339132b4a31
--- /dev/null
+++ b/mozilla/content/html/content/public/nsIHTMLContent.h
@@ -0,0 +1,89 @@
+/* -*- 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.
+ */
+#ifndef nsIHTMLContent_h___
+#define nsIHTMLContent_h___
+
+#include "nsIContent.h"
+#include "nsHTMLValue.h"
+class nsString;
+class nsIFrame;
+class nsISupportsArray;
+class nsIStyleRule;
+class nsIStyleContext;
+class nsIPresContext;
+
+// IID for the nsIHTMLContent class
+#define NS_IHTMLCONTENT_IID   \
+{ 0xb9e110b0, 0x94d6, 0x11d1, \
+  {0x89, 0x5c, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} }
+
+// Abstract interface for all html content
+class nsIHTMLContent : public nsIContent {
+public:
+  /**
+   * If this html content is a container, then compact asks it to minimize
+   * it's storage usage.
+   */
+  virtual void Compact() = 0;
+
+  virtual void SetAttribute(const nsString& aName, const nsString& aValue) = 0;
+  virtual void SetAttribute(nsIAtom* aAttribute, const nsString& aValue) = 0;
+  virtual void SetAttribute(nsIAtom* aAttribute,
+                            const nsHTMLValue& aValue=nsHTMLValue::kNull) = 0;
+
+  virtual void UnsetAttribute(nsIAtom* aAttribute) = 0;
+
+  virtual nsContentAttr GetAttribute(const nsString& aName,
+                                     nsString& aResult) const = 0;
+  virtual nsContentAttr GetAttribute(nsIAtom* aAttribute,
+                                     nsHTMLValue& aValue) const = 0;
+  virtual PRInt32 GetAllAttributeNames(nsISupportsArray* aArray) const = 0;
+  virtual PRInt32 GetAttributeCount(void) const = 0;
+
+  virtual void      SetID(nsIAtom* aID) = 0;
+  virtual nsIAtom*  GetID(void) const = 0;
+  virtual void      SetClass(nsIAtom* aClass) = 0;  // XXX this will have to change for CSS2
+  virtual nsIAtom*  GetClass(void) const = 0;  // XXX this will have to change for CSS2
+
+  virtual nsIStyleRule* GetStyleRule(void) = 0;
+
+  virtual void MapAttributesInto(nsIStyleContext* aContext, 
+                                 nsIPresContext* aPresContext) = 0;
+
+  /**
+   * Translate this piece of content to html. Note that this only
+   * translates this content object, not any children it might
+   * have. The caller is responsible for recursing down the
+   * hierarchy.
+   */
+  // XXX add in output character set information so that we know how
+  // to encode non 7 bit characters
+  virtual void ToHTMLString(nsString& aResult) const = 0;
+
+  virtual void ToHTML(FILE* out) const = 0;
+
+  /**
+   * Used by the html content's delegate to create a frame
+   * for the content.
+   */
+  virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext,
+                                PRInt32 aIndexInParent,
+                                nsIFrame* aParentFrame) = 0;
+};
+
+#endif /* nsIHTMLContent_h___ */
diff --git a/mozilla/content/html/content/src/nsHTMLAtoms.cpp b/mozilla/content/html/content/src/nsHTMLAtoms.cpp
new file mode 100644
index 00000000000..377ed58e605
--- /dev/null
+++ b/mozilla/content/html/content/src/nsHTMLAtoms.cpp
@@ -0,0 +1,367 @@
+/* -*- 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 "nsHTMLAtoms.h"
+
+nsIAtom* nsHTMLAtoms::a;
+nsIAtom* nsHTMLAtoms::above;
+nsIAtom* nsHTMLAtoms::action;
+nsIAtom* nsHTMLAtoms::align;
+nsIAtom* nsHTMLAtoms::alink;
+nsIAtom* nsHTMLAtoms::alt;
+nsIAtom* nsHTMLAtoms::archive;
+nsIAtom* nsHTMLAtoms::background;
+nsIAtom* nsHTMLAtoms::below;
+nsIAtom* nsHTMLAtoms::bgcolor;
+nsIAtom* nsHTMLAtoms::body;
+nsIAtom* nsHTMLAtoms::border;
+nsIAtom* nsHTMLAtoms::bordercolor;
+nsIAtom* nsHTMLAtoms::bottompadding;
+nsIAtom* nsHTMLAtoms::br;
+nsIAtom* nsHTMLAtoms::cellpadding;
+nsIAtom* nsHTMLAtoms::cellspacing;
+nsIAtom* nsHTMLAtoms::checked;
+nsIAtom* nsHTMLAtoms::kClass;
+nsIAtom* nsHTMLAtoms::classid;
+nsIAtom* nsHTMLAtoms::clear;
+nsIAtom* nsHTMLAtoms::clip;
+nsIAtom* nsHTMLAtoms::code;
+nsIAtom* nsHTMLAtoms::codebase;
+nsIAtom* nsHTMLAtoms::color;
+nsIAtom* nsHTMLAtoms::cols;
+nsIAtom* nsHTMLAtoms::colspan;
+nsIAtom* nsHTMLAtoms::compact;
+nsIAtom* nsHTMLAtoms::coords;
+nsIAtom* nsHTMLAtoms::data;
+nsIAtom* nsHTMLAtoms::dir;
+nsIAtom* nsHTMLAtoms::div;
+nsIAtom* nsHTMLAtoms::dl;
+nsIAtom* nsHTMLAtoms::encoding;
+nsIAtom* nsHTMLAtoms::face;
+nsIAtom* nsHTMLAtoms::font;
+nsIAtom* nsHTMLAtoms::fontWeight;
+nsIAtom* nsHTMLAtoms::frameborder;
+nsIAtom* nsHTMLAtoms::gutter;
+nsIAtom* nsHTMLAtoms::h1;
+nsIAtom* nsHTMLAtoms::h2;
+nsIAtom* nsHTMLAtoms::h3;
+nsIAtom* nsHTMLAtoms::h4;
+nsIAtom* nsHTMLAtoms::h5;
+nsIAtom* nsHTMLAtoms::h6;
+nsIAtom* nsHTMLAtoms::height;
+nsIAtom* nsHTMLAtoms::hidden;
+nsIAtom* nsHTMLAtoms::href;
+nsIAtom* nsHTMLAtoms::hspace;
+nsIAtom* nsHTMLAtoms::httpEquiv;
+nsIAtom* nsHTMLAtoms::id;
+nsIAtom* nsHTMLAtoms::ismap;
+nsIAtom* nsHTMLAtoms::language;
+nsIAtom* nsHTMLAtoms::li;
+nsIAtom* nsHTMLAtoms::link;
+nsIAtom* nsHTMLAtoms::left;
+nsIAtom* nsHTMLAtoms::leftpadding;
+nsIAtom* nsHTMLAtoms::lowsrc;
+nsIAtom* nsHTMLAtoms::marginheight;
+nsIAtom* nsHTMLAtoms::marginwidth;
+nsIAtom* nsHTMLAtoms::maxlength;
+nsIAtom* nsHTMLAtoms::mayscript;
+nsIAtom* nsHTMLAtoms::menu;
+nsIAtom* nsHTMLAtoms::method;
+nsIAtom* nsHTMLAtoms::multicol;
+nsIAtom* nsHTMLAtoms::multiple;
+nsIAtom* nsHTMLAtoms::name;
+nsIAtom* nsHTMLAtoms::noresize;
+nsIAtom* nsHTMLAtoms::noshade;
+nsIAtom* nsHTMLAtoms::nowrap;
+nsIAtom* nsHTMLAtoms::ol;
+nsIAtom* nsHTMLAtoms::onblur;
+nsIAtom* nsHTMLAtoms::onfocus;
+nsIAtom* nsHTMLAtoms::onload;
+nsIAtom* nsHTMLAtoms::onunload;
+nsIAtom* nsHTMLAtoms::overflow;
+nsIAtom* nsHTMLAtoms::p;
+nsIAtom* nsHTMLAtoms::pagex;
+nsIAtom* nsHTMLAtoms::pagey;
+nsIAtom* nsHTMLAtoms::pointSize;
+nsIAtom* nsHTMLAtoms::pre;
+nsIAtom* nsHTMLAtoms::prompt;
+nsIAtom* nsHTMLAtoms::rel;
+nsIAtom* nsHTMLAtoms::rightpadding;
+nsIAtom* nsHTMLAtoms::rows;
+nsIAtom* nsHTMLAtoms::rowspan;
+nsIAtom* nsHTMLAtoms::scrolling;
+nsIAtom* nsHTMLAtoms::selected;
+nsIAtom* nsHTMLAtoms::shape;
+nsIAtom* nsHTMLAtoms::size;
+nsIAtom* nsHTMLAtoms::src;
+nsIAtom* nsHTMLAtoms::start;
+nsIAtom* nsHTMLAtoms::suppress;
+nsIAtom* nsHTMLAtoms::tabstop;
+nsIAtom* nsHTMLAtoms::target;
+nsIAtom* nsHTMLAtoms::text;
+nsIAtom* nsHTMLAtoms::top;
+nsIAtom* nsHTMLAtoms::toppadding;
+nsIAtom* nsHTMLAtoms::type;
+nsIAtom* nsHTMLAtoms::ul;
+nsIAtom* nsHTMLAtoms::usemap;
+nsIAtom* nsHTMLAtoms::valign;
+nsIAtom* nsHTMLAtoms::value;
+nsIAtom* nsHTMLAtoms::variable;
+nsIAtom* nsHTMLAtoms::visibility;
+nsIAtom* nsHTMLAtoms::vlink;
+nsIAtom* nsHTMLAtoms::vspace;
+nsIAtom* nsHTMLAtoms::width;
+nsIAtom* nsHTMLAtoms::wrap;
+nsIAtom* nsHTMLAtoms::zindex;
+
+
+static nsrefcnt gRefCnt;
+
+void nsHTMLAtoms::AddrefAtoms()
+{
+  if (0 == gRefCnt) {
+    a = NS_NewAtom("A");
+    above = NS_NewAtom("ABOVE");
+    action = NS_NewAtom("ACTION");
+    align = NS_NewAtom("ALIGN");
+    alink = NS_NewAtom("ALINK");
+    alt = NS_NewAtom("ALT");
+    archive = NS_NewAtom("ARCHIVE");
+    background = NS_NewAtom("BACKGROUND");
+    below = NS_NewAtom("BELOW");
+    bgcolor = NS_NewAtom("BGCOLOR");
+    body = NS_NewAtom("BODY");
+    border = NS_NewAtom("BORDER");
+    bordercolor = NS_NewAtom("BORDERCOLOR");
+    bottompadding = NS_NewAtom("BOTTOMPADDING");
+    br = NS_NewAtom("BR");
+    cellpadding = NS_NewAtom("CELLPADDING");
+    cellspacing = NS_NewAtom("CELLSPACING");
+    checked = NS_NewAtom("CHECKED");
+    kClass = NS_NewAtom("CLASS");
+    classid = NS_NewAtom("CLASSID");
+    clear = NS_NewAtom("CLEAR");
+    clip = NS_NewAtom("CLIP");
+    code = NS_NewAtom("CODE");
+    codebase = NS_NewAtom("CODEBASE");
+    color = NS_NewAtom("COLOR");
+    cols = NS_NewAtom("COLS");
+    colspan = NS_NewAtom("COLSPAN");
+    compact = NS_NewAtom("COMPACT");
+    coords = NS_NewAtom("COORDS");
+    dir = NS_NewAtom("DIR");
+    div = NS_NewAtom("DIV");
+    dl = NS_NewAtom("DL");
+    data = NS_NewAtom("DATA");
+    encoding = NS_NewAtom("ENCODING");
+    face = NS_NewAtom("FACE");
+    font = NS_NewAtom("FONT");
+    fontWeight = NS_NewAtom("FONT-WEIGHT");
+    frameborder = NS_NewAtom("FRAMEBORDER");
+    gutter = NS_NewAtom("GUTTER");
+    h1 = NS_NewAtom("H1");
+    h2 = NS_NewAtom("H2");
+    h3 = NS_NewAtom("H3");
+    h4 = NS_NewAtom("H4");
+    h5 = NS_NewAtom("H5");
+    h6 = NS_NewAtom("H6");
+    height = NS_NewAtom("HEIGHT");
+    hidden = NS_NewAtom("HIDDEN");
+    href = NS_NewAtom("HREF");
+    hspace = NS_NewAtom("HSPACE");
+    httpEquiv = NS_NewAtom("HTTP-EQUIV");
+    id = NS_NewAtom("ID");
+    ismap = NS_NewAtom("ISMAP");
+    language = NS_NewAtom("LANGUAGE");
+    li = NS_NewAtom("LI");
+    link = NS_NewAtom("LINK");
+    left = NS_NewAtom("LEFT");
+    leftpadding = NS_NewAtom("LEFTPADDING");
+    lowsrc = NS_NewAtom("LOWSRC");
+    marginheight = NS_NewAtom("MARGINHEIGHT");
+    marginwidth = NS_NewAtom("MARGINWIDTH");
+    maxlength = NS_NewAtom("MAXLENGTH");
+    mayscript = NS_NewAtom("MAYSCRIPT");
+    menu = NS_NewAtom("MENU");
+    method = NS_NewAtom("METHOD");
+    multicol = NS_NewAtom("MULTICOL");
+    multiple = NS_NewAtom("MULTIPLE");
+    name = NS_NewAtom("NAME");
+    noresize = NS_NewAtom("NORESIZE");
+    noshade = NS_NewAtom("NOSHADE");
+    nowrap = NS_NewAtom("NOWRAP");
+    ol = NS_NewAtom("OL");
+    onblur = NS_NewAtom("ONBLUR");
+    onfocus = NS_NewAtom("ONFOCUS");
+    onload = NS_NewAtom("ONLOAD");
+    onunload = NS_NewAtom("ONUNLOAD");
+    overflow = NS_NewAtom("OVERFLOW");
+    p = NS_NewAtom("P");
+    pagex = NS_NewAtom("PAGEX");
+    pagey = NS_NewAtom("PAGEY");
+    pointSize = NS_NewAtom("POINT-SIZE");
+    pre = NS_NewAtom("PRE");
+    prompt = NS_NewAtom("PROMPT");
+    rel = NS_NewAtom("REL");
+    rightpadding = NS_NewAtom("RIGHTPADDING");
+    rows = NS_NewAtom("ROWS");
+    rowspan = NS_NewAtom("ROWSPAN");
+    scrolling = NS_NewAtom("SCROLLING");
+    selected = NS_NewAtom("SELECTED");
+    shape = NS_NewAtom("SHAPE");
+    size = NS_NewAtom("SIZE");
+    src = NS_NewAtom("SRC");
+    start = NS_NewAtom("START");
+    suppress = NS_NewAtom("SUPPRESS");
+    tabstop = NS_NewAtom("TABSTOP");
+    target = NS_NewAtom("TARGET");
+    text = NS_NewAtom("TEXT");
+    top = NS_NewAtom("TOP");
+    toppadding = NS_NewAtom("TOPPADDING");
+    type = NS_NewAtom("TYPE");
+    ul = NS_NewAtom("UL");
+    usemap = NS_NewAtom("USEMAP");
+    valign = NS_NewAtom("VALIGN");
+    value = NS_NewAtom("VALUE");
+    variable = NS_NewAtom("VARIABLE");
+    visibility = NS_NewAtom("VISIBILITY");
+    vlink = NS_NewAtom("VLINK");
+    vspace = NS_NewAtom("VSPACE");
+    width = NS_NewAtom("WIDTH");
+    wrap = NS_NewAtom("WRAP");
+    zindex = NS_NewAtom("ZINDEX");
+  }
+  ++gRefCnt;
+}
+
+void nsHTMLAtoms::ReleaseAtoms()
+{
+  NS_PRECONDITION(gRefCnt != 0, "bad release atoms");
+  if (--gRefCnt == 0) {
+    NS_RELEASE(a);
+    NS_RELEASE(above);
+    NS_RELEASE(action);
+    NS_RELEASE(align);
+    NS_RELEASE(alink);
+    NS_RELEASE(alt);
+    NS_RELEASE(archive);
+    NS_RELEASE(background);
+    NS_RELEASE(below);
+    NS_RELEASE(bgcolor);
+    NS_RELEASE(body);
+    NS_RELEASE(border);
+    NS_RELEASE(bordercolor);
+    NS_RELEASE(bottompadding);
+    NS_RELEASE(br);
+    NS_RELEASE(cellpadding);
+    NS_RELEASE(cellspacing);
+    NS_RELEASE(checked);
+    NS_RELEASE(kClass);
+    NS_RELEASE(classid);
+    NS_RELEASE(clear);
+    NS_RELEASE(clip);
+    NS_RELEASE(code);
+    NS_RELEASE(codebase);
+    NS_RELEASE(color);
+    NS_RELEASE(cols);
+    NS_RELEASE(colspan);
+    NS_RELEASE(compact);
+    NS_RELEASE(coords);
+    NS_RELEASE(dir);
+    NS_RELEASE(div);
+    NS_RELEASE(dl);
+    NS_RELEASE(data);
+    NS_RELEASE(encoding);
+    NS_RELEASE(face);
+    NS_RELEASE(font);
+    NS_RELEASE(fontWeight);
+    NS_RELEASE(frameborder);
+    NS_RELEASE(gutter);
+    NS_RELEASE(h1);
+    NS_RELEASE(h2);
+    NS_RELEASE(h3);
+    NS_RELEASE(h4);
+    NS_RELEASE(h5);
+    NS_RELEASE(h6);
+    NS_RELEASE(height);
+    NS_RELEASE(hidden);
+    NS_RELEASE(href);
+    NS_RELEASE(hspace);
+    NS_RELEASE(httpEquiv);
+    NS_RELEASE(id);
+    NS_RELEASE(ismap);
+    NS_RELEASE(language);
+    NS_RELEASE(li);
+    NS_RELEASE(link);
+    NS_RELEASE(left);
+    NS_RELEASE(leftpadding);
+    NS_RELEASE(lowsrc);
+    NS_RELEASE(marginheight);
+    NS_RELEASE(marginwidth);
+    NS_RELEASE(maxlength);
+    NS_RELEASE(mayscript);
+    NS_RELEASE(menu);
+    NS_RELEASE(method);
+    NS_RELEASE(multicol);
+    NS_RELEASE(multiple);
+    NS_RELEASE(name);
+    NS_RELEASE(noresize);
+    NS_RELEASE(noshade);
+    NS_RELEASE(nowrap);
+    NS_RELEASE(ol);
+    NS_RELEASE(onblur);
+    NS_RELEASE(onfocus);
+    NS_RELEASE(onload);
+    NS_RELEASE(onunload);
+    NS_RELEASE(overflow);
+    NS_RELEASE(p);
+    NS_RELEASE(pagex);
+    NS_RELEASE(pagey);
+    NS_RELEASE(pointSize);
+    NS_RELEASE(pre);
+    NS_RELEASE(prompt);
+    NS_RELEASE(rel);
+    NS_RELEASE(rightpadding);
+    NS_RELEASE(rows);
+    NS_RELEASE(rowspan);
+    NS_RELEASE(scrolling);
+    NS_RELEASE(selected);
+    NS_RELEASE(shape);
+    NS_RELEASE(size);
+    NS_RELEASE(src);
+    NS_RELEASE(start);
+    NS_RELEASE(suppress);
+    NS_RELEASE(tabstop);
+    NS_RELEASE(target);
+    NS_RELEASE(text);
+    NS_RELEASE(top);
+    NS_RELEASE(toppadding);
+    NS_RELEASE(type);
+    NS_RELEASE(ul);
+    NS_RELEASE(usemap);
+    NS_RELEASE(valign);
+    NS_RELEASE(value);
+    NS_RELEASE(variable);
+    NS_RELEASE(visibility);
+    NS_RELEASE(vlink);
+    NS_RELEASE(vspace);
+    NS_RELEASE(width);
+    NS_RELEASE(wrap);
+    NS_RELEASE(zindex);
+  }
+}
+
diff --git a/mozilla/content/html/content/src/nsHTMLAtoms.h b/mozilla/content/html/content/src/nsHTMLAtoms.h
new file mode 100644
index 00000000000..0f1eb0a8df1
--- /dev/null
+++ b/mozilla/content/html/content/src/nsHTMLAtoms.h
@@ -0,0 +1,168 @@
+/* -*- 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.
+ */
+#ifndef nsHTMLAtoms_h___
+#define nsHTMLAtoms_h___
+
+#include "nsIAtom.h"
+
+/**
+ * This class wraps up the creation (and destruction) of the standard
+ * set of html atoms used during normal html handling. This objects
+ * are created when the first html content object is created and they
+ * are destroyed when the last html content object is destroyed.
+ */
+class nsHTMLAtoms {
+public:
+
+  static void AddrefAtoms();
+  static void ReleaseAtoms();
+
+  // Alphabetical list of html attribute atoms
+  static nsIAtom* a;
+  static nsIAtom* above;
+  static nsIAtom* action;
+  static nsIAtom* align;
+  static nsIAtom* alink;
+  static nsIAtom* alt;
+  static nsIAtom* archive;
+
+  static nsIAtom* background;
+  static nsIAtom* below;
+  static nsIAtom* bgcolor;
+  static nsIAtom* body;
+  static nsIAtom* border;
+  static nsIAtom* bordercolor;
+  static nsIAtom* bottompadding;
+  static nsIAtom* br;
+
+  static nsIAtom* cellpadding;
+  static nsIAtom* cellspacing;
+  static nsIAtom* checked;
+  static nsIAtom* kClass;
+  static nsIAtom* classid;
+  static nsIAtom* clear;
+  static nsIAtom* clip;
+  static nsIAtom* code;
+  static nsIAtom* codebase;
+  static nsIAtom* color;
+  static nsIAtom* cols;
+  static nsIAtom* colspan;
+  static nsIAtom* compact;
+  static nsIAtom* coords;
+
+  static nsIAtom* data;
+  static nsIAtom* dir;
+  static nsIAtom* div;
+  static nsIAtom* dl;
+
+  static nsIAtom* encoding;
+
+  static nsIAtom* face;
+  static nsIAtom* font;
+  static nsIAtom* fontWeight;
+  static nsIAtom* frameborder;
+
+  static nsIAtom* gutter;
+
+  static nsIAtom* h1;
+  static nsIAtom* h2;
+  static nsIAtom* h3;
+  static nsIAtom* h4;
+  static nsIAtom* h5;
+  static nsIAtom* h6;
+  static nsIAtom* height;
+  static nsIAtom* hidden;
+  static nsIAtom* href;
+  static nsIAtom* hspace;
+  static nsIAtom* httpEquiv;
+
+  static nsIAtom* id;
+  static nsIAtom* ismap;
+
+  static nsIAtom* language;
+  static nsIAtom* li;
+  static nsIAtom* link;
+  static nsIAtom* left;
+  static nsIAtom* leftpadding;
+  static nsIAtom* lowsrc;
+
+  static nsIAtom* marginheight;
+  static nsIAtom* marginwidth;
+  static nsIAtom* maxlength;
+  static nsIAtom* mayscript;
+  static nsIAtom* menu;
+  static nsIAtom* method;
+  static nsIAtom* multicol;
+  static nsIAtom* multiple;
+
+  static nsIAtom* name;
+  static nsIAtom* noresize;
+  static nsIAtom* noshade;
+  static nsIAtom* nowrap;
+
+  static nsIAtom* ol;
+  static nsIAtom* onblur;
+  static nsIAtom* onfocus;
+  static nsIAtom* onload;
+  static nsIAtom* onunload;
+  static nsIAtom* overflow;
+
+  static nsIAtom* p;
+  static nsIAtom* pagex;
+  static nsIAtom* pagey;
+  static nsIAtom* pointSize;
+  static nsIAtom* pre;
+  static nsIAtom* prompt;
+
+  static nsIAtom* rel;
+  static nsIAtom* rightpadding;
+  static nsIAtom* rows;
+  static nsIAtom* rowspan;
+
+  static nsIAtom* scrolling;
+  static nsIAtom* selected;
+  static nsIAtom* shape;
+  static nsIAtom* size;
+  static nsIAtom* src;
+  static nsIAtom* start;
+  static nsIAtom* suppress;
+
+  static nsIAtom* tabstop;
+  static nsIAtom* target;
+  static nsIAtom* text;
+  static nsIAtom* top;
+  static nsIAtom* toppadding;
+  static nsIAtom* type;
+
+  static nsIAtom* ul;
+  static nsIAtom* usemap;
+
+  static nsIAtom* valign;
+  static nsIAtom* value;
+  static nsIAtom* variable;
+  static nsIAtom* visibility;
+  static nsIAtom* vlink;
+  static nsIAtom* vspace;
+
+  static nsIAtom* width;
+  static nsIAtom* wrap;
+
+  static nsIAtom* zindex;
+};
+
+#endif /* nsHTMLAtoms_h___ */
diff --git a/mozilla/content/html/document/src/nsHTMLContentSink.cpp b/mozilla/content/html/document/src/nsHTMLContentSink.cpp
new file mode 100644
index 00000000000..77b8ae042d8
--- /dev/null
+++ b/mozilla/content/html/document/src/nsHTMLContentSink.cpp
@@ -0,0 +1,1054 @@
+/* -*- 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 "nsIHTMLContentSink.h"
+#include "nsIStyleSheet.h"
+#include "nsIUnicharInputStream.h"
+#include "nsIHTMLContent.h"
+#include "nsIURL.h"
+#include "nsHTMLDocument.h"
+#include "nsIPresShell.h"
+#include "nsIPresContext.h"
+#include "nsHTMLTokens.h"
+#include "nsCRT.h"
+#include "prtime.h"
+#include "prlog.h"
+
+#include "nsHTMLParts.h"
+#include "nsTablePart.h"
+#include "nsTableRow.h"
+#include "nsTableCell.h"
+
+#include "nsHTMLForms.h"
+#include "nsIFormManager.h"
+#include "nsIImageMap.h"
+
+// XXX attribute values have entities in them - use the parsers expander!
+
+// XXX Go through a factory for this one
+#include "nsICSSParser.h"
+
+#ifdef NS_DEBUG
+
+static PRInt32 gLogLevel = 0;
+
+#define NOISY_SINK_TRACE(_msg,_node)             \
+{                                                \
+  char buf[200];                                 \
+  (_node).GetText().ToCString(buf, sizeof(buf)); \
+  if (gLogLevel >= PR_LOG_WARNING) {             \
+    PR_LogPrint("%s; [%s]", _msg, buf);          \
+  }                                              \
+}
+
+#define REALLY_NOISY_SINK_TRACE(_msg,_node)      \
+{                                                \
+  char buf[200];                                 \
+  (_node).GetText().ToCString(buf, sizeof(buf)); \
+  if (gLogLevel >= PR_LOG_DEBUG) {               \
+    PR_LogPrint("%s; [%s]", _msg, buf);          \
+  }                                              \
+}
+
+#else /* !NOISY_SINK */
+
+#define NOISY_SINK_TRACE(_a,_node)
+#define REALLY_NOISY_SINK_TRACE(_a,_node)
+
+#endif /* NOISY_SINK */
+
+//----------------------------------------------------------------------
+
+static NS_DEFINE_IID(kIHTMLContentSinkIID, NS_IHTMLCONTENTSINK_IID);
+
+class HTMLContentSink : public nsIHTMLContentSink {
+public:
+
+  NS_DECL_ISUPPORTS
+
+  HTMLContentSink();
+  ~HTMLContentSink();
+
+  void* operator new(size_t size) {
+    void* rv = ::operator new(size);
+    nsCRT::zero(rv, size);
+    return (void*) rv;
+  }
+
+  nsresult Init(nsIDocument* aDoc, nsIURL* aURL);
+  nsIHTMLContent* GetCurrentContainer(eHTMLTags* aType);
+
+  virtual PRBool SetTitle(const nsString& aValue);
+
+  // Called when Opening or closing the main HTML container
+  virtual PRBool OpenHTML(const nsIParserNode& aNode);
+  virtual PRBool CloseHTML(const nsIParserNode& aNode);
+
+  // Called when Opening or closing the main HEAD container
+  virtual PRBool OpenHead(const nsIParserNode& aNode);
+  virtual PRBool CloseHead(const nsIParserNode& aNode);
+
+  // Called when Opening or closing the main BODY container
+  virtual PRBool OpenBody(const nsIParserNode& aNode);
+  virtual PRBool CloseBody(const nsIParserNode& aNode);
+
+  // Called when Opening or closing FORM containers
+  virtual PRBool OpenForm(const nsIParserNode& aNode);
+  virtual PRBool CloseForm(const nsIParserNode& aNode);
+
+  // Called when Opening or closing the main FRAMESET container
+  virtual PRBool OpenFrameset(const nsIParserNode& aNode);
+  virtual PRBool CloseFrameset(const nsIParserNode& aNode);
+
+  // Called when Opening or closing a general container
+  // This includes: OL,UL,DIR,SPAN,TABLE,H[1..6],etc.
+  // Until proven otherwise, I also plan to toss STYLE,
+  // FORMS, FRAME, SCRIPT, etc. here too!
+  virtual PRBool OpenContainer(const nsIParserNode& aNode);
+  virtual PRBool CloseContainer(const nsIParserNode& aNode);
+  virtual PRBool CloseTopmostContainer();
+
+  // Called for text, comments and so on...
+  virtual PRBool AddLeaf(const nsIParserNode& aNode);
+
+protected:
+
+  void StartLayout();
+
+  void ReflowNewContent();
+
+  //----------------------------------------------------------------------
+  // Leaf tag handler routines that translate a leaf tag into a
+  // content object, processing all of the tag attributes.
+
+  nsresult ProcessAREATag(const nsIParserNode& aNode);
+  nsresult ProcessBASETag(const nsIParserNode& aNode);
+  nsresult ProcessSTYLETag(const nsIParserNode& aNode);
+
+  nsresult ProcessBRTag(nsIHTMLContent** aInstancePtrResult,
+                        const nsIParserNode& aNode);
+  nsresult ProcessHRTag(nsIHTMLContent** aInstancePtrResult,
+                        const nsIParserNode& aNode);
+  nsresult ProcessINPUTTag(nsIHTMLContent** aInstancePtrResult,
+                           const nsIParserNode& aNode);
+  nsresult ProcessIMGTag(nsIHTMLContent** aInstancePtrResult,
+                         const nsIParserNode& aNode);
+  nsresult ProcessSPACERTag(nsIHTMLContent** aInstancePtrResult,
+                            const nsIParserNode& aNode);
+  nsresult ProcessWBRTag(nsIHTMLContent** aInstancePtrResult,
+                         const nsIParserNode& aNode);
+
+  //----------------------------------------------------------------------
+
+  void GetAttributeValueAt(const nsIParserNode& aNode,
+                           PRInt32 aIndex,
+                           nsString& aResult);
+
+  nsresult AddAttributes(const nsIParserNode& aNode,
+                         nsIHTMLContent* aInstancePtrResult);
+
+  nsresult LoadStyleSheet(nsIURL* aURL,
+                          nsIUnicharInputStream* aUIN);
+
+  nsIDocument* mDocument;
+  nsIURL* mDocumentURL;
+
+  eHTMLTags mNodeStack[100];/* XXX */
+  nsIHTMLContent* mContainerStack[100];/* XXX */
+  PRInt32 mStackPos;
+  nsString* mTitle;
+  nsString mBaseHREF;
+  nsString mBaseTarget;
+  nsIStyleSheet* mStyleSheet;
+  nsIFormManager* mCurrentForm;
+  nsIImageMap* mCurrentMap;
+
+  nsIHTMLContent* mRoot;
+  nsIHTMLContent* mBody;
+
+  PRTime mLastUpdateTime;
+  PRTime mUpdateDelta;
+  PRBool mLayoutStarted;
+};
+
+// Note: operator new zeros our memory
+HTMLContentSink::HTMLContentSink()
+{
+#if 0
+  if (nsnull == gSinkLog) {
+    gSinkLog = PR_NewLogModule("HTMLContentSink");
+  }
+#endif
+
+  // Set the first update delta to be 50ms
+  LL_I2L(mUpdateDelta, PR_USEC_PER_MSEC * 50);
+}
+
+HTMLContentSink::~HTMLContentSink()
+{
+  NS_IF_RELEASE(mBody);
+  NS_IF_RELEASE(mRoot);
+  NS_IF_RELEASE(mDocumentURL);
+  NS_IF_RELEASE(mStyleSheet);
+  NS_IF_RELEASE(mCurrentForm);
+  NS_IF_RELEASE(mCurrentMap);
+  if (nsnull != mTitle) {
+    delete mTitle;
+  }
+}
+
+nsresult HTMLContentSink::Init(nsIDocument* aDoc, nsIURL* aDocURL)
+{
+  mDocument = aDoc;
+  NS_IF_ADDREF(aDoc);
+
+  mDocumentURL = aDocURL;
+  NS_IF_ADDREF(aDocURL);
+
+  // Make root part
+  nsresult rv = NS_NewRootPart(&mRoot, aDoc);
+  if (NS_OK == rv) {
+  }
+
+  return rv;
+}
+
+NS_IMPL_ISUPPORTS(HTMLContentSink,kIHTMLContentSinkIID)
+
+PRBool HTMLContentSink::OpenHTML(const nsIParserNode& aNode)
+{
+  NOISY_SINK_TRACE("OpenHTML", aNode)
+  NS_PRECONDITION(0 == mStackPos, "bad stack pos");
+
+  mNodeStack[0] = (eHTMLTags)aNode.GetNodeType();
+  mContainerStack[0] = mRoot;
+  mStackPos = 1;
+
+  return PR_TRUE;
+}
+
+PRBool HTMLContentSink::CloseHTML(const nsIParserNode& aNode)
+{
+  NOISY_SINK_TRACE("CloseHTML", aNode)
+
+  NS_ASSERTION(mStackPos > 0, "bad bad");
+  mNodeStack[--mStackPos] = eHTMLTag_unknown;
+
+  PRInt32 i, ns = mDocument->GetNumberOfShells();
+  for (i = 0; i < ns; i++) {
+    nsIPresShell* shell = mDocument->GetShellAt(i);
+    if (nsnull != shell) {
+      shell->BeginObservingDocument();
+      NS_RELEASE(shell);
+    }
+  }
+  NS_IF_RELEASE(mCurrentForm);
+
+  return PR_TRUE;
+}
+
+PRBool HTMLContentSink::OpenHead(const nsIParserNode& aNode)
+{
+  NOISY_SINK_TRACE("OpenHead", aNode)
+
+  mNodeStack[mStackPos++] = (eHTMLTags)aNode.GetNodeType();
+  return PR_TRUE;
+}
+
+PRBool HTMLContentSink::CloseHead(const nsIParserNode& aNode)
+{
+  NOISY_SINK_TRACE("CloseHead", aNode)
+
+  NS_ASSERTION(mStackPos > 0, "bad bad");
+  mNodeStack[--mStackPos] = eHTMLTag_unknown;
+  return PR_TRUE;
+}
+
+PRBool HTMLContentSink::SetTitle(const nsString& aValue)
+{
+  if (nsnull == mTitle) {
+    mTitle = new nsString(aValue);
+  }
+  else {
+    *mTitle = aValue;
+  }
+  mTitle->CompressWhitespace(PR_TRUE, PR_TRUE);
+  ((nsHTMLDocument*)mDocument)->SetTitle(*mTitle);
+  return PR_TRUE;
+}
+
+PRBool HTMLContentSink::OpenBody(const nsIParserNode& aNode)
+{
+  NOISY_SINK_TRACE("OpenBody", aNode)
+
+  PRBool startLayout = PR_FALSE;
+  if (nsnull == mBody) {
+    nsIAtom* atom = NS_NewAtom("BODY");
+    nsresult rv = NS_NewBodyPart(&mBody, atom);
+    if (NS_OK == rv) {
+      mRoot->AppendChild(mBody);
+      startLayout = PR_TRUE;
+    }
+    NS_RELEASE(atom);
+  }
+
+  mNodeStack[mStackPos] = (eHTMLTags)aNode.GetNodeType();
+  mContainerStack[mStackPos] = mBody;
+  mStackPos++;
+
+  // Add attributes to the body content object, but only if it's really a body
+  // tag that is triggering the OpenBody.
+  if (aNode.GetText().EqualsIgnoreCase("body")) {
+    AddAttributes(aNode, mBody);
+    // XXX If the body already existed and has been reflowed somewhat
+    // then we need to trigger a style change
+  }
+
+  if (startLayout) {
+    // XXX This has to be done now that the body is in because we
+    // don't know how to handle a content-appended reflow if the
+    // root has no children
+    StartLayout();
+  }
+
+  return PR_TRUE;
+}
+
+PRBool HTMLContentSink::CloseBody(const nsIParserNode& aNode)
+{
+  NOISY_SINK_TRACE("CloseBody", aNode)
+
+  NS_ASSERTION(mStackPos > 0, "bad bad");
+  mNodeStack[--mStackPos] = eHTMLTag_unknown;
+
+  // Reflow any lingering content
+  ReflowNewContent();
+
+  return PR_TRUE;
+}
+
+
+PRBool HTMLContentSink::OpenForm(const nsIParserNode& aNode)
+{
+  NOISY_SINK_TRACE("OpenForm", aNode)
+
+  // Close out previous form if it's there
+  if (nsnull != mCurrentForm) {
+	  NS_RELEASE(mCurrentForm);
+    mCurrentForm = nsnull;
+  }
+
+  // Create new form
+  nsAutoString tmp(aNode.GetText());
+  tmp.ToUpperCase();
+  nsIAtom* atom = NS_NewAtom(tmp);
+  nsresult rv = NS_NewHTMLForm(&mCurrentForm, atom);
+  NS_RELEASE(atom);
+
+  if (NS_OK == rv) {
+    // Add tag attributes to the form
+    nsAutoString k, v;
+    PRInt32 ac = aNode.GetAttributeCount();
+    for (PRInt32 i = 0; i < ac; i++) {
+      // Get upper-cased key
+      const nsString& key = aNode.GetKeyAt(i);
+      k.SetLength(0);
+      k.Append(key);
+      k.ToUpperCase();
+
+      // Get value and remove mandatory quotes
+      GetAttributeValueAt(aNode, i, v);
+      mCurrentForm->SetAttribute(k, v);
+    }
+  }
+
+  return PR_TRUE;
+}
+
+PRBool HTMLContentSink::CloseForm(const nsIParserNode& aNode)
+{
+  NOISY_SINK_TRACE("CloseForm", aNode)
+
+  if (nsnull != mCurrentForm) {
+	  NS_RELEASE(mCurrentForm);
+    mCurrentForm = nsnull;
+  }
+  return PR_TRUE;
+}
+
+PRBool HTMLContentSink::OpenFrameset(const nsIParserNode& aNode)
+{
+  NOISY_SINK_TRACE("OpenFrameset", aNode)
+
+  mNodeStack[mStackPos++] = (eHTMLTags)aNode.GetNodeType();
+  return PR_TRUE;
+}
+
+PRBool HTMLContentSink::CloseFrameset(const nsIParserNode& aNode)
+{
+  NOISY_SINK_TRACE("CloseFrameset", aNode)
+
+  mNodeStack[--mStackPos] = eHTMLTag_unknown;
+  return PR_TRUE;
+}
+
+PRBool HTMLContentSink::OpenContainer(const nsIParserNode& aNode)
+{
+  NOISY_SINK_TRACE("OpenContainer", aNode)
+
+  nsAutoString tmp(aNode.GetText());
+  tmp.ToUpperCase();
+  nsIAtom* atom = NS_NewAtom(tmp);
+
+  nsresult rv;
+  nsIHTMLContent* container = nsnull;
+  if (aNode.GetTokenType() == eToken_start) {
+    switch (aNode.GetNodeType()) {
+    case eHTMLTag_map:
+      NS_IF_RELEASE(mCurrentMap);
+      rv = NS_NewImageMap(&mCurrentMap, atom);
+      if (NS_OK == rv) {
+        // Look for name attribute and set the map name
+        PRInt32 ac = aNode.GetAttributeCount();
+        for (PRInt32 i = 0; i < ac; i++) {
+          const nsString& key = aNode.GetKeyAt(i);
+          if (key.EqualsIgnoreCase("name")) {
+            nsAutoString name;
+            GetAttributeValueAt(aNode, i, name);
+            name.StripWhitespace();     // XXX leading, trailing, interior non=-space ws is removed
+            mCurrentMap->SetName(name);
+          }
+        }
+        // Add the map to the document
+        ((nsHTMLDocument*)mDocument)->AddImageMap(mCurrentMap);
+      }
+      return PR_TRUE;
+
+    case eHTMLTag_table:
+      rv = NS_NewTablePart(&container, atom);
+      break;
+
+    case eHTMLTag_caption:
+      rv = NS_NewTableCaptionPart(&container, atom);
+      break;
+
+    case eHTMLTag_tr:
+      rv = NS_NewTableRowPart(&container, atom);
+      break;
+
+    case eHTMLTag_tbody:
+    case eHTMLTag_thead:
+    case eHTMLTag_tfoot:
+      rv = NS_NewTableRowGroupPart(&container, atom);
+      break;
+
+    case eHTMLTag_colgroup:
+      rv = NS_NewTableColGroupPart(&container, atom);
+      break;
+
+    case eHTMLTag_col:
+      rv = NS_NewTableColPart(&container, atom);
+      break;
+
+    case eHTMLTag_td:
+    case eHTMLTag_th:
+      rv = NS_NewTableCellPart(&container, atom);
+      break;
+
+    default:
+      rv = NS_NewHTMLContainer(&container, atom);
+      break;
+    }
+  }
+
+  // XXX for now assume that if it's a container, it's a simple container
+  mNodeStack[mStackPos] = (eHTMLTags) aNode.GetNodeType();
+  mContainerStack[mStackPos] = container;
+
+  if (nsnull != container) {
+    container->SetDocument(mDocument);
+    rv = AddAttributes(aNode, container);
+    mStackPos++;
+  }
+
+  NS_RELEASE(atom);
+  return PR_TRUE;
+}
+
+PRBool HTMLContentSink::CloseContainer(const nsIParserNode& aNode)
+{
+  NOISY_SINK_TRACE("CloseContainer", aNode)
+
+  switch (aNode.GetNodeType()) {
+  case eHTMLTag_map:
+    NS_IF_RELEASE(mCurrentMap);
+    return PR_TRUE;
+  }
+
+  // XXX we could assert things about the top tag name == aNode.getText
+  if (0 == mStackPos) {
+    // Can't pop empty stack
+    return PR_TRUE;
+  }
+
+  --mStackPos;
+  nsIHTMLContent* container = mContainerStack[mStackPos];
+  mNodeStack[mStackPos] = eHTMLTag_unknown;
+  mContainerStack[mStackPos] = nsnull;
+
+  if (nsnull != container) {
+    // Now that this container is complete, append it to it's parent
+    eHTMLTags parentType;
+    nsIHTMLContent* parent = GetCurrentContainer(&parentType);
+    container->Compact();
+
+    if(parent) {
+      parent->AppendChild(container);
+      if (parent == mBody) {
+        // We just closed a child of the body off. Trigger a
+        // content-appended reflow if enough time has elapsed
+        PRTime now = PR_Now();
+        if (now - mLastUpdateTime >= mUpdateDelta) {
+          mLastUpdateTime = now;
+          mUpdateDelta += mUpdateDelta;
+          ReflowNewContent();
+        }
+      }
+    }
+    NS_RELEASE(container);
+  }
+  return PR_TRUE;
+}
+
+void HTMLContentSink::StartLayout()
+{
+  if (!mLayoutStarted) {
+    PRInt32 i, ns = mDocument->GetNumberOfShells();
+    for (i = 0; i < ns; i++) {
+      nsIPresShell* shell = mDocument->GetShellAt(i);
+      if (nsnull != shell) {
+        nsIPresContext* cx = shell->GetPresContext();
+        nsRect r = cx->GetVisibleArea();
+        shell->ResizeReflow(r.width, r.height);
+        NS_RELEASE(cx);
+        NS_RELEASE(shell);
+      }
+    }
+    mLayoutStarted = PR_TRUE;
+  }
+}
+
+void HTMLContentSink::ReflowNewContent()
+{
+  printf("reflow body\n");
+
+  // Trigger reflows in each of the presentation shells
+  PRInt32 i, ns = mDocument->GetNumberOfShells();
+  for (i = 0; i < ns; i++) {
+    nsIPresShell* shell = mDocument->GetShellAt(i);
+    if (nsnull != shell) {
+      shell->ContentAppended(mBody);
+      NS_RELEASE(shell);
+    }
+  }
+}
+
+PRBool HTMLContentSink::CloseTopmostContainer()
+{
+  return PR_TRUE;
+}
+
+nsIHTMLContent* HTMLContentSink::GetCurrentContainer(eHTMLTags* aType)
+{
+  nsIHTMLContent* parent;
+  if (mStackPos <= 2) {         // assume HTML and BODY are on the stack
+    parent = mBody;
+    *aType = eHTMLTag_body;
+  } else {
+    parent = mContainerStack[mStackPos - 1];
+    *aType = mNodeStack[mStackPos - 1];
+  }
+  return parent;
+}
+
+//----------------------------------------------------------------------
+
+// Leaf tag handling code
+
+PRBool HTMLContentSink::AddLeaf(const nsIParserNode& aNode)
+{
+  REALLY_NOISY_SINK_TRACE("AddLeaf", aNode)
+
+  // Check for nodes that require special handling
+  switch (aNode.GetNodeType()) {
+  case eHTMLTag_style:
+    ProcessSTYLETag(aNode);
+    return PR_TRUE;
+
+  case eHTMLTag_script:
+    return PR_TRUE;
+
+  case eHTMLTag_area:
+    ProcessAREATag(aNode);
+    return PR_TRUE;
+  }
+
+  eHTMLTags parentType;
+  nsIHTMLContent* parent = GetCurrentContainer(&parentType);
+
+  switch (parentType) {
+  case eHTMLTag_table:
+  case eHTMLTag_tr:
+    // XXX Discard leaf content (those annoying \n's really) in
+    // table's or table rows
+    return PR_TRUE;
+  }
+
+  nsresult rv = NS_OK;
+  nsIHTMLContent* leaf = nsnull;
+  switch (aNode.GetTokenType()) {
+  case eToken_start:
+    switch (aNode.GetNodeType()) {
+    case eHTMLTag_br:
+      rv = ProcessBRTag(&leaf, aNode);
+      break;
+    case eHTMLTag_hr:
+      rv = ProcessHRTag(&leaf, aNode);
+      break;
+    case eHTMLTag_input:
+      rv = ProcessINPUTTag(&leaf, aNode);
+      break;
+    case eHTMLTag_img:
+      rv = ProcessIMGTag(&leaf, aNode);
+      break;
+    case eHTMLTag_spacer:
+      rv = ProcessSPACERTag(&leaf, aNode);
+      break;
+    }
+    break;
+
+  case eToken_text:
+  case eToken_whitespace:
+    {
+      nsAutoString tmp;
+      tmp.Append(aNode.GetText());
+      rv = NS_NewHTMLText(&leaf, tmp.GetUnicode(), tmp.Length());
+    }
+    break;
+
+    // XXX ick
+  case eToken_newline:
+    {
+      nsAutoString tmp;
+      tmp.Append('\n');
+      rv = NS_NewHTMLText(&leaf, tmp.GetUnicode(), tmp.Length());
+    }
+    break;
+
+  case eToken_entity:
+    {
+      nsAutoString tmp;
+      PRInt32 unicode = aNode.TranslateToUnicode();
+      if (unicode < 0) {
+        tmp.Append(aNode.GetText());
+      } else {
+        tmp.Append(PRUnichar(unicode));
+      }
+      rv = NS_NewHTMLText(&leaf, tmp.GetUnicode(), tmp.Length());
+    }
+    break;
+
+  case eToken_skippedcontent:
+    break;
+  }
+
+  if (NS_OK == rv) {
+    if (nsnull != leaf) {
+      if (nsnull != parent) {
+        parent->AppendChild(leaf);
+      } else {
+        // XXX drop stuff on the floor that doesn't have a container!
+        // Bad parser!
+      }
+    }
+  }
+  NS_IF_RELEASE(leaf);
+
+  return PR_TRUE;
+}
+
+void HTMLContentSink::GetAttributeValueAt(const nsIParserNode& aNode,
+                                          PRInt32 aIndex,
+                                          nsString& aResult)
+{
+  // Copy value
+  const nsString& value = aNode.GetValueAt(aIndex);
+  aResult.Truncate();
+  aResult.Append(value);
+
+  // strip quotes if present
+  PRUnichar first = aResult.First();
+  if ((first == '"') || (first == '\'')) {
+    if (aResult.Last() == first) {
+      aResult.Cut(0, 1);
+      PRInt32 pos = aResult.Length() - 1;
+      if (pos >= 0) {
+        aResult.Cut(pos, 1);
+      }
+    } else {
+      // Mismatched quotes - leave them in
+    }
+  }
+}
+
+nsresult HTMLContentSink::AddAttributes(const nsIParserNode& aNode,
+                                        nsIHTMLContent* aInstancePtrResult)
+{
+  nsIContent* content = (nsIContent*) aInstancePtrResult;
+
+  // Add tag attributes to the content attributes
+  nsAutoString k, v;
+  PRInt32 ac = aNode.GetAttributeCount();
+  for (PRInt32 i = 0; i < ac; i++) {
+    // Get upper-cased key
+    const nsString& key = aNode.GetKeyAt(i);
+    k.Truncate();
+    k.Append(key);
+    k.ToUpperCase();
+    
+    // Get value and remove mandatory quotes
+    GetAttributeValueAt(aNode, i, v);
+
+    content->SetAttribute(k, v);
+  }
+
+  return NS_OK;
+}
+
+nsresult HTMLContentSink::ProcessAREATag(const nsIParserNode& aNode)
+{
+  if (nsnull != mCurrentMap) {
+    nsAutoString shape, coords, href, target(mBaseTarget), alt;
+    PRInt32 ac = aNode.GetAttributeCount();
+    PRBool suppress = PR_FALSE;
+    for (PRInt32 i = 0; i < ac; i++) {
+      // Get upper-cased key
+      const nsString& key = aNode.GetKeyAt(i);
+      if (key.EqualsIgnoreCase("shape")) {
+        GetAttributeValueAt(aNode, i, shape);
+      }
+      else if (key.EqualsIgnoreCase("coords")) {
+        GetAttributeValueAt(aNode, i, coords);
+      }
+      else if (key.EqualsIgnoreCase("href")) {
+        GetAttributeValueAt(aNode, i, href);
+        href.StripWhitespace();
+      }
+      else if (key.EqualsIgnoreCase("target")) {
+        GetAttributeValueAt(aNode, i, target);
+      }
+      else if (key.EqualsIgnoreCase("alt")) {
+        GetAttributeValueAt(aNode, i, alt);
+      }
+      else if (key.EqualsIgnoreCase("suppress")) {
+        suppress = PR_TRUE;
+      }
+    }
+    mCurrentMap->AddArea(mBaseHREF, shape, coords, href, target, alt,
+                         suppress);
+  }
+  return NS_OK;
+}
+
+nsresult HTMLContentSink::ProcessBASETag(const nsIParserNode& aNode)
+{
+  PRInt32 ac = aNode.GetAttributeCount();
+  for (PRInt32 i = 0; i < ac; i++) {
+    const nsString& key = aNode.GetKeyAt(i);
+    if (key.EqualsIgnoreCase("href")) {
+      const nsString& href = aNode.GetValueAt(i);
+      if (href.Length() > 0) {
+        mBaseHREF = href;
+      }
+    } else if (key.EqualsIgnoreCase("target")) {
+
+      const nsString& target= aNode.GetValueAt(i);
+      if (target.Length() > 0) {
+        mBaseTarget = target;
+      }
+    }
+  }
+  return NS_OK;
+}
+
+nsresult HTMLContentSink::ProcessBRTag(nsIHTMLContent** aInstancePtrResult,
+                                       const nsIParserNode& aNode)
+{
+  nsresult rv = NS_OK;
+  nsAutoString tmp(aNode.GetText());
+  tmp.ToUpperCase();
+  nsIAtom* atom = NS_NewAtom(tmp);
+  rv = NS_NewHTMLBreak(aInstancePtrResult, atom);
+  if (NS_OK == rv) {
+    rv = AddAttributes(aNode, *aInstancePtrResult);
+  }
+  NS_RELEASE(atom);
+  return rv;
+}
+
+nsresult HTMLContentSink::ProcessHRTag(nsIHTMLContent** aInstancePtrResult,
+                                       const nsIParserNode& aNode)
+{
+  nsresult rv = NS_OK;
+  nsAutoString tmp(aNode.GetText());
+  tmp.ToUpperCase();
+  nsIAtom* atom = NS_NewAtom(tmp);
+  rv = NS_NewHRulePart(aInstancePtrResult, atom);
+  if (NS_OK == rv) {
+    rv = AddAttributes(aNode, *aInstancePtrResult);
+  }
+  NS_RELEASE(atom);
+  return rv;
+}
+
+nsresult HTMLContentSink::ProcessIMGTag(nsIHTMLContent** aInstancePtrResult,
+                                        const nsIParserNode& aNode)
+{
+  nsAutoString tmp(aNode.GetText());
+  tmp.ToUpperCase();
+  nsIAtom* atom = NS_NewAtom(tmp);
+  nsresult rv = NS_NewHTMLImage(aInstancePtrResult, atom);
+  if (NS_OK == rv) {
+    rv = AddAttributes(aNode, *aInstancePtrResult);
+    // XXX get base url to image
+  }
+  NS_RELEASE(atom);
+  return rv;
+}
+
+nsresult HTMLContentSink::ProcessSPACERTag(nsIHTMLContent** aInstancePtrResult,
+                                           const nsIParserNode& aNode)
+{
+  nsAutoString tmp(aNode.GetText());
+  tmp.ToUpperCase();
+  nsIAtom* atom = NS_NewAtom(tmp);
+  nsresult rv = NS_NewHTMLSpacer(aInstancePtrResult, atom);
+  if (NS_OK == rv) {
+    rv = AddAttributes(aNode, *aInstancePtrResult);
+  }
+  NS_RELEASE(atom);
+  return rv;
+}
+
+// 3 ways to load a style sheet: inline, style src=, link tag
+  // XXX What does nav do if we have SRC= and some style data inline?
+nsresult HTMLContentSink::ProcessSTYLETag(const nsIParserNode& aNode)
+{
+  nsresult rv = NS_OK;
+  PRInt32 i, ac = aNode.GetAttributeCount();
+
+  nsString* src = nsnull;
+  for (i = 0; i < ac; i++) {
+    const nsString& key = aNode.GetKeyAt(i);
+    if (key.EqualsIgnoreCase("src")) {
+      src = new nsString(aNode.GetValueAt(i));
+    }
+  }
+
+  // The skipped content contains the inline style data
+  const nsString& content = aNode.GetSkippedContent();
+
+  nsIURL* url = nsnull;
+  nsIUnicharInputStream* uin = nsnull;
+  if (nsnull == src) {
+    // Create a string to hold the data and wrap it up in a unicode
+    // input stream.
+    rv = NS_NewStringUnicharInputStream(&uin, new nsString(content));
+    if (NS_OK != rv) {
+      return rv;
+    }
+
+    // Use the document's url since the style data came from there
+    url = mDocumentURL;
+    NS_IF_ADDREF(url);
+  } else {
+    // src with immediate style data doesn't add up
+    // XXX what does nav do?
+    char* spec = src->ToNewCString();
+    rv = NS_NewURL(&url, nsnull, spec);
+    delete spec;
+    delete src;
+    if (NS_OK != rv) {
+      return rv;
+    }
+    PRInt32 ec;
+    nsIInputStream* iin = url->Open(&ec);
+    if (nsnull == iin) {
+      NS_RELEASE(url);
+      return (nsresult) ec;/* XXX fix url->Open */
+    }
+    rv = NS_NewConverterStream(&uin, nsnull, iin);
+    NS_RELEASE(iin);
+    if (NS_OK != rv) {
+      NS_RELEASE(url);
+      return rv;
+    }
+  }
+
+  // Now that we have a url and a unicode input stream, parse the
+  // style sheet.
+  rv = LoadStyleSheet(url, uin);
+  NS_RELEASE(uin);
+  NS_RELEASE(url);
+
+  return rv;
+}
+
+nsresult HTMLContentSink::LoadStyleSheet(nsIURL* aURL,
+                                         nsIUnicharInputStream* aUIN)
+{
+  /* XXX use repository */
+  nsICSSParser* parser;
+  nsresult rv = NS_NewCSSParser(&parser);
+  if (NS_OK == rv) {
+    PRInt32 ec;
+    if (nsnull != mStyleSheet) {
+      parser->SetStyleSheet(mStyleSheet);
+      // XXX we do probably need to trigger a style change reflow
+      // when we are finished if this is adding data to the same sheet
+    }
+    nsIStyleSheet* sheet = parser->Parse(&ec, aUIN, mDocumentURL);
+    if (nsnull != sheet) {
+      if (nsnull == mStyleSheet) {
+        // Add in the sheet the first time; if we update the sheet
+        // with new data (mutliple style tags in the same document)
+        // then the sheet will be updated by the css parser and
+        // therefore we don't need to add it to the document)
+        mDocument->AddStyleSheet(sheet);
+        mStyleSheet = sheet;
+      }
+      rv = NS_OK;
+    } else {
+      rv = NS_ERROR_OUT_OF_MEMORY;/* XXX */
+    }
+    NS_RELEASE(parser);
+  }
+  return rv;
+}
+
+
+nsresult HTMLContentSink::ProcessINPUTTag(nsIHTMLContent** aInstancePtrResult,
+                                          const nsIParserNode& aNode)
+{
+  nsAutoString tmp(aNode.GetText());
+  tmp.ToUpperCase();
+  nsIAtom* atom = NS_NewAtom(tmp);
+
+  nsresult rv = NS_ERROR_NOT_INITIALIZED;
+
+  // Find type attribute and then create the appropriate form element
+  PRInt32 ac = aNode.GetAttributeCount();
+  for (PRInt32 i = 0; i < ac; i++) {
+    const nsString& key = aNode.GetKeyAt(i);
+    if (key.EqualsIgnoreCase("type")) {
+      const nsString& val= aNode.GetValueAt(i);
+      if (val.EqualsIgnoreCase("submit")) {
+        rv = NS_NewHTMLInputSubmit(aInstancePtrResult, atom, mCurrentForm);
+      }
+      else if (val.EqualsIgnoreCase("reset")) {
+        rv = NS_NewHTMLInputReset(aInstancePtrResult, atom, mCurrentForm);
+      }
+      else if (val.EqualsIgnoreCase("button")) {
+        rv = NS_NewHTMLInputButton(aInstancePtrResult, atom, mCurrentForm);
+      }
+      else if (val.EqualsIgnoreCase("checkbox")) {
+        rv = NS_NewHTMLInputCheckbox(aInstancePtrResult, atom, mCurrentForm);
+      }
+      else if (val.EqualsIgnoreCase("file")) {
+        rv = NS_NewHTMLInputFile(aInstancePtrResult, atom, mCurrentForm);
+      }
+      else if (val.EqualsIgnoreCase("hidden")) {
+        rv = NS_NewHTMLInputHidden(aInstancePtrResult, atom, mCurrentForm);
+      }
+      else if (val.EqualsIgnoreCase("image")) {
+        rv = NS_NewHTMLInputImage(aInstancePtrResult, atom, mCurrentForm);
+      }
+      else if (val.EqualsIgnoreCase("password")) {
+        rv = NS_NewHTMLInputPassword(aInstancePtrResult, atom, mCurrentForm);
+      }
+      else if (val.EqualsIgnoreCase("radio")) {
+        rv = NS_NewHTMLInputRadio(aInstancePtrResult, atom, mCurrentForm);
+      }
+      else if (val.EqualsIgnoreCase("text")) {
+        rv = NS_NewHTMLInputText(aInstancePtrResult, atom, mCurrentForm);
+      }
+      else {
+        rv = NS_NewHTMLInputSubmit(aInstancePtrResult, atom, mCurrentForm);
+      }
+      break;
+    }
+  }
+
+  if (NS_ERROR_NOT_INITIALIZED == rv) {
+    // Create textfield when no type is specified
+    rv = NS_NewHTMLInputText(aInstancePtrResult, atom, mCurrentForm);
+  }
+
+  if ((NS_OK == rv) && (nsnull != *aInstancePtrResult)) {
+    // Add remaining attributes from the tag
+    rv = AddAttributes(aNode, *aInstancePtrResult);
+  }
+
+  NS_RELEASE(atom);
+  return rv;
+}
+
+nsresult HTMLContentSink::ProcessWBRTag(nsIHTMLContent** aInstancePtrResult,
+                                        const nsIParserNode& aNode)
+{
+  nsAutoString tmp(aNode.GetText());
+  tmp.ToUpperCase();
+  nsIAtom* atom = NS_NewAtom(tmp);
+  nsresult rv = NS_NewHTMLWordBreak(aInstancePtrResult, atom);
+  if (NS_OK == rv) {
+    rv = AddAttributes(aNode, *aInstancePtrResult);
+  }
+  NS_RELEASE(atom);
+  return rv;
+}
+
+//----------------------------------------------------------------------
+
+nsresult NS_NewHTMLContentSink(nsIHTMLContentSink** aInstancePtrResult,
+                               nsIDocument* aDoc,
+                               nsIURL* aURL)
+{
+  NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr");
+  if (nsnull == aInstancePtrResult) {
+    return NS_ERROR_NULL_POINTER;
+  }
+  HTMLContentSink* it = new HTMLContentSink();
+  if (nsnull == it) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  nsresult rv = it->Init(aDoc, aURL);
+  if (NS_OK != rv) {
+    delete it;
+    return rv;
+  }
+  return it->QueryInterface(kIHTMLContentSinkIID, (void **)aInstancePtrResult);
+}
diff --git a/mozilla/content/html/document/src/nsHTMLDocument.cpp b/mozilla/content/html/document/src/nsHTMLDocument.cpp
new file mode 100644
index 00000000000..0beeedc38f6
--- /dev/null
+++ b/mozilla/content/html/document/src/nsHTMLDocument.cpp
@@ -0,0 +1,280 @@
+/* -*- 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 "nsHTMLDocument.h"
+#include "nsIParser.h"
+#include "nsIHTMLContentSink.h"
+#include "nsHTMLParts.h"
+#include "nsIHTMLStyleSheet.h"
+#include "nsIStyleSet.h"
+#include "nsIDocumentObserver.h"
+#include "nsHTMLAtoms.h"
+#include "nsIPresShell.h"
+#include "nsIPresContext.h"
+#include "nsIImageMap.h"
+
+static NS_DEFINE_IID(kIDocumentIID, NS_IDOCUMENT_IID);
+static NS_DEFINE_IID(kIHTMLDocumentIID, NS_IHTMLDOCUMENT_IID);
+
+NS_LAYOUT nsresult
+NS_NewHTMLDocument(nsIDocument** aInstancePtrResult)
+{
+  nsHTMLDocument* doc = new nsHTMLDocument();
+  return doc->QueryInterface(kIDocumentIID, (void**) aInstancePtrResult);
+}
+
+nsHTMLDocument::nsHTMLDocument()
+  : nsDocument(),
+    mAttrStyleSheet(nsnull)
+{
+  nsHTMLAtoms::AddrefAtoms();
+}
+
+nsHTMLDocument::~nsHTMLDocument()
+{
+  NS_IF_RELEASE(mAttrStyleSheet);
+  nsHTMLAtoms::ReleaseAtoms();
+}
+
+NS_IMETHODIMP nsHTMLDocument::QueryInterface(REFNSIID aIID,
+                                             void** aInstancePtr)
+{
+  NS_PRECONDITION(nsnull != aInstancePtr, "null ptr");
+  if (nsnull == aInstancePtr) {
+    return NS_ERROR_NULL_POINTER;
+  }
+  if (aIID.Equals(kIHTMLDocumentIID)) {
+    AddRef();
+    *aInstancePtr = (void**) &mIHTMLDocument;
+    return NS_OK;
+  }
+  return nsDocument::QueryInterface(aIID, aInstancePtr);
+}
+
+void nsHTMLDocument::LoadURL(nsIURL* aURL)
+{
+  NS_IF_RELEASE(mAttrStyleSheet);
+  NS_IF_RELEASE(mDocumentURL);
+  if (nsnull != mDocumentTitle) {
+    delete mDocumentTitle;
+    mDocumentTitle = nsnull;
+  }
+
+  mDocumentURL = aURL;
+  NS_ADDREF(aURL);
+
+  nsIParser* parser;
+  nsresult rv = NS_NewHTMLParser(&parser);
+  if (NS_OK == rv) {
+    nsIHTMLContentSink* sink;
+    rv = NS_NewHTMLContentSink(&sink, this, aURL);
+    if (NS_OK == rv) {
+      if (NS_OK == NS_NewHTMLStyleSheet(&mAttrStyleSheet, aURL)) {
+        AddStyleSheet(mAttrStyleSheet); // tell the world about our new style sheet
+      }
+
+      parser->SetContentSink(sink);
+      parser->Parse(aURL);
+      NS_RELEASE(sink);
+    }
+    NS_RELEASE(parser);
+  }
+  //XXX return NS_OK;
+}
+
+static NS_DEFINE_IID(kIDocumentObserverIID, NS_IDOCUMENTOBSERVER_IID);
+
+NS_IMETHODIMP nsHTMLDocument::SetTitle(const nsString& aTitle)
+{
+  if (nsnull == mDocumentTitle) {
+    mDocumentTitle = new nsString(aTitle);
+  }
+  else {
+    *mDocumentTitle = aTitle;
+  }
+
+  // Pass on title to observers
+  PRInt32 i, n = mObservers.Count();
+  for (i = 0; i < n; i++) {
+    nsIDocumentObserver*  observer = (nsIDocumentObserver*)mObservers[i];
+    observer->SetTitle(*mDocumentTitle);
+  }
+
+  // Pass on to any interested containers
+  n = mPresShells.Count();
+  for (i = 0; i < n; i++) {
+    nsIPresShell* shell = (nsIPresShell*) mPresShells.ElementAt(i);
+    nsIPresContext* cx = shell->GetPresContext();
+    nsISupports* container;
+    if (NS_OK == cx->GetContainer(&container)) {
+      if (nsnull != container) {
+        nsIDocumentObserver* docob;
+        if (NS_OK == container->QueryInterface(kIDocumentObserverIID,
+                                               (void**) &docob)) {
+          docob->SetTitle(aTitle);
+          NS_RELEASE(docob);
+        }
+        NS_RELEASE(container);
+      }
+    }
+    NS_RELEASE(cx);
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsHTMLDocument::AddImageMap(nsIImageMap* aMap)
+{
+  NS_PRECONDITION(nsnull != aMap, "null ptr");
+  if (nsnull == aMap) {
+    return NS_ERROR_NULL_POINTER;
+  }
+  if (mImageMaps.AppendElement(aMap)) {
+    NS_ADDREF(aMap);
+    return NS_OK;
+  }
+  return NS_ERROR_OUT_OF_MEMORY;
+}
+
+NS_IMETHODIMP nsHTMLDocument::GetImageMap(const nsString& aMapName,
+                                          nsIImageMap** aResult)
+{
+  NS_PRECONDITION(nsnull != aResult, "null ptr");
+  if (nsnull == aResult) {
+    return NS_ERROR_NULL_POINTER;
+  }
+
+  nsAutoString name;
+  PRInt32 i, n = mImageMaps.Count();
+  for (i = 0; i < n; i++) {
+    nsIImageMap* map = (nsIImageMap*) mImageMaps.ElementAt(i);
+    if (NS_OK == map->GetName(name)) {
+      if (name.EqualsIgnoreCase(aMapName)) {
+        *aResult = map;
+        NS_ADDREF(map);
+        return NS_OK;
+      }
+    }
+  }
+
+  return 1;/* XXX NS_NOT_FOUND */
+}
+
+void nsHTMLDocument::AddStyleSheetToSet(nsIStyleSheet* aSheet, nsIStyleSet* aSet)
+{
+  if ((nsnull != mAttrStyleSheet) && (aSheet != mAttrStyleSheet)) {
+    aSet->InsertDocStyleSheetBefore(aSheet, mAttrStyleSheet);
+  }
+  else {
+    aSet->AppendDocStyleSheet(aSheet);
+  }
+}
+
+//----------------------------------------------------------------------
+
+// Aggregation class to give nsHTMLDocument the nsIHTMLDocument interface
+
+#define GET_OUTER() \
+ ((nsHTMLDocument*) ((char*)this - nsHTMLDocument::GetOuterOffset()))
+
+nsHTMLDocument::AggIHTMLDocument::AggIHTMLDocument() {
+  NS_INIT_REFCNT();
+}
+
+nsHTMLDocument::AggIHTMLDocument::~AggIHTMLDocument() { }
+
+NS_IMETHODIMP_(nsrefcnt) nsHTMLDocument::AggIHTMLDocument::AddRef() {
+  return GET_OUTER()->AddRef();
+}
+
+NS_IMETHODIMP_(nsrefcnt) nsHTMLDocument::AggIHTMLDocument::Release() {
+  return GET_OUTER()->Release();
+}
+
+NS_IMETHODIMP nsHTMLDocument::AggIHTMLDocument::QueryInterface(REFNSIID aIID,
+                                                               void** aInstancePtr)
+{
+  return GET_OUTER()->QueryInterface(aIID, aInstancePtr);
+}
+
+NS_IMETHODIMP nsHTMLDocument::AggIHTMLDocument::SetTitle(const nsString& aTitle) {
+  return GET_OUTER()->SetTitle(aTitle);
+}
+
+NS_IMETHODIMP nsHTMLDocument::AggIHTMLDocument::AddImageMap(nsIImageMap* aMap) {
+  return GET_OUTER()->AddImageMap(aMap);
+}
+
+NS_IMETHODIMP nsHTMLDocument::AggIHTMLDocument::GetImageMap(const nsString& aMapName,
+                                            nsIImageMap** aResult) {
+  return GET_OUTER()->GetImageMap(aMapName, aResult);
+}
+
+//----------------------------------------------------------------------
+
+#ifdef NS_DEBUG
+
+NS_LAYOUT void
+NS_HackAppendContent(nsIDocument* aDoc)
+{
+  ((nsHTMLDocument*)aDoc)->HackAppendContent();
+}
+
+#include "nsIHTMLContent.h"
+#include "nsIAtom.h"
+
+static const char* kBigParagraph =
+"This is some text. It will be word wrapped because our container will "
+"word wrap us. It will also be baseline aligned because our container "
+"will do that too. ";
+
+#define NUM_BIG_TEXTS 114
+
+nsresult nsHTMLDocument::HackAppendSimpleSpan(nsIContent* aContainer,
+                                              const char* aTag,
+                                              const char* aText)
+{
+  nsIHTMLContent* span;
+  nsIHTMLContent* text;
+  nsIAtom* atom = NS_NewAtom(aTag);
+  nsresult rv = NS_NewHTMLContainer(&span, atom);
+  if (NS_OK == rv) {
+    nsAutoString tmp;
+    for (PRIntn i = 0; i < NUM_BIG_TEXTS; i++) {
+      tmp.Append(aText);
+    }
+    rv = NS_NewHTMLText(&text, tmp.GetUnicode(), tmp.Length());
+    if (NS_OK == rv) {
+      span->AppendChild(text);
+      NS_RELEASE(text);
+    }
+    aContainer->AppendChild(span);
+    NS_RELEASE(span);
+  }
+  NS_RELEASE(atom);
+  return rv;
+}
+
+void nsHTMLDocument::HackAppendContent()
+{
+  nsIContent* body = mRootContent->ChildAt(0);
+  HackAppendSimpleSpan(body, "P", kBigParagraph);
+  NS_RELEASE(body);
+}
+#endif
+
+
diff --git a/mozilla/content/html/document/src/nsHTMLDocument.h b/mozilla/content/html/document/src/nsHTMLDocument.h
new file mode 100644
index 00000000000..2e1fc1e04d0
--- /dev/null
+++ b/mozilla/content/html/document/src/nsHTMLDocument.h
@@ -0,0 +1,76 @@
+/* -*- 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.
+ */
+#ifndef nsHTMLDocument_h___
+#define nsHTMLDocument_h___
+
+#include "nsDocument.h"
+#include "nsIHTMLDocument.h"
+
+class nsIHTMLStyleSheet;
+
+class nsHTMLDocument : public nsDocument {
+public:
+  nsHTMLDocument();
+  virtual ~nsHTMLDocument();
+
+  NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
+
+  virtual void LoadURL(nsIURL* aURL);
+
+  NS_IMETHOD SetTitle(const nsString& aTitle);
+
+  NS_IMETHOD AddImageMap(nsIImageMap* aMap);
+
+  NS_IMETHOD GetImageMap(const nsString& aMapName, nsIImageMap** aResult);
+
+  static PRInt32 GetOuterOffset() {
+    return offsetof(nsHTMLDocument,mIHTMLDocument);
+  }
+
+protected:
+  virtual void AddStyleSheetToSet(nsIStyleSheet* aSheet, nsIStyleSet* aSet);
+
+#ifdef NS_DEBUG
+public:
+  void HackAppendContent();
+
+protected:
+  nsresult HackAppendSimpleSpan(nsIContent* aContainer, const char* aTag,
+                                const char* aText);
+#endif
+
+  class AggIHTMLDocument : public nsIHTMLDocument {
+  public:
+    AggIHTMLDocument();
+    ~AggIHTMLDocument();
+
+    NS_DECL_ISUPPORTS
+
+    NS_IMETHOD SetTitle(const nsString& aTitle);
+
+    NS_IMETHOD AddImageMap(nsIImageMap* aMap);
+
+    NS_IMETHOD GetImageMap(const nsString& aMapName, nsIImageMap** aResult);
+  };
+
+  AggIHTMLDocument mIHTMLDocument;
+  nsIHTMLStyleSheet* mAttrStyleSheet;
+  nsVoidArray mImageMaps;
+};
+
+#endif /* nsHTMLDocument_h___ */
diff --git a/mozilla/content/html/document/src/nsIHTMLDocument.h b/mozilla/content/html/document/src/nsIHTMLDocument.h
new file mode 100644
index 00000000000..b6d9cd8a6b1
--- /dev/null
+++ b/mozilla/content/html/document/src/nsIHTMLDocument.h
@@ -0,0 +1,41 @@
+/* -*- 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.
+ */
+#ifndef nsIHTMLDocument_h___
+#define nsIHTMLDocument_h___
+
+#include "nsISupports.h"
+class nsIImageMap;
+class nsString;
+
+/* b2a848b0-d0a9-11d1-89b1-006008911b81 */
+#define NS_IHTMLDOCUMENT_IID \
+{0xb2a848b0, 0xd0a9, 0x11d1, {0x89, 0xb1, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81}}
+
+/**
+ * HTML document extensions to nsIDocument.
+ */
+class nsIHTMLDocument : public nsISupports {
+public:
+  NS_IMETHOD SetTitle(const nsString& aTitle) = 0;
+
+  NS_IMETHOD AddImageMap(nsIImageMap* aMap) = 0;
+
+  NS_IMETHOD GetImageMap(const nsString& aMapName, nsIImageMap** aResult) = 0;
+};
+
+#endif /* nsIHTMLDocument_h___ */
diff --git a/mozilla/content/html/style/public/nsICSSParser.h b/mozilla/content/html/style/public/nsICSSParser.h
new file mode 100644
index 00000000000..e9b21f10215
--- /dev/null
+++ b/mozilla/content/html/style/public/nsICSSParser.h
@@ -0,0 +1,56 @@
+/* -*- 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.
+ */
+#ifndef nsCSS1Parser_h___
+#define nsCSS1Parser_h___
+
+#include "nslayout.h"
+#include "nsISupports.h"
+class nsIStyleSheet;
+class nsIUnicharInputStream;
+class nsIURL;
+
+#define NS_ICSS_PARSER_IID    \
+{ 0xcc9c0610, 0x968c, 0x11d1, \
+  {0x93, 0x23, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} }
+
+// Interface to the css parser.
+class nsICSSParser : public nsISupports {
+public:
+  // Return a mask of the various css standards that this parser
+  // supports.
+  virtual PRUint32 GetInfoMask() = 0;
+
+  // Set a style sheet for the parser to fill in. The style sheet must
+  // implement the nsICSSStyleSheet interface
+  virtual nsresult SetStyleSheet(nsIStyleSheet* aSheet) = 0;
+
+  virtual nsIStyleSheet* Parse(PRInt32* aErrorCode,
+                               nsIUnicharInputStream* aInput,
+                               nsIURL* aInputURL) = 0;
+};
+
+// Values or'd in the GetInfoMask; other bits are reserved
+#define NS_CSS_GETINFO_CSS1         ((PRUint32) 0x00000001L)
+#define NS_CSS_GETINFO_CSSP         ((PRUint32) 0x00000002L)
+#define NS_CSS_GETINFO_CSS2         ((PRUint32) 0x00000004L)
+#define NS_CSS_GETINFO_CSS_FROSTING ((PRUint32) 0x00000008L)
+
+extern NS_HTML nsresult
+  NS_NewCSSParser(nsICSSParser** aInstancePtrResult);
+
+#endif /* nsCSS1Parser_h___ */
diff --git a/mozilla/content/html/style/src/nsCSSDeclaration.cpp b/mozilla/content/html/style/src/nsCSSDeclaration.cpp
new file mode 100644
index 00000000000..2f9d7ac6155
--- /dev/null
+++ b/mozilla/content/html/style/src/nsCSSDeclaration.cpp
@@ -0,0 +1,1350 @@
+/* -*- 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 "nsICSSDeclaration.h"
+#include "nsString.h"
+#include "nsCRT.h"
+#include "nsCSSProps.h"
+#include "nsCSSPropIDs.h"
+#include "nsUnitConversion.h"
+
+static NS_DEFINE_IID(kCSSFontSID, NS_CSS_FONT_SID);
+static NS_DEFINE_IID(kCSSColorSID, NS_CSS_COLOR_SID);
+static NS_DEFINE_IID(kCSSTextSID, NS_CSS_TEXT_SID);
+static NS_DEFINE_IID(kCSSMarginSID, NS_CSS_MARGIN_SID);
+static NS_DEFINE_IID(kCSSPositionSID, NS_CSS_POSITION_SID);
+static NS_DEFINE_IID(kCSSListSID, NS_CSS_LIST_SID);
+static NS_DEFINE_IID(kICSSDeclarationIID, NS_ICSS_DECLARATION_IID);
+
+
+nsCSSValue::nsCSSValue(void)
+  : mUnit(eCSSUnit_Null)
+{
+  mValue.mInt = 0;
+}
+
+nsCSSValue::nsCSSValue(PRInt32 aValue, nsCSSUnit aUnit)
+  : mUnit(aUnit)
+{
+  mValue.mInt = aValue;
+}
+
+nsCSSValue::nsCSSValue(float aValue, nsCSSUnit aUnit)
+  : mUnit(aUnit)
+{
+  mValue.mFloat = aValue;
+}
+
+nsCSSValue::nsCSSValue(const nsString& aValue)
+  : mUnit(eCSSUnit_String)
+{
+  mValue.mString = aValue.ToNewString();
+}
+
+nsCSSValue::nsCSSValue(nscolor aValue)
+  : mUnit(eCSSUnit_Color)
+{
+  mValue.mColor = aValue;
+}
+
+nsCSSValue::nsCSSValue(const nsCSSValue& aCopy)
+  : mUnit(aCopy.mUnit)
+{
+  if (eCSSUnit_String == mUnit) {
+    if (nsnull != aCopy.mValue.mString) {
+      mValue.mString = (aCopy.mValue.mString)->ToNewString();
+    }
+    else {
+      mValue.mString = nsnull;
+    }
+  }
+  else if ((eCSSUnit_Absolute <= mUnit) && (mUnit <= eCSSUnit_Enumerated)) {
+    mValue.mInt = aCopy.mValue.mInt;
+  }
+  else if (eCSSUnit_Color == mUnit){
+    mValue.mColor = aCopy.mValue.mColor;
+  }
+  else {
+    mValue.mFloat = aCopy.mValue.mFloat;
+  }
+}
+
+nsCSSValue::~nsCSSValue(void)
+{
+  Reset();
+}
+
+nsCSSValue& nsCSSValue::operator=(const nsCSSValue& aCopy)
+{
+  Reset();
+  mUnit = aCopy.mUnit;
+  if (eCSSUnit_String == mUnit) {
+    if (nsnull != aCopy.mValue.mString) {
+      mValue.mString = (aCopy.mValue.mString)->ToNewString();
+    }
+  }
+  else if ((eCSSUnit_Absolute <= mUnit) && (mUnit <= eCSSUnit_Enumerated)) {
+    mValue.mInt = aCopy.mValue.mInt;
+  }
+  else if (eCSSUnit_Color == mUnit){
+    mValue.mColor = aCopy.mValue.mColor;
+  }
+  else {
+    mValue.mFloat = aCopy.mValue.mFloat;
+  }
+  return *this;
+}
+
+PRBool nsCSSValue::operator==(const nsCSSValue& aOther) const
+{
+  if (mUnit == aOther.mUnit) {
+    if (eCSSUnit_String == mUnit) {
+      if (nsnull == mValue.mString) {
+        if (nsnull == aOther.mValue.mString) {
+          return PR_TRUE;
+        }
+      }
+      else if (nsnull != aOther.mValue.mString) {
+        return mValue.mString->Equals(*(aOther.mValue.mString));
+      }
+    }
+    else if ((eCSSUnit_Absolute <= mUnit) && (mUnit < eCSSUnit_Percent)) {
+      return PRBool(mValue.mInt == aOther.mValue.mInt);
+    }
+    else if (eCSSUnit_Color == mUnit){
+      return PRBool(mValue.mColor == aOther.mValue.mColor);
+    }
+    else {
+      return PRBool(mValue.mFloat == aOther.mValue.mFloat);
+    }
+  }
+  return PR_FALSE;
+}
+
+nscoord nsCSSValue::GetLengthTwips(void) const
+{
+  NS_ASSERTION(IsFixedLengthUnit(), "not a fixed length unit");
+
+  if (IsFixedLengthUnit()) {
+    switch (mUnit) {
+    case eCSSUnit_Inch:        
+      return (nscoord)NS_INCHES_TO_TWIPS(mValue.mFloat);
+    case eCSSUnit_Foot:        
+      return (nscoord)NS_FEET_TO_TWIPS(mValue.mFloat);
+    case eCSSUnit_Mile:        
+      return (nscoord)NS_MILES_TO_TWIPS(mValue.mFloat);
+
+    case eCSSUnit_Millimeter:
+      return (nscoord)NS_MILLIMETERS_TO_TWIPS(mValue.mFloat);
+    case eCSSUnit_Centimeter:
+      return (nscoord)NS_CENTIMETERS_TO_TWIPS(mValue.mFloat);
+    case eCSSUnit_Meter:
+      return (nscoord)NS_METERS_TO_TWIPS(mValue.mFloat);
+    case eCSSUnit_Kilometer:
+      return (nscoord)NS_KILOMETERS_TO_TWIPS(mValue.mFloat);
+
+    case eCSSUnit_Point:
+      return (nscoord)NS_POINTS_TO_TWIPS_FLOAT(mValue.mFloat);
+    case eCSSUnit_Pica:
+      return (nscoord)NS_PICAS_TO_TWIPS(mValue.mFloat);
+    case eCSSUnit_Didot:
+      return (nscoord)NS_DIDOTS_TO_TWIPS(mValue.mFloat);
+    case eCSSUnit_Cicero:
+      return (nscoord)NS_CICEROS_TO_TWIPS(mValue.mFloat);
+    }
+  }
+  return 0;
+}
+
+void nsCSSValue::Reset(void)
+{
+  if ((eCSSUnit_String == mUnit) && (nsnull != mValue.mString)) {
+    delete mValue.mString;
+  }
+  mUnit = eCSSUnit_Null;
+  mValue.mInt = 0;
+};
+
+void nsCSSValue::Set(PRInt32 aValue, nsCSSUnit aUnit)
+{
+  Reset();
+  mUnit = aUnit;
+  mValue.mInt = aValue;
+}
+
+void nsCSSValue::Set(float aValue, nsCSSUnit aUnit)
+{
+  Reset();
+  mUnit = aUnit;
+  mValue.mFloat = aValue;
+}
+
+void nsCSSValue::Set(const nsString& aValue)
+{
+  Reset();
+  mUnit = eCSSUnit_String;
+  mValue.mString = aValue.ToNewString();
+}
+
+void nsCSSValue::Set(nscolor aValue)
+{
+  Reset();
+  mUnit = eCSSUnit_Color;
+  mValue.mColor = aValue;
+}
+
+void nsCSSValue::AppendToString(nsString& aBuffer, PRInt32 aPropID) const
+{
+  if (eCSSUnit_Null == mUnit) {
+    return;
+  }
+
+  if (-1 < aPropID) {
+    aBuffer.Append(nsCSSProps::kNameTable[aPropID].name);
+    aBuffer.Append(": ");
+  }
+
+  if (eCSSUnit_String == mUnit) {
+    if (nsnull != mValue.mString) {
+      aBuffer.Append('"');
+      aBuffer.Append(*(mValue.mString));
+      aBuffer.Append('"');
+    }
+    else {
+      aBuffer.Append("null str");
+    }
+  }
+  else if ((eCSSUnit_Absolute <= mUnit) && (mUnit <= eCSSUnit_Enumerated)) {
+    aBuffer.Append(mValue.mInt, 10);
+    aBuffer.Append("[0x");
+    aBuffer.Append(mValue.mInt, 16);
+    aBuffer.Append(']');
+  }
+  else if (eCSSUnit_Color == mUnit){
+    aBuffer.Append("(0x");
+    aBuffer.Append(NS_GET_R(mValue.mColor), 16);
+    aBuffer.Append(" 0x");
+    aBuffer.Append(NS_GET_G(mValue.mColor), 16);
+    aBuffer.Append(" 0x");
+    aBuffer.Append(NS_GET_B(mValue.mColor), 16);
+    aBuffer.Append(" 0x");
+    aBuffer.Append(NS_GET_A(mValue.mColor), 16);
+    aBuffer.Append(')');
+  }
+  else if (eCSSUnit_Percent <= mUnit) {
+    aBuffer.Append(mValue.mFloat);
+  }
+
+  switch (mUnit) {
+    case eCSSUnit_Null:       break;
+    case eCSSUnit_Auto:       aBuffer.Append("auto"); break;
+    case eCSSUnit_String:     break;
+    case eCSSUnit_Absolute:   aBuffer.Append("abs");  break;
+    case eCSSUnit_Enumerated: aBuffer.Append("enum"); break;
+    case eCSSUnit_Color:      aBuffer.Append("rbga"); break;
+    case eCSSUnit_Percent:    aBuffer.Append("%");    break;
+    case eCSSUnit_Number:     aBuffer.Append("#");    break;
+    case eCSSUnit_Inch:       aBuffer.Append("in");   break;
+    case eCSSUnit_Foot:       aBuffer.Append("ft");   break;
+    case eCSSUnit_Mile:       aBuffer.Append("mi");   break;
+    case eCSSUnit_Millimeter: aBuffer.Append("mm");   break;
+    case eCSSUnit_Centimeter: aBuffer.Append("cm");   break;
+    case eCSSUnit_Meter:      aBuffer.Append("m");    break;
+    case eCSSUnit_Kilometer:  aBuffer.Append("km");   break;
+    case eCSSUnit_Point:      aBuffer.Append("pt");   break;
+    case eCSSUnit_Pica:       aBuffer.Append("pc");   break;
+    case eCSSUnit_Didot:      aBuffer.Append("dt");   break;
+    case eCSSUnit_Cicero:     aBuffer.Append("cc");   break;
+    case eCSSUnit_EM:         aBuffer.Append("em");   break;
+    case eCSSUnit_EN:         aBuffer.Append("en");   break;
+    case eCSSUnit_XHeight:    aBuffer.Append("ex");   break;
+    case eCSSUnit_CapHeight:  aBuffer.Append("cap");  break;
+    case eCSSUnit_Pixel:      aBuffer.Append("px");   break;
+  }
+  aBuffer.Append(' ');
+}
+
+void nsCSSValue::ToString(nsString& aBuffer, PRInt32 aPropID) const
+{
+  aBuffer.SetLength(0);
+  AppendToString(aBuffer, aPropID);
+}
+
+const nsID& nsCSSFont::GetID(void)
+{
+  return kCSSFontSID;
+}
+
+void nsCSSFont::List(FILE* out, PRInt32 aIndent) const
+{
+  for (PRInt32 index = aIndent; --index >= 0; ) fputs("  ", out);
+
+  nsAutoString buffer;
+
+  mFamily.AppendToString(buffer, PROP_FONT_FAMILY);
+  mStyle.AppendToString(buffer, PROP_FONT_STYLE);
+  mVariant.AppendToString(buffer, PROP_FONT_VARIANT);
+  mWeight.AppendToString(buffer, PROP_FONT_WEIGHT);
+  mSize.AppendToString(buffer, PROP_FONT_SIZE);
+  fputs(buffer, out);
+}
+
+
+const nsID& nsCSSColor::GetID(void)
+{
+  return kCSSColorSID;
+}
+
+void nsCSSColor::List(FILE* out, PRInt32 aIndent) const
+{
+  for (PRInt32 index = aIndent; --index >= 0; ) fputs("  ", out);
+
+  nsAutoString buffer;
+
+  mColor.AppendToString(buffer, PROP_COLOR);
+  mBackColor.AppendToString(buffer, PROP_BACKGROUND_COLOR);
+  mBackImage.AppendToString(buffer, PROP_BACKGROUND_IMAGE);
+  mBackRepeat.AppendToString(buffer, PROP_BACKGROUND_REPEAT);
+  mBackAttachment.AppendToString(buffer, PROP_BACKGROUND_ATTACHMENT);
+  mBackPositionX.AppendToString(buffer, PROP_BACKGROUND_X_POSITION);
+  mBackPositionY.AppendToString(buffer, PROP_BACKGROUND_Y_POSITION);
+  mBackFilter.AppendToString(buffer, PROP_BACKGROUND_FILTER);
+  fputs(buffer, out);
+}
+
+const nsID& nsCSSText::GetID(void)
+{
+  return kCSSTextSID;
+}
+
+void nsCSSText::List(FILE* out, PRInt32 aIndent) const
+{
+  for (PRInt32 index = aIndent; --index >= 0; ) fputs("  ", out);
+
+  nsAutoString buffer;
+
+  mWordSpacing.AppendToString(buffer, PROP_WORD_SPACING);
+  mLetterSpacing.AppendToString(buffer, PROP_LETTER_SPACING);
+  mDecoration.AppendToString(buffer, PROP_TEXT_DECORATION);
+  mVertAlign.AppendToString(buffer, PROP_VERTICAL_ALIGN);
+  mTransform.AppendToString(buffer, PROP_TEXT_TRANSFORM);
+  mHorzAlign.AppendToString(buffer, PROP_TEXT_ALIGN);
+  mIndent.AppendToString(buffer, PROP_TEXT_INDENT);
+  mLineHeight.AppendToString(buffer, PROP_LINE_HEIGHT);
+  mWhiteSpace.AppendToString(buffer, PROP_WHITE_SPACE);
+  fputs(buffer, out);
+}
+
+void nsCSSRect::List(FILE* out, PRInt32 aPropID, PRInt32 aIndent) const
+{
+  for (PRInt32 index = aIndent; --index >= 0; ) fputs("  ", out);
+
+  nsAutoString buffer;
+
+  if (-1 < aPropID) {
+    buffer.Append(nsCSSProps::kNameTable[aPropID].name);
+    buffer.Append(": ");
+  }
+
+  mTop.AppendToString(buffer);
+  mRight.AppendToString(buffer);
+  mBottom.AppendToString(buffer); 
+  mLeft.AppendToString(buffer);
+  fputs(buffer, out);
+}
+
+nsCSSMargin::nsCSSMargin(void)
+  : mMargin(nsnull), mPadding(nsnull), mBorder(nsnull), mColor(nsnull), mStyle(nsnull)
+{
+}
+
+nsCSSMargin::~nsCSSMargin(void)
+{
+  if (nsnull != mMargin) {
+    delete mMargin;
+  }
+  if (nsnull != mPadding) {
+    delete mPadding;
+  }
+  if (nsnull != mBorder) {
+    delete mBorder;
+  }
+  if (nsnull != mColor) {
+    delete mColor;
+  }
+  if (nsnull != mStyle) {
+    delete mStyle;
+  }
+}
+
+const nsID& nsCSSMargin::GetID(void)
+{
+  return kCSSMarginSID;
+}
+
+void nsCSSMargin::List(FILE* out, PRInt32 aIndent) const
+{
+  for (PRInt32 index = aIndent; --index >= 0; ) fputs("  ", out);
+
+  if (nsnull != mMargin) {
+    mMargin->List(out, PROP_MARGIN, aIndent);
+  }
+  if (nsnull != mPadding) {
+    mPadding->List(out, PROP_PADDING, aIndent);
+  }
+  if (nsnull != mBorder) {
+    mBorder->List(out, PROP_BORDER_WIDTH, aIndent);
+  }
+  if (nsnull != mColor) {
+    mColor->List(out, PROP_BORDER_COLOR, aIndent);
+  }
+  if (nsnull != mStyle) {
+    mStyle->List(out, PROP_BORDER_STYLE, aIndent);
+  }
+}
+
+nsCSSPosition::nsCSSPosition(void)
+  : mClip(nsnull)
+{
+}
+
+nsCSSPosition::~nsCSSPosition(void)
+{
+  if (nsnull != mClip) {
+    delete mClip;
+  }
+}
+
+const nsID& nsCSSPosition::GetID(void)
+{
+  return kCSSPositionSID;
+}
+
+void nsCSSPosition::List(FILE* out, PRInt32 aIndent) const
+{
+  for (PRInt32 index = aIndent; --index >= 0; ) fputs("  ", out);
+
+  nsAutoString buffer;
+
+  mPosition.AppendToString(buffer, PROP_POSITION);
+  mWidth.AppendToString(buffer, PROP_WIDTH);
+  mHeight.AppendToString(buffer, PROP_HEIGHT);
+  mLeft.AppendToString(buffer, PROP_LEFT);
+  mTop.AppendToString(buffer, PROP_TOP);
+  fputs(buffer, out);
+  if (nsnull != mClip) {
+    mClip->List(out, PROP_CLIP);
+  }
+  buffer.SetLength(0);
+  mOverflow.AppendToString(buffer, PROP_OVERFLOW);
+  mZIndex.AppendToString(buffer, PROP_OVERFLOW);
+  mVisibility.AppendToString(buffer, PROP_VISIBILITY);
+  mFloat.AppendToString(buffer, PROP_FLOAT);
+  mClear.AppendToString(buffer, PROP_CLEAR);
+  mDisplay.AppendToString(buffer, PROP_DISPLAY);
+  mFilter.AppendToString(buffer, PROP_FILTER);
+  fputs(buffer, out);
+}
+
+const nsID& nsCSSList::GetID(void)
+{
+  return kCSSListSID;
+}
+
+void nsCSSList::List(FILE* out, PRInt32 aIndent) const
+{
+  for (PRInt32 index = aIndent; --index >= 0; ) fputs("  ", out);
+
+  nsAutoString buffer;
+
+  mType.AppendToString(buffer, PROP_LIST_STYLE_TYPE);
+  mImage.AppendToString(buffer, PROP_LIST_STYLE_IMAGE);
+  mPosition.AppendToString(buffer, PROP_LIST_STYLE_POSITION);
+  fputs(buffer, out);
+}
+
+
+
+class CSSDeclarationImpl : public nsICSSDeclaration {
+public:
+  void* operator new(size_t size);
+
+  CSSDeclarationImpl(void);
+  ~CSSDeclarationImpl(void);
+
+  NS_DECL_ISUPPORTS
+
+  nsresult  GetData(const nsID& aSID, nsCSSStruct** aData);
+  nsresult  EnsureData(const nsID& aSID, nsCSSStruct** aData);
+
+  nsresult AddValue(const char* aProperty, const nsCSSValue& aValue);
+  nsresult AddValue(PRInt32 aProperty, const nsCSSValue& aValue);
+  nsresult GetValue(const char* aProperty, nsCSSValue& aValue);
+  nsresult GetValue(PRInt32 aProperty, nsCSSValue& aValue);
+
+  void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
+
+private:
+  CSSDeclarationImpl(const CSSDeclarationImpl& aCopy);
+  CSSDeclarationImpl& operator=(const CSSDeclarationImpl& aCopy);
+  PRBool operator==(const CSSDeclarationImpl& aCopy) const;
+
+protected:
+  nsCSSFont*      mFont;
+  nsCSSColor*     mColor;
+  nsCSSText*      mText;
+  nsCSSMargin*    mMargin;
+  nsCSSPosition*  mPosition;
+  nsCSSList*      mList;
+};
+
+void* CSSDeclarationImpl::operator new(size_t size)
+{
+  void* result = new char[size];
+
+  nsCRT::zero(result, size);
+  return result;
+}
+
+CSSDeclarationImpl::CSSDeclarationImpl(void)
+{
+  NS_INIT_REFCNT();
+}
+
+CSSDeclarationImpl::~CSSDeclarationImpl(void)
+{
+  if (nsnull != mFont) {
+    delete mFont;
+  }
+  if (nsnull != mColor) {
+    delete mColor;
+  }
+  if (nsnull != mText) {
+    delete mText;
+  }
+  if (nsnull != mMargin) {
+    delete mMargin;
+  }
+  if (nsnull != mPosition) {
+    delete mPosition;
+  }
+  if (nsnull != mList) {
+    delete mList;
+  }
+}
+
+NS_IMPL_ISUPPORTS(CSSDeclarationImpl, kICSSDeclarationIID);
+
+nsresult CSSDeclarationImpl::GetData(const nsID& aSID, nsCSSStruct** aDataPtr)
+{
+  if (nsnull == aDataPtr) {
+    return NS_ERROR_NULL_POINTER;
+  }
+
+  if (aSID.Equals(kCSSFontSID)) {
+    *aDataPtr = mFont;
+  }
+  else if (aSID.Equals(kCSSColorSID)) {
+    *aDataPtr = mColor;
+  }
+  else if (aSID.Equals(kCSSTextSID)) {
+    *aDataPtr = mText;
+  }
+  else if (aSID.Equals(kCSSMarginSID)) {
+    *aDataPtr = mMargin;
+  }
+  else if (aSID.Equals(kCSSPositionSID)) {
+    *aDataPtr = mPosition;
+  }
+  else if (aSID.Equals(kCSSListSID)) {
+    *aDataPtr = mList;
+  }
+  else {
+    return NS_NOINTERFACE;
+  }
+  return NS_OK;
+}
+
+nsresult CSSDeclarationImpl::EnsureData(const nsID& aSID, nsCSSStruct** aDataPtr)
+{
+  if (nsnull == aDataPtr) {
+    return NS_ERROR_NULL_POINTER;
+  }
+
+  if (aSID.Equals(kCSSFontSID)) {
+    if (nsnull == mFont) {
+      mFont = new nsCSSFont();
+    }
+    *aDataPtr = mFont;
+  }
+  else if (aSID.Equals(kCSSColorSID)) {
+    if (nsnull == mColor) {
+      mColor = new nsCSSColor();
+    }
+    *aDataPtr = mColor;
+  }
+  else if (aSID.Equals(kCSSTextSID)) {
+    if (nsnull == mText) {
+      mText = new nsCSSText();
+    }
+    *aDataPtr = mText;
+  }
+  else if (aSID.Equals(kCSSMarginSID)) {
+    if (nsnull == mMargin) {
+      mMargin = new nsCSSMargin();
+    }
+    *aDataPtr = mMargin;
+  }
+  else if (aSID.Equals(kCSSPositionSID)) {
+    if (nsnull == mPosition) {
+      mPosition = new nsCSSPosition();
+    }
+    *aDataPtr = mPosition;
+  }
+  else if (aSID.Equals(kCSSListSID)) {
+    if (nsnull == mList) {
+      mList = new nsCSSList();
+    }
+    *aDataPtr = mList;
+  }
+  else {
+    return NS_NOINTERFACE;
+  }
+  if (nsnull == *aDataPtr) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  return NS_OK;
+}
+
+nsresult CSSDeclarationImpl::AddValue(const char* aProperty, const nsCSSValue& aValue)
+{
+  return AddValue(nsCSSProps::LookupName(aProperty), aValue);
+}
+
+nsresult CSSDeclarationImpl::AddValue(PRInt32 aProperty, const nsCSSValue& aValue)
+{
+  nsresult result = NS_OK;
+
+  switch (aProperty) {
+    // nsCSSFont
+    case PROP_FONT_FAMILY:
+    case PROP_FONT_STYLE:
+    case PROP_FONT_VARIANT:
+    case PROP_FONT_WEIGHT:
+    case PROP_FONT_SIZE:
+      if (nsnull == mFont) {
+        mFont = new nsCSSFont();
+      }
+      if (nsnull != mFont) {
+        switch (aProperty) {
+          case PROP_FONT_FAMILY:  mFont->mFamily = aValue;   break;
+          case PROP_FONT_STYLE:   mFont->mStyle = aValue;    break;
+          case PROP_FONT_VARIANT: mFont->mVariant = aValue;  break;
+          case PROP_FONT_WEIGHT:  mFont->mWeight = aValue;   break;
+          case PROP_FONT_SIZE:    mFont->mSize = aValue;     break;
+        }
+      }
+      else {
+        result = NS_ERROR_OUT_OF_MEMORY;
+      }
+      break;
+
+    // nsCSSColor
+    case PROP_COLOR:
+    case PROP_BACKGROUND_COLOR:
+    case PROP_BACKGROUND_IMAGE:
+    case PROP_BACKGROUND_REPEAT:
+    case PROP_BACKGROUND_ATTACHMENT:
+    case PROP_BACKGROUND_X_POSITION:
+    case PROP_BACKGROUND_Y_POSITION:
+    case PROP_BACKGROUND_FILTER:
+      if (nsnull == mColor) {
+        mColor = new nsCSSColor();
+      }
+      if (nsnull != mColor) {
+        switch (aProperty) {
+          case PROP_COLOR:                  mColor->mColor = aValue;           break;
+          case PROP_BACKGROUND_COLOR:       mColor->mBackColor = aValue;       break;
+          case PROP_BACKGROUND_IMAGE:       mColor->mBackImage = aValue;       break;
+          case PROP_BACKGROUND_REPEAT:      mColor->mBackRepeat = aValue;      break;
+          case PROP_BACKGROUND_ATTACHMENT:  mColor->mBackAttachment = aValue;  break;
+          case PROP_BACKGROUND_X_POSITION:  mColor->mBackPositionX = aValue;   break;
+          case PROP_BACKGROUND_Y_POSITION:  mColor->mBackPositionY = aValue;   break;
+          case PROP_BACKGROUND_FILTER:      mColor->mBackFilter = aValue;      break;
+        }
+      }
+      else {
+        result = NS_ERROR_OUT_OF_MEMORY;
+      }
+      break;
+
+    // nsCSSText
+    case PROP_WORD_SPACING:
+    case PROP_LETTER_SPACING:
+    case PROP_TEXT_DECORATION:
+    case PROP_VERTICAL_ALIGN:
+    case PROP_TEXT_TRANSFORM:
+    case PROP_TEXT_ALIGN:
+    case PROP_TEXT_INDENT:
+    case PROP_LINE_HEIGHT:
+    case PROP_WHITE_SPACE:
+      if (nsnull == mText) {
+        mText = new nsCSSText();
+      }
+      if (nsnull != mText) {
+        switch (aProperty) {
+          case PROP_WORD_SPACING:     mText->mWordSpacing = aValue;    break;
+          case PROP_LETTER_SPACING:   mText->mLetterSpacing = aValue;  break;
+          case PROP_TEXT_DECORATION:  mText->mDecoration = aValue;     break;
+          case PROP_VERTICAL_ALIGN:   mText->mVertAlign = aValue;      break;
+          case PROP_TEXT_TRANSFORM:   mText->mTransform = aValue;      break;
+          case PROP_TEXT_ALIGN:       mText->mHorzAlign = aValue;      break;
+          case PROP_TEXT_INDENT:      mText->mIndent = aValue;         break;
+          case PROP_LINE_HEIGHT:      mText->mLineHeight = aValue;     break;
+          case PROP_WHITE_SPACE:      mText->mWhiteSpace = aValue;     break;
+        }
+      }
+      else {
+        result = NS_ERROR_OUT_OF_MEMORY;
+      }
+      break;
+
+    // nsCSSMargin
+    case PROP_MARGIN_TOP:
+    case PROP_MARGIN_RIGHT:
+    case PROP_MARGIN_BOTTOM:
+    case PROP_MARGIN_LEFT:
+      if (nsnull == mMargin) {
+        mMargin = new nsCSSMargin();
+      }
+      if (nsnull != mMargin) {
+        if (nsnull == mMargin->mMargin) {
+          mMargin->mMargin = new nsCSSRect();
+        }
+        if (nsnull != mMargin->mMargin) {
+          switch (aProperty) {
+            case PROP_MARGIN_TOP:     mMargin->mMargin->mTop = aValue;     break;
+            case PROP_MARGIN_RIGHT:   mMargin->mMargin->mRight = aValue;   break;
+            case PROP_MARGIN_BOTTOM:  mMargin->mMargin->mBottom = aValue;  break;
+            case PROP_MARGIN_LEFT:    mMargin->mMargin->mLeft = aValue;    break;
+          }
+        }
+        else {
+          result = NS_ERROR_OUT_OF_MEMORY;
+        }
+      }
+      else {
+        result = NS_ERROR_OUT_OF_MEMORY;
+      }
+      break;
+
+    case PROP_PADDING_TOP:
+    case PROP_PADDING_RIGHT:
+    case PROP_PADDING_BOTTOM:
+    case PROP_PADDING_LEFT:
+      if (nsnull == mMargin) {
+        mMargin = new nsCSSMargin();
+      }
+      if (nsnull != mMargin) {
+        if (nsnull == mMargin->mPadding) {
+          mMargin->mPadding = new nsCSSRect();
+        }
+        if (nsnull != mMargin->mPadding) {
+          switch (aProperty) {
+            case PROP_PADDING_TOP:    mMargin->mPadding->mTop = aValue;    break;
+            case PROP_PADDING_RIGHT:  mMargin->mPadding->mRight = aValue;  break;
+            case PROP_PADDING_BOTTOM: mMargin->mPadding->mBottom = aValue; break;
+            case PROP_PADDING_LEFT:   mMargin->mPadding->mLeft = aValue;   break;
+          }
+        }
+        else {
+          result = NS_ERROR_OUT_OF_MEMORY;
+        }
+      }
+      else {
+        result = NS_ERROR_OUT_OF_MEMORY;
+      }
+      break;
+
+    case PROP_BORDER_TOP_WIDTH:
+    case PROP_BORDER_RIGHT_WIDTH:
+    case PROP_BORDER_BOTTOM_WIDTH:
+    case PROP_BORDER_LEFT_WIDTH:
+      if (nsnull == mMargin) {
+        mMargin = new nsCSSMargin();
+      }
+      if (nsnull != mMargin) {
+        if (nsnull == mMargin->mBorder) {
+          mMargin->mBorder = new nsCSSRect();
+        }
+        if (nsnull != mMargin->mBorder) {
+          switch (aProperty) {
+            case PROP_BORDER_TOP_WIDTH:     mMargin->mBorder->mTop = aValue;     break;
+            case PROP_BORDER_RIGHT_WIDTH:   mMargin->mBorder->mRight = aValue;   break;
+            case PROP_BORDER_BOTTOM_WIDTH:  mMargin->mBorder->mBottom = aValue;  break;
+            case PROP_BORDER_LEFT_WIDTH:    mMargin->mBorder->mLeft = aValue;    break;
+          }
+        }
+        else {
+          result = NS_ERROR_OUT_OF_MEMORY;
+        }
+      }
+      else {
+        result = NS_ERROR_OUT_OF_MEMORY;
+      }
+      break;
+
+    case PROP_BORDER_TOP_COLOR:
+    case PROP_BORDER_RIGHT_COLOR:
+    case PROP_BORDER_BOTTOM_COLOR:
+    case PROP_BORDER_LEFT_COLOR:
+      if (nsnull == mMargin) {
+        mMargin = new nsCSSMargin();
+      }
+      if (nsnull != mMargin) {
+        if (nsnull == mMargin->mColor) {
+          mMargin->mColor = new nsCSSRect();
+        }
+        if (nsnull != mMargin->mColor) {
+          switch (aProperty) {
+            case PROP_BORDER_TOP_COLOR:     mMargin->mColor->mTop = aValue;    break;
+            case PROP_BORDER_RIGHT_COLOR:   mMargin->mColor->mRight = aValue;  break;
+            case PROP_BORDER_BOTTOM_COLOR:  mMargin->mColor->mBottom = aValue; break;
+            case PROP_BORDER_LEFT_COLOR:    mMargin->mColor->mLeft = aValue;   break;
+          }
+        }
+        else {
+          result = NS_ERROR_OUT_OF_MEMORY;
+        }
+      }
+      else {
+        result = NS_ERROR_OUT_OF_MEMORY;
+      }
+      break;
+
+    case PROP_BORDER_TOP_STYLE:
+    case PROP_BORDER_RIGHT_STYLE:
+    case PROP_BORDER_BOTTOM_STYLE:
+    case PROP_BORDER_LEFT_STYLE:
+      if (nsnull == mMargin) {
+        mMargin = new nsCSSMargin();
+      }
+      if (nsnull != mMargin) {
+        if (nsnull == mMargin->mStyle) {
+          mMargin->mStyle = new nsCSSRect();
+        }
+        if (nsnull != mMargin->mStyle) {
+          switch (aProperty) {
+            case PROP_BORDER_TOP_STYLE:     mMargin->mStyle->mTop = aValue;    break;
+            case PROP_BORDER_RIGHT_STYLE:   mMargin->mStyle->mRight = aValue;  break;
+            case PROP_BORDER_BOTTOM_STYLE:  mMargin->mStyle->mBottom = aValue; break;
+            case PROP_BORDER_LEFT_STYLE:    mMargin->mStyle->mLeft = aValue;   break;
+          }
+        }
+        else {
+          result = NS_ERROR_OUT_OF_MEMORY;
+        }
+      }
+      else {
+        result = NS_ERROR_OUT_OF_MEMORY;
+      }
+      break;
+
+    // nsCSSPosition
+    case PROP_POSITION:
+    case PROP_WIDTH:
+    case PROP_HEIGHT:
+    case PROP_LEFT:
+    case PROP_TOP:
+    case PROP_OVERFLOW:
+    case PROP_Z_INDEX:
+    case PROP_VISIBILITY:
+    case PROP_FLOAT:
+    case PROP_CLEAR:
+    case PROP_DISPLAY:
+    case PROP_FILTER:
+      if (nsnull == mPosition) {
+        mPosition = new nsCSSPosition();
+      }
+      if (nsnull != mPosition) {
+        switch (aProperty) {
+          case PROP_POSITION:   mPosition->mPosition = aValue;   break;
+          case PROP_WIDTH:      mPosition->mWidth = aValue;      break;
+          case PROP_HEIGHT:     mPosition->mHeight = aValue;     break;
+          case PROP_LEFT:       mPosition->mLeft = aValue;       break;
+          case PROP_TOP:        mPosition->mTop = aValue;        break;
+          case PROP_OVERFLOW:   mPosition->mOverflow = aValue;   break;
+          case PROP_Z_INDEX:    mPosition->mZIndex = aValue;     break;
+          case PROP_VISIBILITY: mPosition->mVisibility = aValue; break;
+          case PROP_FLOAT:      mPosition->mFloat = aValue;      break;
+          case PROP_CLEAR:      mPosition->mClear = aValue;      break;
+          case PROP_DISPLAY:    mPosition->mDisplay = aValue;    break;
+          case PROP_FILTER:     mPosition->mFilter = aValue;     break;
+        }
+      }
+      else {
+        result = NS_ERROR_OUT_OF_MEMORY;
+      }
+      break;
+
+    case PROP_CLIP_TOP:
+    case PROP_CLIP_RIGHT:
+    case PROP_CLIP_BOTTOM:
+    case PROP_CLIP_LEFT:
+      if (nsnull == mPosition) {
+        mPosition = new nsCSSPosition();
+      }
+      if (nsnull != mPosition) {
+        if (nsnull == mPosition->mClip) {
+          mPosition->mClip = new nsCSSRect();
+        }
+        if (nsnull != mPosition->mClip) {
+          switch(aProperty) {
+            case PROP_CLIP_TOP:     mPosition->mClip->mTop = aValue;     break;
+            case PROP_CLIP_RIGHT:   mPosition->mClip->mRight = aValue;   break;
+            case PROP_CLIP_BOTTOM:  mPosition->mClip->mBottom = aValue;  break;
+            case PROP_CLIP_LEFT:    mPosition->mClip->mLeft = aValue;    break;
+          }
+        }
+        else {
+          result = NS_ERROR_OUT_OF_MEMORY;
+        }
+      }
+      else {
+        result = NS_ERROR_OUT_OF_MEMORY;
+      }
+      break;
+
+      // nsCSSList
+    case PROP_LIST_STYLE_TYPE:
+    case PROP_LIST_STYLE_IMAGE:
+    case PROP_LIST_STYLE_POSITION:
+      if (nsnull == mList) {
+        mList = new nsCSSList();
+      }
+      if (nsnull != mList) {
+        switch (aProperty) {
+          case PROP_LIST_STYLE_TYPE:      mList->mType = aValue;     break;
+          case PROP_LIST_STYLE_IMAGE:     mList->mImage = aValue;    break;
+          case PROP_LIST_STYLE_POSITION:  mList->mPosition = aValue; break;
+        }
+      }
+      else {
+        result = NS_ERROR_OUT_OF_MEMORY;
+      }
+      break;
+
+    case PROP_BACKGROUND:
+    case PROP_BORDER:
+    case PROP_CLIP:
+    case PROP_FONT:
+    case PROP_LIST_STYLE:
+    case PROP_MARGIN:
+    case PROP_PADDING:
+    case PROP_BACKGROUND_POSITION:
+    case PROP_BORDER_TOP:
+    case PROP_BORDER_RIGHT:
+    case PROP_BORDER_BOTTOM:
+    case PROP_BORDER_LEFT:
+    case PROP_BORDER_COLOR:
+    case PROP_BORDER_STYLE:
+    case PROP_BORDER_WIDTH:
+      NS_ERROR("can't query for shorthand properties");
+    default:
+      result = NS_ERROR_ILLEGAL_VALUE;
+      break;
+  }
+  return result;
+}
+
+nsresult CSSDeclarationImpl::GetValue(const char* aProperty, nsCSSValue& aValue)
+{
+  return GetValue(nsCSSProps::LookupName(aProperty), aValue);
+}
+
+nsresult CSSDeclarationImpl::GetValue(PRInt32 aProperty, nsCSSValue& aValue)
+{
+  nsresult result = NS_OK;
+
+  switch (aProperty) {
+    // nsCSSFont
+    case PROP_FONT_FAMILY:
+    case PROP_FONT_STYLE:
+    case PROP_FONT_VARIANT:
+    case PROP_FONT_WEIGHT:
+    case PROP_FONT_SIZE:
+      if (nsnull != mFont) {
+        switch (aProperty) {
+          case PROP_FONT_FAMILY:  aValue = mFont->mFamily;   break;
+          case PROP_FONT_STYLE:   aValue = mFont->mStyle;    break;
+          case PROP_FONT_VARIANT: aValue = mFont->mVariant;  break;
+          case PROP_FONT_WEIGHT:  aValue = mFont->mWeight;   break;
+          case PROP_FONT_SIZE:    aValue = mFont->mSize;     break;
+        }
+      }
+      else {
+        aValue.Reset();
+      }
+      break;
+
+    // nsCSSColor
+    case PROP_COLOR:
+    case PROP_BACKGROUND_COLOR:
+    case PROP_BACKGROUND_IMAGE:
+    case PROP_BACKGROUND_REPEAT:
+    case PROP_BACKGROUND_ATTACHMENT:
+    case PROP_BACKGROUND_X_POSITION:
+    case PROP_BACKGROUND_Y_POSITION:
+    case PROP_BACKGROUND_FILTER:
+      if (nsnull != mColor) {
+        switch (aProperty) {
+          case PROP_COLOR:                  aValue = mColor->mColor;           break;
+          case PROP_BACKGROUND_COLOR:       aValue = mColor->mBackColor;       break;
+          case PROP_BACKGROUND_IMAGE:       aValue = mColor->mBackImage;       break;
+          case PROP_BACKGROUND_REPEAT:      aValue = mColor->mBackRepeat;      break;
+          case PROP_BACKGROUND_ATTACHMENT:  aValue = mColor->mBackAttachment;  break;
+          case PROP_BACKGROUND_X_POSITION:  aValue = mColor->mBackPositionX;   break;
+          case PROP_BACKGROUND_Y_POSITION:  aValue = mColor->mBackPositionY;   break;
+          case PROP_BACKGROUND_FILTER:      aValue = mColor->mBackFilter;      break;
+        }
+      }
+      else {
+        aValue.Reset();
+      }
+      break;
+
+    // nsCSSText
+    case PROP_WORD_SPACING:
+    case PROP_LETTER_SPACING:
+    case PROP_TEXT_DECORATION:
+    case PROP_VERTICAL_ALIGN:
+    case PROP_TEXT_TRANSFORM:
+    case PROP_TEXT_ALIGN:
+    case PROP_TEXT_INDENT:
+    case PROP_LINE_HEIGHT:
+    case PROP_WHITE_SPACE:
+      if (nsnull != mText) {
+        switch (aProperty) {
+          case PROP_WORD_SPACING:     aValue = mText->mWordSpacing;    break;
+          case PROP_LETTER_SPACING:   aValue = mText->mLetterSpacing;  break;
+          case PROP_TEXT_DECORATION:  aValue = mText->mDecoration;     break;
+          case PROP_VERTICAL_ALIGN:   aValue = mText->mVertAlign;      break;
+          case PROP_TEXT_TRANSFORM:   aValue = mText->mTransform;      break;
+          case PROP_TEXT_ALIGN:       aValue = mText->mHorzAlign;      break;
+          case PROP_TEXT_INDENT:      aValue = mText->mIndent;         break;
+          case PROP_LINE_HEIGHT:      aValue = mText->mLineHeight;     break;
+          case PROP_WHITE_SPACE:      aValue = mText->mWhiteSpace;     break;
+        }
+      }
+      else {
+        aValue.Reset();
+      }
+      break;
+
+    // nsCSSMargin
+    case PROP_MARGIN_TOP:
+    case PROP_MARGIN_RIGHT:
+    case PROP_MARGIN_BOTTOM:
+    case PROP_MARGIN_LEFT:
+      if ((nsnull != mMargin) && (nsnull != mMargin->mMargin)) {
+        switch (aProperty) {
+          case PROP_MARGIN_TOP:     aValue = mMargin->mMargin->mTop;     break;
+          case PROP_MARGIN_RIGHT:   aValue = mMargin->mMargin->mRight;   break;
+          case PROP_MARGIN_BOTTOM:  aValue = mMargin->mMargin->mBottom;  break;
+          case PROP_MARGIN_LEFT:    aValue = mMargin->mMargin->mLeft;    break;
+        }
+      }
+      else {
+        aValue.Reset();
+      }
+      break;
+
+    case PROP_PADDING_TOP:
+    case PROP_PADDING_RIGHT:
+    case PROP_PADDING_BOTTOM:
+    case PROP_PADDING_LEFT:
+      if ((nsnull != mMargin) && (nsnull != mMargin->mPadding)) {
+        switch (aProperty) {
+          case PROP_PADDING_TOP:    aValue = mMargin->mPadding->mTop;    break;
+          case PROP_PADDING_RIGHT:  aValue = mMargin->mPadding->mRight;  break;
+          case PROP_PADDING_BOTTOM: aValue = mMargin->mPadding->mBottom; break;
+          case PROP_PADDING_LEFT:   aValue = mMargin->mPadding->mLeft;   break;
+        }
+      }
+      else {
+        aValue.Reset();
+      }
+      break;
+
+    case PROP_BORDER_TOP_WIDTH:
+    case PROP_BORDER_RIGHT_WIDTH:
+    case PROP_BORDER_BOTTOM_WIDTH:
+    case PROP_BORDER_LEFT_WIDTH:
+      if ((nsnull != mMargin) && (nsnull != mMargin->mBorder)) {
+        switch (aProperty) {
+          case PROP_BORDER_TOP_WIDTH:     aValue = mMargin->mBorder->mTop;     break;
+          case PROP_BORDER_RIGHT_WIDTH:   aValue = mMargin->mBorder->mRight;   break;
+          case PROP_BORDER_BOTTOM_WIDTH:  aValue = mMargin->mBorder->mBottom;  break;
+          case PROP_BORDER_LEFT_WIDTH:    aValue = mMargin->mBorder->mLeft;    break;
+        }
+      }
+      else {
+        aValue.Reset();
+      }
+      break;
+
+    case PROP_BORDER_TOP_COLOR:
+    case PROP_BORDER_RIGHT_COLOR:
+    case PROP_BORDER_BOTTOM_COLOR:
+    case PROP_BORDER_LEFT_COLOR:
+      if ((nsnull != mMargin) && (nsnull != mMargin->mColor)) {
+        switch (aProperty) {
+          case PROP_BORDER_TOP_COLOR:     aValue = mMargin->mColor->mTop;    break;
+          case PROP_BORDER_RIGHT_COLOR:   aValue = mMargin->mColor->mRight;  break;
+          case PROP_BORDER_BOTTOM_COLOR:  aValue = mMargin->mColor->mBottom; break;
+          case PROP_BORDER_LEFT_COLOR:    aValue = mMargin->mColor->mLeft;   break;
+        }
+      }
+      else {
+        aValue.Reset();
+      }
+      break;
+
+    case PROP_BORDER_TOP_STYLE:
+    case PROP_BORDER_RIGHT_STYLE:
+    case PROP_BORDER_BOTTOM_STYLE:
+    case PROP_BORDER_LEFT_STYLE:
+      if ((nsnull != mMargin) && (nsnull != mMargin->mStyle)) {
+        switch (aProperty) {
+          case PROP_BORDER_TOP_STYLE:     aValue = mMargin->mStyle->mTop;    break;
+          case PROP_BORDER_RIGHT_STYLE:   aValue = mMargin->mStyle->mRight;  break;
+          case PROP_BORDER_BOTTOM_STYLE:  aValue = mMargin->mStyle->mBottom; break;
+          case PROP_BORDER_LEFT_STYLE:    aValue = mMargin->mStyle->mLeft;   break;
+        }
+      }
+      else {
+        aValue.Reset();
+      }
+      break;
+
+    // nsCSSPosition
+    case PROP_POSITION:
+    case PROP_WIDTH:
+    case PROP_HEIGHT:
+    case PROP_LEFT:
+    case PROP_TOP:
+    case PROP_OVERFLOW:
+    case PROP_Z_INDEX:
+    case PROP_VISIBILITY:
+    case PROP_FLOAT:
+    case PROP_CLEAR:
+    case PROP_DISPLAY:
+    case PROP_FILTER:
+      if (nsnull != mPosition) {
+        switch (aProperty) {
+          case PROP_POSITION:   aValue = mPosition->mPosition;   break;
+          case PROP_WIDTH:      aValue = mPosition->mWidth;      break;
+          case PROP_HEIGHT:     aValue = mPosition->mHeight;     break;
+          case PROP_LEFT:       aValue = mPosition->mLeft;       break;
+          case PROP_TOP:        aValue = mPosition->mTop;        break;
+          case PROP_OVERFLOW:   aValue = mPosition->mOverflow;   break;
+          case PROP_Z_INDEX:    aValue = mPosition->mZIndex;     break;
+          case PROP_VISIBILITY: aValue = mPosition->mVisibility; break;
+          case PROP_FLOAT:      aValue = mPosition->mFloat;      break;
+          case PROP_CLEAR:      aValue = mPosition->mClear;      break;
+          case PROP_DISPLAY:    aValue = mPosition->mDisplay;    break;
+          case PROP_FILTER:     aValue = mPosition->mFilter;     break;
+        }
+      }
+      else {
+        aValue.Reset();
+      }
+      break;
+
+    case PROP_CLIP_TOP:
+    case PROP_CLIP_RIGHT:
+    case PROP_CLIP_BOTTOM:
+    case PROP_CLIP_LEFT:
+      if ((nsnull != mPosition) && (nsnull != mPosition->mClip)) {
+        switch(aProperty) {
+          case PROP_CLIP_TOP:     aValue = mPosition->mClip->mTop;     break;
+          case PROP_CLIP_RIGHT:   aValue = mPosition->mClip->mRight;   break;
+          case PROP_CLIP_BOTTOM:  aValue = mPosition->mClip->mBottom;  break;
+          case PROP_CLIP_LEFT:    aValue = mPosition->mClip->mLeft;    break;
+        }
+      }
+      else {
+        aValue.Reset();
+      }
+      break;
+
+      // nsCSSList
+    case PROP_LIST_STYLE_TYPE:
+    case PROP_LIST_STYLE_IMAGE:
+    case PROP_LIST_STYLE_POSITION:
+      if (nsnull != mList) {
+        switch (aProperty) {
+          case PROP_LIST_STYLE_TYPE:      aValue = mList->mType;     break;
+          case PROP_LIST_STYLE_IMAGE:     aValue = mList->mImage;    break;
+          case PROP_LIST_STYLE_POSITION:  aValue = mList->mPosition; break;
+        }
+      }
+      else {
+        aValue.Reset();
+      }
+      break;
+
+    case PROP_BACKGROUND:
+    case PROP_BORDER:
+    case PROP_CLIP:
+    case PROP_FONT:
+    case PROP_LIST_STYLE:
+    case PROP_MARGIN:
+    case PROP_PADDING:
+    case PROP_BACKGROUND_POSITION:
+    case PROP_BORDER_TOP:
+    case PROP_BORDER_RIGHT:
+    case PROP_BORDER_BOTTOM:
+    case PROP_BORDER_LEFT:
+    case PROP_BORDER_COLOR:
+    case PROP_BORDER_STYLE:
+    case PROP_BORDER_WIDTH:
+      NS_ERROR("can't query for shorthand properties");
+    default:
+      result = NS_ERROR_ILLEGAL_VALUE;
+      break;
+  }
+  return result;
+}
+
+void CSSDeclarationImpl::List(FILE* out, PRInt32 aIndent) const
+{
+  for (PRInt32 index = aIndent; --index >= 0; ) fputs("  ", out);
+
+  fputs("{ ", out);
+
+  if (nsnull != mFont) {
+    mFont->List(out);
+  }
+  if (nsnull != mColor) {
+    mColor->List(out);
+  }
+  if (nsnull != mText) {
+    mText->List(out);
+  }
+  if (nsnull != mMargin) {
+    mMargin->List(out);
+  }
+  if (nsnull != mPosition) {
+    mPosition->List(out);
+  }
+  if (nsnull != mList) {
+    mList->List(out);
+  }
+
+  fputs("}", out);
+}
+
+NS_HTML nsresult
+  NS_NewCSSDeclaration(nsICSSDeclaration** aInstancePtrResult)
+{
+  if (aInstancePtrResult == nsnull) {
+    return NS_ERROR_NULL_POINTER;
+  }
+
+  CSSDeclarationImpl  *it = new CSSDeclarationImpl();
+
+  if (nsnull == it) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  return it->QueryInterface(kICSSDeclarationIID, (void **) aInstancePtrResult);
+}
+
+
+/*
+font 
+===========
+
+'font-family', string (list)
+'font-style', enum
+'font-variant' enum (ie: small caps)
+'font-weight' enum
+'font-size' abs, pct, enum, +-1
+
+
+color/background
+=============
+
+color: color
+background-color: color
+background-image: url(string)
+background-repeat: enum 
+background-attachment: enum
+background-position-x -y: abs, pct, enum (left/top center right/bottom (pct?))
+
+
+
+text
+=======
+word-spacing: abs, "normal"
+letter-spacing: abs, "normal"
+text-decoration: enum
+vertical-align: enum, pct
+text-transform: enum
+text-align: enum
+text-indent: abs, pct
+line-height: "normal", abs, pct, number-factor
+white-space: enum
+
+margin
+=======
+margin-top -right -bottom -left: "auto", abs, pct
+padding-top -right -bottom -left: abs, pct
+border-top -right -bottom -left-width: enum, abs
+border-top -right -bottom -left-color: color
+border-top -right -bottom -left-style: enum
+
+size
+=======
+position: enum
+width: abs, pct, "auto"
+height: abs, pct, "auto"
+left: abs, pct, "auto"
+top: abs, pct, "auto"
+clip: shape, "auto" (shape: rect - abs, auto)
+overflow: enum
+z-index: int, auto
+visibity: enum
+
+float: enum
+clear: enum
+
+display: enum
+
+filter: string
+
+list
+========
+list-style-type: enum
+list-style-image: url, "none"
+list-style-position: enum (bool? in/out)
+
+*/
+
+
+
diff --git a/mozilla/content/html/style/src/nsCSSKeywords.h b/mozilla/content/html/style/src/nsCSSKeywords.h
new file mode 100644
index 00000000000..1db3cbe5ee3
--- /dev/null
+++ b/mozilla/content/html/style/src/nsCSSKeywords.h
@@ -0,0 +1,40 @@
+/* -*- 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.
+ */
+#ifndef nsCSSKeywords_h___
+#define nsCSSKeywords_h___
+
+#include "nslayout.h"
+#include "nsCSSKeywordIDs.h"
+
+class NS_LAYOUT nsCSSKeywords {
+public:
+  // Given a null terminated string of 7 bit characters, return the
+  // tag id (see nsHTMLTagIDs.h) for the tag or -1 if the tag is not
+  // known. The lookup function uses a perfect hash.
+  static PRInt32 LookupName(const char* str);
+
+  struct NameTableEntry {
+    const char* name;
+    PRInt32 id;
+  };
+
+  // A table whose index is the tag id (from LookupName)
+  static const NameTableEntry kNameTable[];
+};
+
+#endif /* nsCSSKeywords_h___ */
diff --git a/mozilla/content/html/style/src/nsCSSLayout.cpp b/mozilla/content/html/style/src/nsCSSLayout.cpp
new file mode 100644
index 00000000000..b21ce611ba6
--- /dev/null
+++ b/mozilla/content/html/style/src/nsCSSLayout.cpp
@@ -0,0 +1,229 @@
+/* -*- 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 "nsCSSLayout.h"
+#include "nsIStyleContext.h"
+#include "nsStyleConsts.h"
+#include "nsIContent.h"
+#include "nsIFrame.h"
+#include "nsIFontMetrics.h"
+#include "nsIPresContext.h"
+#include "nsRect.h"
+
+static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID);
+
+// XXX what about ebina's center vs. ncsa-center?
+/*
+ * Notes: It's a known fact that this doesn't do what ebina's layout
+ * engine does because his code did vertical alignment on the
+ * fly. Hopefully that's ok because his code generated surprising
+ * results in a number of unusual cases.
+ */
+nscoord nsCSSLayout::VerticallyAlignChildren(nsIPresContext* aCX,
+                                             nsIFrame* aContainer,
+                                             nsStyleFont* aContainerFont,
+                                             nscoord aY0,
+                                             nsIFrame* aFirstChild,
+                                             PRIntn aChildCount,
+                                             nscoord* aAscents,
+                                             nscoord aMaxAscent)
+{
+  // Determine minimum and maximum y values for the line and
+  // perform alignment of all children except those requesting bottom
+  // alignment. The second pass will align bottom children (if any)
+  nsIFontMetrics* fm = aCX->GetMetricsFor(aContainerFont->mFont);
+  nsIFrame* kid = aFirstChild;
+  nsRect kidRect;
+  nscoord minY = aY0;
+  nscoord maxY = aY0;
+  PRIntn bottomAlignKids = 0;
+  PRIntn kidCount = aChildCount;
+  while (--kidCount >= 0) {
+    nscoord kidAscent = *aAscents++;
+    nsIStyleContext* kidSC = kid->GetStyleContext(aCX);
+    nsIContent* kidContent = kid->GetContent();
+    nsStyleMolecule* kidMol =
+      (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID);
+    PRIntn verticalAlign = kidMol->verticalAlign;
+    float verticalAlignPct = kidMol->verticalAlignPct;
+    NS_RELEASE(kidSC);
+    NS_RELEASE(kidContent);
+
+    kid->GetRect(kidRect);
+
+    // Vertically align the child
+    nscoord kidYTop = 0;
+    switch (verticalAlign) {
+    default:
+    case NS_STYLE_VERTICAL_ALIGN_BASELINE:
+      // Align the kid's baseline at the max baseline
+      kidYTop = aMaxAscent - kidAscent;
+      break;
+
+    case NS_STYLE_VERTICAL_ALIGN_TOP:
+      // Align the top of the kid with the top of the line box
+      break;
+
+    case NS_STYLE_VERTICAL_ALIGN_SUB:
+      // Move baseline by 1/2 the ascent of the child.
+      // NOTE: CSSx doesn't seem to specify what subscripting does
+      // so we are using ebina's logic
+      kidYTop = aMaxAscent + (kidAscent/2) - kidAscent;
+      break;
+
+    case NS_STYLE_VERTICAL_ALIGN_SUPER:
+      // Move baseline by 1/2 the ascent of the child
+      // NOTE: CSSx doesn't seem to specify what superscripting does
+      // so we are using ebina's logic
+      kidYTop = aMaxAscent - (kidAscent/2) - kidAscent;
+      break;
+
+    case NS_STYLE_VERTICAL_ALIGN_BOTTOM:
+      bottomAlignKids++;
+      break;
+
+    case NS_STYLE_VERTICAL_ALIGN_MIDDLE:
+      kidYTop = aMaxAscent - (fm->GetHeight(/*'x'XXX */) / 2) - kidRect.height/2;
+      break;
+
+    case NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM:
+      kidYTop = aMaxAscent + fm->GetMaxDescent() - kidRect.height;
+      break;
+
+    case NS_STYLE_VERTICAL_ALIGN_TEXT_TOP:
+      kidYTop = aMaxAscent - fm->GetMaxAscent();
+      break;
+
+    case NS_STYLE_VERTICAL_ALIGN_LENGTH:
+      // XXX css2 hasn't yet specified what this means!
+      break;
+
+    case NS_STYLE_VERTICAL_ALIGN_PCT:
+      // XXX need kidMol->lineHeight in translated to a value form...
+      break;
+    }
+
+    // Place kid and update min and max Y values
+    nscoord y = aY0 + kidYTop;
+    if (y < minY) minY = y;
+    kid->MoveTo(kidRect.x, y);
+    y += kidRect.height;
+    if (y > maxY) maxY = y;
+
+    kid = kid->GetNextSibling();
+  }
+
+  nscoord lineHeight = maxY - minY;
+
+  if (0 != bottomAlignKids) {
+    // Position all of the bottom aligned children
+    kidCount = aChildCount;
+    kid = aFirstChild;
+    while (--kidCount >= 0) {
+      // Get kid's vertical align style data
+      nsIStyleContext* kidSC = kid->GetStyleContext(aCX);
+      nsIContent* kidContent = kid->GetContent();
+      nsStyleMolecule* kidMol =
+        (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID);
+      PRIntn verticalAlign = kidMol->verticalAlign;
+      NS_RELEASE(kidSC);
+      NS_RELEASE(kidContent);
+
+      // Vertically align the child
+      if (verticalAlign == NS_STYLE_VERTICAL_ALIGN_BOTTOM) {
+        // Place kid along the bottom
+        kid->GetRect(kidRect);
+        kid->MoveTo(kidRect.x, aY0 + lineHeight - kidRect.height);
+        if (--bottomAlignKids == 0) {
+          // Stop on lost bottom aligned kid
+          break;
+        }
+      }
+
+      kid = kid->GetNextSibling();
+    }
+  }
+
+  NS_RELEASE(fm);
+  return lineHeight;
+}
+
+/**
+ * Horizontally place the children in the container frame.
+ */
+void nsCSSLayout::HorizontallyPlaceChildren(nsIPresContext* aCX,
+                                            nsIFrame* aContainer,
+                                            nsStyleMolecule* aContainerStyle,
+                                            nsIFrame* aFirstChild,
+                                            PRInt32 aChildCount,
+                                            nscoord aLineWidth,
+                                            nscoord aMaxWidth)
+{
+  PRIntn textAlign = aContainerStyle->textAlign;
+
+  nscoord dx = 0;
+  switch (textAlign) {
+  case NS_STYLE_TEXT_ALIGN_LEFT:
+  case NS_STYLE_TEXT_ALIGN_JUSTIFY:
+    // Default layout has everything aligned left
+    return;
+
+  case NS_STYLE_TEXT_ALIGN_RIGHT:
+    dx = aMaxWidth - aLineWidth;
+    break;
+
+  case NS_STYLE_TEXT_ALIGN_CENTER:
+    dx = (aMaxWidth - aLineWidth) / 2;
+    break;
+  }
+
+  // Position children
+  nsPoint origin;
+  nsIFrame* kid = aFirstChild;
+  while (--aChildCount >= 0) {
+    kid->GetOrigin(origin);
+    kid->MoveTo(origin.x + dx, origin.y);
+    kid = kid->GetNextSibling();
+  }
+}
+
+/**
+ * Apply css relative positioning to any child that requires it.
+ */
+void nsCSSLayout::RelativePositionChildren(nsIPresContext* aCX,
+                                           nsIFrame* aContainer,
+                                           nsStyleMolecule* aContainerStyle,
+                                           nsIFrame* aFirstChild,
+                                           PRInt32 aChildCount)
+{
+  nsPoint origin;
+  nsIFrame* kid = aFirstChild;
+  while (--aChildCount >= 0) {
+    nsIContent* kidContent = kid->GetContent();
+    nsIStyleContext* kidSC = kid->GetStyleContext(aCX);
+    nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID);
+    if (NS_STYLE_POSITION_RELATIVE == kidMol->positionFlags) {
+      kid->GetOrigin(origin);
+      nscoord dx = kidMol->left;
+      nscoord dy = kidMol->top;
+      kid->MoveTo(origin.x + dx, origin.y + dy);
+    }
+    NS_RELEASE(kidContent);
+    NS_RELEASE(kidSC);
+    kid = kid->GetNextSibling();
+  }
+}
diff --git a/mozilla/content/html/style/src/nsCSSParser.cpp b/mozilla/content/html/style/src/nsCSSParser.cpp
new file mode 100644
index 00000000000..79220097b2c
--- /dev/null
+++ b/mozilla/content/html/style/src/nsCSSParser.cpp
@@ -0,0 +1,2186 @@
+/* -*- 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 "nsICSSParser.h"
+#include "nsCSSProps.h"
+#include "nsCSSKeywords.h"
+#include "nsCSSScanner.h"
+#include "nsICSSStyleRule.h"
+#include "nsIUnicharInputStream.h"
+#include "nsIStyleSet.h"
+#include "nsICSSStyleSheet.h"
+#include "nsICSSDeclaration.h"
+#include "nsStyleConsts.h"
+#include "nsIURL.h"
+#include "nsString.h"
+#include "nsIAtom.h"
+#include "nsVoidArray.h"
+#include "nsColor.h"
+
+static NS_DEFINE_IID(kICSSParserIID, NS_ICSS_PARSER_IID);
+static NS_DEFINE_IID(kICSSStyleSheetIID, NS_ICSS_STYLE_SHEET_IID);
+static NS_DEFINE_IID(kIStyleSheetIID, NS_ISTYLE_SHEET_IID);
+
+// XXX url's spec'd in a style sheet are relative to the style sheet
+// (this includes things like background-image!).
+// XXX cell-padding, spacing, etc.???
+
+struct Selector {
+  nsString mTag;     // weight 1
+  nsString mID;      // weight 100
+  nsString mClass;   // weight 10
+  nsString mPseudo;  // weight 10 (== class)
+  PRUint32 mMask;    // which fields have values
+
+  Selector();
+  ~Selector();
+
+  PRInt32 Weight() const;
+#ifdef NS_DEBUG
+  void Dump() const;
+#endif
+};
+
+#define SELECTOR_TAG 0x1
+#define SELECTOR_ID 0x2
+#define SELECTOR_CLASS 0x4
+#define SELECTOR_PSEUDO 0x8
+
+#define SELECTOR_WEIGHT_BASE 10
+
+Selector::Selector()
+{
+  mMask = 0;
+}
+
+Selector::~Selector()
+{
+}
+
+PRInt32 Selector::Weight() const
+{
+  return (((0 != (SELECTOR_TAG & mMask)) ? 1 : 0) + 
+          ((0 != (SELECTOR_ID & mMask)) ? (SELECTOR_WEIGHT_BASE * SELECTOR_WEIGHT_BASE) : 0) + 
+          ((0 != ((SELECTOR_CLASS | SELECTOR_PSEUDO) & mMask)) ? SELECTOR_WEIGHT_BASE : 0));
+}
+
+#ifdef NS_DEBUG
+void Selector::Dump() const
+{
+  PRBool needSpace = PR_FALSE;
+  if (mTag.Length() > 0) {
+    fputs(mTag, stdout);
+    needSpace = PR_TRUE;
+  }
+  if (mID.Length() > 0) {
+    if (needSpace) fputs(" ", stdout);
+    fputs("#", stdout);
+    fputs(mID, stdout);
+    needSpace = PR_TRUE;
+  }
+  if (mClass.Length() > 0) {
+    if (needSpace) fputs(" ", stdout);
+    fputs(".", stdout);
+    fputs(mClass, stdout);
+    needSpace = PR_TRUE;
+  }
+  if (mPseudo.Length() > 0) {
+    if (needSpace) fputs(" ", stdout);
+    fputs(":", stdout);
+    fputs(mPseudo, stdout);
+    needSpace = PR_TRUE;
+  }
+}
+#endif
+
+// e.g. "P B, H1 B { ... }" has a selector list with two elements,
+// each of which has two selectors.
+struct SelectorList {
+  SelectorList* mNext;
+  nsVoidArray mSelectors;
+
+  SelectorList();
+
+  void Destroy();
+
+  void AddSelector(Selector* aSelector) {
+    mSelectors.AppendElement(aSelector);
+  }
+
+#ifdef NS_DEBUG
+  void Dump();
+#endif
+
+private:
+  ~SelectorList();
+};
+
+SelectorList::SelectorList()
+{
+  mNext = nsnull;
+}
+
+SelectorList::~SelectorList()
+{
+  PRInt32 n = mSelectors.Count();
+  for (PRInt32 i = 0; i < n; i++) {
+    Selector* sel = (Selector*) mSelectors.ElementAt(i);
+    delete sel;
+  }
+}
+
+void SelectorList::Destroy()
+{
+  SelectorList* list = this;
+  while (nsnull != list) {
+    SelectorList* next = list->mNext;
+    delete list;
+    list = next;
+  }
+}
+
+#ifdef NS_DEBUG
+void SelectorList::Dump()
+{
+  PRInt32 n = mSelectors.Count();
+  for (PRInt32 i = 0; i < n; i++) {
+    Selector* sel = (Selector*) mSelectors.ElementAt(i);
+    sel->Dump();
+    fputs(" ", stdout);
+  }
+  if (mNext) {
+    fputs(", ", stdout);
+    mNext->Dump();
+  }
+}
+#endif
+
+//----------------------------------------------------------------------
+
+// Your basic top-down recursive descent style parser
+class CSSParserImpl : public nsICSSParser {
+public:
+  CSSParserImpl();
+  CSSParserImpl(nsICSSStyleSheet* aSheet);
+  ~CSSParserImpl();
+
+  NS_DECL_ISUPPORTS
+
+  virtual PRUint32 GetInfoMask();
+
+  virtual nsresult SetStyleSheet(nsIStyleSheet* aSheet);
+
+  virtual nsIStyleSheet* Parse(PRInt32* aErrorCode,
+                               nsIUnicharInputStream* aInput,
+                               nsIURL* aInputURL);
+
+protected:
+  PRBool GetToken(PRInt32* aErrorCode, PRBool aSkipWS);
+  void UngetToken();
+
+  PRBool ExpectSymbol(PRInt32* aErrorCode, char aSymbol, PRBool aSkipWS);
+  nsString* NextIdent(PRInt32* aErrorCode);
+  void SkipUntil(PRInt32* aErrorCode, PRUnichar aStopSymbol);
+  void SkipRuleSet(PRInt32* aErrorCode);
+  void SkipDeclaration(PRInt32* aErrorCode);
+
+  PRBool ParseRuleSet(PRInt32* aErrorCode);
+  PRBool ParseAtRule(PRInt32* aErrorCode);
+  PRBool ParseImportRule(PRInt32* aErrorCode);
+
+  PRBool ParseSelectorGroup(PRInt32* aErrorCode, SelectorList* aListHead);
+  PRBool ParseSelectorList(PRInt32* aErrorCode, SelectorList* aListHead);
+  PRBool ParseSelector(PRInt32* aErrorCode, Selector* aSelectorResult);
+  nsICSSDeclaration* ParseDeclarationBlock(PRInt32* aErrorCode);
+  PRBool ParseDeclaration(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration);
+  PRBool ParseProperty(PRInt32* aErrorCode, const char* aName,
+                       nsICSSDeclaration* aDeclaration);
+  PRBool ParseProperty(PRInt32* aErrorCode, const char* aName,
+                       nsICSSDeclaration* aDeclaration, PRInt32 aID);
+
+  // Property specific parsing routines
+  PRBool ParseBackground(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration);
+  PRBool ParseBackgroundFilter(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration,
+                               const char* aName);
+  PRBool ParseForegroundFilter(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration,
+                               const char* aName);
+  PRBool ParseBackgroundPosition(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration,
+                                 const char* aName);
+  PRBool ParseBorder(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration);
+  PRBool ParseBorderColor(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration);
+  PRBool ParseBorderSide(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration,
+                         const char* aNames[], PRInt32 aWhichSide);
+  PRBool ParseBorderStyle(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration);
+  PRBool ParseBorderWidth(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration);
+  PRBool ParseClip(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration);
+  PRBool ParseFont(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration,
+                   const char* aName);
+  PRBool ParseFontFamily(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration,
+                         const char* aName);
+  PRBool ParseFontWeight(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration,
+                         const char* aName);
+  PRBool ParseListStyle(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration);
+  PRBool ParseMargin(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration);
+  PRBool ParsePadding(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration);
+  PRBool ParseTextDecoration(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration,
+                             const char* aName);
+
+  // Reused utility parsing routines
+  PRBool ParseBoxProperties(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration,
+                            const char* aNames[]);
+  PRInt32 ParseChoice(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration,
+                      const char* aNames[], PRInt32 aNumNames);
+  PRBool ParseColor(PRInt32* aErrorCode, nscolor* aColorResult);
+  PRBool ParseColorComponent(PRInt32* aErrorCode, PRUint8* aComponent,
+                             char aStop);
+  PRBool ParseEnum(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration,
+                   const char* aName, PRInt32* aTable);
+  PRInt32 SearchKeywordTable(PRInt32 aID, PRInt32 aTable[]);
+  PRBool ParseVariant(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration,
+                      const char* aName, PRInt32 aVariant,
+                      PRInt32* aTable);
+  PRBool TranslateLength(nsICSSDeclaration* aDeclaration, const char* aName,
+                         float aNumber, const nsString& aDimension);
+
+  void ProcessImport(const nsString& aURLSpec);
+
+  // Current token. The value is valid after calling GetToken
+  nsCSSToken mToken;
+
+  // After an UngetToken is done this flag is true. The next call to
+  // GetToken clears the flag.
+  PRBool mHavePushBack;
+
+  nsCSSScanner* mScanner;
+  nsIURL* mURL;
+  nsICSSStyleSheet* mSheet;
+
+  PRBool mInHead;
+};
+
+NS_HTML nsresult
+NS_NewCSSParser(nsICSSParser** aInstancePtrResult)
+{
+  CSSParserImpl *it = new CSSParserImpl();
+
+  if (it == nsnull) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  return it->QueryInterface(kICSSParserIID, (void **) aInstancePtrResult);
+}
+
+CSSParserImpl::CSSParserImpl()
+{
+  NS_INIT_REFCNT();
+  mScanner = nsnull;
+  mSheet = nsnull;
+  mHavePushBack = PR_FALSE;
+}
+
+CSSParserImpl::CSSParserImpl(nsICSSStyleSheet* aSheet)
+{
+  NS_INIT_REFCNT();
+  mScanner = nsnull;
+  mSheet = aSheet; aSheet->AddRef();
+  mHavePushBack = PR_FALSE;
+}
+
+NS_IMPL_ISUPPORTS(CSSParserImpl,kICSSParserIID)
+
+CSSParserImpl::~CSSParserImpl()
+{
+  NS_IF_RELEASE(mSheet);
+}
+
+PRUint32 CSSParserImpl::GetInfoMask()
+{
+  return NS_CSS_GETINFO_CSS1 | NS_CSS_GETINFO_CSSP;
+}
+
+nsresult CSSParserImpl::SetStyleSheet(nsIStyleSheet* aSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null ptr");
+  if (nsnull == aSheet) {
+    return NS_ERROR_NULL_POINTER;
+  }
+
+  // Make sure the sheet supports the correct interface!
+  static NS_DEFINE_IID(kICSSStyleSheetIID, NS_ICSS_STYLE_SHEET_IID);
+  nsICSSStyleSheet* cssSheet;
+  nsresult rv = aSheet->QueryInterface(kICSSStyleSheetIID, (void**)&cssSheet);
+  if (NS_OK != rv) {
+    return rv;
+  }
+
+  // Switch to using the new sheet
+  NS_IF_RELEASE(mSheet);
+  mSheet = cssSheet;
+
+  return NS_OK;
+}
+
+nsIStyleSheet* CSSParserImpl::Parse(PRInt32* aErrorCode,
+                                    nsIUnicharInputStream* aInput,
+                                    nsIURL* aInputURL)
+{
+  if (nsnull == mSheet) {
+    NS_NewCSSStyleSheet(&mSheet, aInputURL);
+  }
+
+  mScanner = new nsCSSScanner();
+  mScanner->Init(aInput);
+  mURL = aInputURL;
+  if (nsnull != aInputURL) {
+    aInputURL->AddRef();
+  }
+  mInHead = PR_TRUE;
+  nsCSSToken* tk = &mToken;
+  for (;;) {
+    // Get next non-whitespace token
+    if (!GetToken(aErrorCode, PR_TRUE)) {
+      break;
+    }
+    if (eCSSToken_AtKeyword == tk->mType) {
+      ParseAtRule(aErrorCode);
+      continue;
+    } else if (eCSSToken_Symbol == tk->mType) {
+      // Discard dangling semicolons. This is not part of the CSS1
+      // forward compatible parsing spec, but it makes alot of sense.
+      if (';' == tk->mSymbol) {
+        continue;
+      }
+    }
+    mInHead = PR_FALSE;
+    UngetToken();
+    ParseRuleSet(aErrorCode);
+  }
+  delete mScanner;
+  mScanner = nsnull;
+  NS_IF_RELEASE(mURL);
+
+  nsIStyleSheet* rv = nsnull;
+  mSheet->QueryInterface(kIStyleSheetIID, (void**)&rv);
+  return rv;
+}
+
+//----------------------------------------------------------------------
+
+PRBool CSSParserImpl::GetToken(PRInt32* aErrorCode, PRBool aSkipWS)
+{
+  for (;;) {
+    if (!mHavePushBack) {
+      if (!mScanner->Next(aErrorCode, &mToken)) {
+        break;
+      }
+    }
+    mHavePushBack = PR_FALSE;
+    if (aSkipWS && (eCSSToken_WhiteSpace == mToken.mType)) {
+      continue;
+    }
+    return PR_TRUE;
+  }
+  return PR_FALSE;
+}
+
+void CSSParserImpl::UngetToken()
+{
+  NS_PRECONDITION(mHavePushBack == PR_FALSE, "double pushback");
+  mHavePushBack = PR_TRUE;
+}
+
+PRBool CSSParserImpl::ExpectSymbol(PRInt32* aErrorCode,
+                                   char aSymbol,
+                                   PRBool aSkipWS)
+{
+  if (!GetToken(aErrorCode, aSkipWS)) {
+    return PR_FALSE;
+  }
+  nsCSSToken* tk = &mToken;
+  if ((eCSSToken_Symbol == tk->mType) && (aSymbol == tk->mSymbol)) {
+    return PR_TRUE;
+  }
+  UngetToken();
+  return PR_FALSE;
+}
+
+nsString* CSSParserImpl::NextIdent(PRInt32* aErrorCode)
+{
+  if (!GetToken(aErrorCode, PR_TRUE)) {
+    return nsnull;
+  }
+  if (eCSSToken_Ident != mToken.mType) {
+    UngetToken();
+    return nsnull;
+  }
+  return &mToken.mIdent;
+}
+
+// XXX @media type {, types } '{' rules '}'
+// XXX @font-face
+// XXX @page { :left | :right } '{' declarations '}'
+PRBool CSSParserImpl::ParseAtRule(PRInt32* aErrorCode)
+{
+  nsCSSToken* tk = &mToken;
+  if (mInHead && tk->mIdent.EqualsIgnoreCase("import")) {
+    ParseImportRule(aErrorCode);
+    return PR_TRUE;
+  }
+
+  // Skip over unsupported at rule
+  for (;;) {
+    if (!GetToken(aErrorCode, PR_TRUE)) {
+      return PR_FALSE;
+    }
+    if (eCSSToken_Symbol == tk->mType) {
+      PRUnichar symbol = tk->mSymbol;
+      if (symbol == ';') {
+        break;
+      }
+      if (symbol == '{') {
+        SkipUntil(aErrorCode, '}');
+        break;
+      } else if (symbol == '(') {
+        SkipUntil(aErrorCode, ')');
+      } else if (symbol == '[') {
+        SkipUntil(aErrorCode, ']');
+      }
+    }
+  }
+  mInHead = PR_FALSE;
+  return PR_TRUE;
+}
+
+// Parse a CSS1 import rule: "@import STRING | URL"
+PRBool CSSParserImpl::ParseImportRule(PRInt32* aErrorCode)
+{
+  nsCSSToken* tk = &mToken;
+  if (!GetToken(aErrorCode, PR_TRUE)) {
+    return PR_FALSE;
+  }
+  if ((eCSSToken_String == tk->mType) || (eCSSToken_URL == tk->mType)) {
+    if (ExpectSymbol(aErrorCode, ';', PR_TRUE)) {
+      ProcessImport(tk->mIdent);
+      return PR_TRUE;
+    }
+    if ((eCSSToken_Symbol != tk->mType) || (';' != tk->mSymbol)) {
+      SkipUntil(aErrorCode, ';');
+    }
+  }
+  mInHead = PR_FALSE;
+  return PR_TRUE;
+}
+
+void CSSParserImpl::ProcessImport(const nsString& aURLSpec)
+{
+  // XXX probably need a way to encode unicode junk for the part of
+  // the url that follows a "?"
+  char* cp = aURLSpec.ToNewCString();
+  nsIURL* url;
+  nsresult rv = NS_NewURL(&url, mURL, cp);
+  delete cp;
+  if (NS_OK != rv) {
+    // import url is bad
+    // XXX log this somewhere for easier web page debugging
+    return;
+  }
+
+  if (PR_FALSE == mSheet->ContainsStyleSheet(url)) { // don't allow circular references
+
+    PRInt32 ec;
+    nsIInputStream* in = url->Open(&ec);
+    if (nsnull == in) {
+      // failure to make connection
+      // XXX log this somewhere for easier web page debugging
+    }
+    else {
+
+      nsIUnicharInputStream* uin;
+      rv = NS_NewConverterStream(&uin, nsnull, in);
+      if (NS_OK != rv) {
+        // XXX no iso-latin-1 converter? out of memory?
+        NS_RELEASE(in);
+      }
+      else {
+
+        NS_RELEASE(in);
+
+        // Create a new parse to parse the import. 
+
+        if (NS_OK == rv) {
+          CSSParserImpl *parser = new CSSParserImpl();
+          nsIStyleSheet* childSheet = parser->Parse(&ec, uin, url);
+          NS_RELEASE(parser);
+          if (nsnull != childSheet) {
+            nsICSSStyleSheet* cssChild = nsnull;
+            if (NS_OK == childSheet->QueryInterface(kICSSStyleSheetIID, (void**)&cssChild)) {
+              mSheet->AppendStyleSheet(cssChild);
+              NS_RELEASE(cssChild);
+            }
+          }
+          NS_RELEASE(childSheet);
+        }
+        NS_RELEASE(uin);
+      }
+    }
+  }
+  NS_RELEASE(url);
+}
+
+void CSSParserImpl::SkipUntil(PRInt32* aErrorCode, PRUnichar aStopSymbol)
+{
+  nsCSSToken* tk = &mToken;
+  for (;;) {
+    if (!GetToken(aErrorCode, PR_TRUE)) {
+      break;
+    }
+    if (eCSSToken_Symbol == tk->mType) {
+      PRUnichar symbol = tk->mSymbol;
+      if (symbol == aStopSymbol) {
+        break;
+      } else if ('{' == symbol) {
+        SkipUntil(aErrorCode, '}');
+      } else if ('[' == symbol) {
+        SkipUntil(aErrorCode, ']');
+      } else if ('(' == symbol) {
+        SkipUntil(aErrorCode, ')');
+      }
+    }
+  }
+}
+
+void CSSParserImpl::SkipDeclaration(PRInt32* aErrorCode)
+{
+  nsCSSToken* tk = &mToken;
+  for (;;) {
+    if (!GetToken(aErrorCode, PR_TRUE)) {
+      break;
+    }
+    if (eCSSToken_Symbol == tk->mType) {
+      PRUnichar symbol = tk->mSymbol;
+      if (';' == symbol) {
+        break;
+      }
+      if ('}' == symbol) {
+        UngetToken();
+        break;
+      }
+      if ('{' == symbol) {
+        SkipUntil(aErrorCode, '}');
+      } else if ('(' == symbol) {
+        SkipUntil(aErrorCode, ')');
+      } else if ('[' == symbol) {
+        SkipUntil(aErrorCode, ']');
+      }
+    }
+  }
+}
+
+void CSSParserImpl::SkipRuleSet(PRInt32* aErrorCode)
+{
+  nsCSSToken* tk = &mToken;
+  for (;;) {
+    if (!GetToken(aErrorCode, PR_TRUE)) {
+      break;
+    }
+    if (eCSSToken_Symbol == tk->mType) {
+      PRUnichar symbol = tk->mSymbol;
+      if ('{' == symbol) {
+        SkipUntil(aErrorCode, '}');
+        break;
+      }
+      if ('(' == symbol) {
+        SkipUntil(aErrorCode, ')');
+      } else if ('[' == symbol) {
+        SkipUntil(aErrorCode, ']');
+      }
+    }
+  }
+}
+
+PRBool CSSParserImpl::ParseRuleSet(PRInt32* aErrorCode)
+{
+  nsCSSToken* tk = &mToken;
+
+  // First get the list of selectors for the rule
+  SelectorList *slist = new SelectorList();
+  if (!ParseSelectorList(aErrorCode, slist)) {
+    SkipRuleSet(aErrorCode);
+    slist->Destroy();
+    return PR_FALSE;
+  }
+
+  // Next parse the declaration block
+  nsICSSDeclaration* declaration = ParseDeclarationBlock(aErrorCode);
+  if (nsnull == declaration) {
+    // XXX skip something here
+    slist->Destroy();
+    return PR_FALSE;
+  }
+
+#if 0
+  slist->Dump();
+  fputs("{\n", stdout);
+  declaration->List();
+  fputs("}\n", stdout);
+#endif
+
+  // Translate the selector list and declaration block into style data
+
+  // XXX PSL working here 
+
+  SelectorList* list = slist;
+  nsCSSSelector selector;
+  nsICSSStyleRule* rule;
+
+  while (nsnull != list) {
+    PRInt32 selIndex = list->mSelectors.Count();
+
+    Selector* sel = (Selector*)list->mSelectors[--selIndex];
+    selector.Set(sel->mTag, sel->mID, sel->mClass, sel->mPseudo);
+    PRInt32 weight = sel->Weight();
+
+    if (NS_OK == NS_NewCSSStyleRule(&rule, selector)) {
+      while (--selIndex >= 0) {
+        Selector* sel = (Selector*)list->mSelectors[selIndex];
+        selector.Set(sel->mTag, sel->mID, sel->mClass, sel->mPseudo);
+
+        rule->AddSelector(selector);
+        weight += sel->Weight();
+      }
+      rule->SetDeclaration(declaration);
+      rule->SetWeight(weight);
+//      rule->List();
+      mSheet->AppendStyleRule(rule);
+      NS_RELEASE(rule);
+    }
+
+    list = list->mNext;
+  }
+
+  // XXX PSL working here
+
+  // Release temporary storage
+  slist->Destroy();
+  NS_RELEASE(declaration);
+  return PR_TRUE;
+}
+
+PRBool CSSParserImpl::ParseSelectorList(PRInt32* aErrorCode,
+                                        SelectorList* aListHead)
+{
+  if (!ParseSelectorGroup(aErrorCode, aListHead)) {
+    // must have at least one selector group
+    return PR_FALSE;
+  }
+
+  // After that there must either be a "," or a "{"
+  nsCSSToken* tk = &mToken;
+  for (;;) {
+    if (!GetToken(aErrorCode, PR_TRUE)) {
+      return PR_FALSE;
+    }
+    if (eCSSToken_Symbol != tk->mType) {
+      UngetToken();
+      return PR_FALSE;
+    }
+    if (',' == tk->mSymbol) {
+      // Another selector group must follow
+      SelectorList* newList = new SelectorList();
+      if (!ParseSelectorGroup(aErrorCode, newList)) {
+        newList->Destroy();
+        return PR_FALSE;
+      }
+      // add new list to the end of the selector list
+      aListHead->mNext = newList;
+      aListHead = newList;
+      continue;
+    } else if ('{' == tk->mSymbol) {
+      UngetToken();
+      break;
+    } else {
+      UngetToken();
+      return PR_FALSE;
+    }
+  }
+
+  return PR_TRUE;
+}
+
+PRBool CSSParserImpl::ParseSelectorGroup(PRInt32* aErrorCode,
+                                         SelectorList* aList)
+{
+  for (;;) {
+    Selector* sel = new Selector();
+    if (!ParseSelector(aErrorCode, sel)) {
+      delete sel;
+      break;
+    }
+    aList->AddSelector(sel);
+  }
+  return (PRBool) (aList->mSelectors.Count() > 0);
+}
+
+/**
+ * These are the 15 possible kinds of CSS1 style selectors:
+ * 
    + *
  • Tag + *
  • Tag#Id + *
  • Tag#Id.Class + *
  • Tag#Id.Class:Pseudo + *
  • Tag#Id:Pseudo + *
  • Tag.Class + *
  • Tag.Class:Pseudo + *
  • Tag:Pseudo + *
  • #Id + *
  • #Id.Class + *
  • #Id.Class:Pseudo + *
  • #Id:Pseudo + *
  • .Class + *
  • .Class:Pseudo + *
  • :Pseudo + *
+ */ +PRBool CSSParserImpl::ParseSelector(PRInt32* aErrorCode, + Selector* aSelectorResult) +{ + PRUint32 mask = 0; + aSelectorResult->mTag.SetLength(0); + aSelectorResult->mClass.SetLength(0); + aSelectorResult->mID.SetLength(0); + aSelectorResult->mPseudo.SetLength(0); + + nsCSSToken* tk = &mToken; + if (!GetToken(aErrorCode, PR_TRUE)) { + return PR_FALSE; + } + if (eCSSToken_Ident == tk->mType) { + // tag + mask |= SELECTOR_TAG; + aSelectorResult->mTag.Append(tk->mIdent); + if (!GetToken(aErrorCode, PR_FALSE)) { + // premature eof is ok (here!) + return PR_TRUE; + } + } + if (eCSSToken_ID == tk->mType) { + // #id + mask |= SELECTOR_ID; + aSelectorResult->mID.Append(tk->mIdent); + if (!GetToken(aErrorCode, PR_FALSE)) { + // premature eof is ok (here!) + return PR_TRUE; + } + } + if ((eCSSToken_Symbol == tk->mType) && ('.' == tk->mSymbol)) { + // .class + mask |= SELECTOR_CLASS; + if (!GetToken(aErrorCode, PR_FALSE)) { + return PR_FALSE; + } + if (eCSSToken_Ident != tk->mType) { + // malformed selector + UngetToken(); + return PR_FALSE; + } + aSelectorResult->mClass.Append(tk->mIdent); + if (!GetToken(aErrorCode, PR_FALSE)) { + // premature eof is ok (here!) + return PR_TRUE; + } + } + if ((eCSSToken_Symbol == tk->mType) && (':' == tk->mSymbol)) { + // :pseudo + mask |= SELECTOR_PSEUDO; + if (!GetToken(aErrorCode, PR_FALSE)) { + // premature eof + return PR_FALSE; + } + if (eCSSToken_Ident != tk->mType) { + // malformed selector + UngetToken(); + return PR_FALSE; + } + aSelectorResult->mPseudo.Append(tk->mIdent); + tk = nsnull; + } + if (nsnull != tk) { + UngetToken(); + } + if (mask == 0) { + return PR_FALSE; + } + aSelectorResult->mMask = mask; + return PR_TRUE; +} + +nsICSSDeclaration* CSSParserImpl::ParseDeclarationBlock(PRInt32* aErrorCode) +{ + if (!ExpectSymbol(aErrorCode, '{', PR_TRUE)) { + return nsnull; + } + nsICSSDeclaration* declaration = nsnull; + if (NS_OK == NS_NewCSSDeclaration(&declaration)) { + for (;;) { + if (!ParseDeclaration(aErrorCode, declaration)) { + SkipDeclaration(aErrorCode); + if (ExpectSymbol(aErrorCode, '}', PR_TRUE)) { + break; + } + // Since the skipped declaration didn't end the block we parse + // the next declaration. + } + } + } + return declaration; +} + +PRBool CSSParserImpl::ParseColor(PRInt32* aErrorCode, nscolor* aColorResult) +{ + char cbuf[50]; + + if (!GetToken(aErrorCode, PR_TRUE)) { + return PR_FALSE; + } + + nsCSSToken* tk = &mToken; + switch (tk->mType) { + case eCSSToken_ID: + // #xxyyzz + tk->mIdent.ToCString(cbuf, sizeof(cbuf)); + if (NS_HexToRGB(cbuf, aColorResult)) { + return PR_TRUE; + } + break; + + case eCSSToken_Ident: + if (!tk->mIdent.EqualsIgnoreCase("rgb")) { + // named color (maybe!) + tk->mIdent.ToCString(cbuf, sizeof(cbuf)); + if (NS_ColorNameToRGB(cbuf, aColorResult)) { + return PR_TRUE; + } + } else { + // rgb ( component , component , component ) + PRUint8 r, g, b; + if (ExpectSymbol(aErrorCode, '(', PR_TRUE) && + ParseColorComponent(aErrorCode, &r, ',') && + ParseColorComponent(aErrorCode, &g, ',') && + ParseColorComponent(aErrorCode, &b, ')')) { + *aColorResult = NS_RGB(r,g,b); + return PR_TRUE; + } + } + break; + + default: + break; + } + + // It's not a color + UngetToken(); + return PR_FALSE; +} + +PRBool CSSParserImpl::ParseColorComponent(PRInt32* aErrorCode, + PRUint8* aComponent, + char aStop) +{ + if (!GetToken(aErrorCode, PR_TRUE)) { + return PR_FALSE; + } + float value; + nsCSSToken* tk = &mToken; + switch (tk->mType) { + case eCSSToken_Number: + value = tk->mNumber; + break; + case eCSSToken_Percentage: + value = tk->mNumber * 255.0f; + break; + default: + UngetToken(); + return PR_FALSE; + } + if (ExpectSymbol(aErrorCode, aStop, PR_TRUE)) { + if (value < 0.0f) value = 0.0f; + if (value > 255.0f) value = 255.0f; + *aComponent = (PRUint8) value; + return PR_TRUE; + } + return PR_FALSE; +} + +//---------------------------------------------------------------------- + +PRBool CSSParserImpl::ParseDeclaration(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + // Get property name + nsCSSToken* tk = &mToken; + for (;;) { + if (!GetToken(aErrorCode, PR_TRUE)) { + return PR_FALSE; + } + if (eCSSToken_Ident == tk->mType) { + if (!ExpectSymbol(aErrorCode, ':', PR_TRUE)) { + return PR_FALSE; + } + break; + } + if ((eCSSToken_Symbol == tk->mType) && (';' == tk->mSymbol)) { + // dangling semicolons are skipped + continue; + } + + // Not a declaration... + UngetToken(); + return PR_FALSE; + } + + // Map property name to it's ID and then parse the property + char propertyName[100]; + tk->mIdent.ToCString(propertyName, sizeof(propertyName)); + if (!ParseProperty(aErrorCode, propertyName, aDeclaration)) { + return PR_FALSE; + } + + // Make sure valid property declaration is terminated with either a + // semicolon or a right-curly-brace. + if (!GetToken(aErrorCode, PR_TRUE)) { + // Premature eof is not ok + return PR_FALSE; + } + if (eCSSToken_Symbol == tk->mType) { + if (';' == tk->mSymbol) { + return PR_TRUE; + } + if ('}' == tk->mSymbol) { + UngetToken(); + return PR_TRUE; + } + } + return PR_FALSE; +} + +// Flags for ParseVariant method +#define VARIANT_KEYWORD 0x01 +#define VARIANT_LENGTH 0x02 +#define VARIANT_PERCENT 0x04 +#define VARIANT_COLOR 0x08 +#define VARIANT_URL 0x10 +#define VARIANT_NUMBER 0x20 +#define VARIANT_INTEGER 0x40 + +// Common combinations of variants +#define VARIANT_KL (VARIANT_KEYWORD | VARIANT_LENGTH) +#define VARIANT_KLP (VARIANT_KEYWORD | VARIANT_LENGTH | VARIANT_PERCENT) +#define VARIANT_KLPN (VARIANT_KLP | VARIANT_NUMBER) +#define VARIANT_KP (VARIANT_KEYWORD | VARIANT_PERCENT) +#define VARIANT_KI (VARIANT_KEYWORD | VARIANT_INTEGER) +#define VARIANT_LP (VARIANT_LENGTH | VARIANT_PERCENT) +#define VARIANT_CK (VARIANT_COLOR | VARIANT_KEYWORD) +#define VARIANT_C VARIANT_COLOR +#define VARIANT_UK (VARIANT_URL | VARIANT_KEYWORD) + +// Keyword id tables for variant/enum parsing +static PRInt32 kBackgroundAttachmentKTable[] = { + KEYWORD_FIXED, NS_STYLE_BG_ATTACHMENT_FIXED, + KEYWORD_SCROLL, NS_STYLE_BG_ATTACHMENT_SCROLL, + -1 +}; + +static PRInt32 kBackgroundColorKTable[] = { + KEYWORD_TRANSPARENT, NS_STYLE_BG_COLOR_TRANSPARENT, + -1 +}; + +static PRInt32 kBackgroundImageKTable[] = { + KEYWORD_NONE, NS_STYLE_BG_IMAGE_NONE, + -1 +}; + +static PRInt32 kBackgroundRepeatKTable[] = { + KEYWORD_NO_REPEAT, NS_STYLE_BG_REPEAT_OFF, + KEYWORD_REPEAT, NS_STYLE_BG_REPEAT_XY, + KEYWORD_REPEAT_X, NS_STYLE_BG_REPEAT_X, + KEYWORD_REPEAT_Y, NS_STYLE_BG_REPEAT_Y, + -1 +}; + +static PRInt32 kBorderStyleKTable[] = { + KEYWORD_NONE, NS_STYLE_BORDER_STYLE_NONE, + KEYWORD_DOTTED, NS_STYLE_BORDER_STYLE_DOTTED, + KEYWORD_DASHED, NS_STYLE_BORDER_STYLE_DASHED, + KEYWORD_SOLID, NS_STYLE_BORDER_STYLE_SOLID, + KEYWORD_DOUBLE, NS_STYLE_BORDER_STYLE_DOUBLE, + KEYWORD_GROOVE, NS_STYLE_BORDER_STYLE_GROOVE, + KEYWORD_RIDGE, NS_STYLE_BORDER_STYLE_RIDGE, + KEYWORD_INSET, NS_STYLE_BORDER_STYLE_INSET, + KEYWORD_OUTSET, NS_STYLE_BORDER_STYLE_OUTSET, + -1 +}; + +static PRInt32 kBorderWidthKTable[] = { + KEYWORD_THIN, NS_STYLE_BORDER_WIDTH_THIN, + KEYWORD_MEDIUM, NS_STYLE_BORDER_WIDTH_MEDIUM, + KEYWORD_THICK, NS_STYLE_BORDER_WIDTH_THICK, + -1 +}; + +static PRInt32 kClearKTable[] = { + KEYWORD_NONE, NS_STYLE_CLEAR_NONE, + KEYWORD_LEFT, NS_STYLE_CLEAR_LEFT, + KEYWORD_RIGHT, NS_STYLE_CLEAR_RIGHT, + KEYWORD_BOTH, NS_STYLE_CLEAR_BOTH, + -1 +}; + +static PRInt32 kClipKTable[] = { + KEYWORD_AUTO, NS_STYLE_CLIP_AUTO, + -1 +}; + +static PRInt32 kDisplayKTable[] = { + KEYWORD_NONE, NS_STYLE_DISPLAY_NONE, + KEYWORD_BLOCK, NS_STYLE_DISPLAY_BLOCK, + KEYWORD_INLINE, NS_STYLE_DISPLAY_INLINE, + KEYWORD_LIST_ITEM, NS_STYLE_DISPLAY_LIST_ITEM, + -1 +}; + +static PRInt32 kFloatKTable[] = { + KEYWORD_NONE, NS_STYLE_FLOAT_NONE, + KEYWORD_LEFT, NS_STYLE_FLOAT_LEFT, + KEYWORD_RIGHT, NS_STYLE_FLOAT_RIGHT, + -1 +}; + +static PRInt32 kFontSizeKTable[] = { + KEYWORD_XX_SMALL, NS_STYLE_FONT_SIZE_XXSMALL, + KEYWORD_X_SMALL, NS_STYLE_FONT_SIZE_XSMALL, + KEYWORD_SMALL, NS_STYLE_FONT_SIZE_SMALL, + KEYWORD_MEDIUM, NS_STYLE_FONT_SIZE_MEDIUM, + KEYWORD_LARGE, NS_STYLE_FONT_SIZE_LARGE, + KEYWORD_X_LARGE, NS_STYLE_FONT_SIZE_XLARGE, + KEYWORD_XX_LARGE, NS_STYLE_FONT_SIZE_XXLARGE, + KEYWORD_LARGER, NS_STYLE_FONT_SIZE_LARGER, + KEYWORD_SMALLER, NS_STYLE_FONT_SIZE_SMALLER, + -1 +}; + +static PRInt32 kFontStyleKTable[] = { + KEYWORD_NORMAL, NS_STYLE_FONT_STYLE_NORMAL, + KEYWORD_ITALIC, NS_STYLE_FONT_STYLE_ITALIC, + KEYWORD_OBLIQUE, NS_STYLE_FONT_STYLE_OBLIQUE, + -1 +}; + +static PRInt32 kFontVariantKTable[] = { + KEYWORD_NORMAL, NS_STYLE_FONT_VARIANT_NORMAL, + KEYWORD_SMALL_CAPS, NS_STYLE_FONT_VARIANT_SMALL_CAPS, + -1 +}; + +static PRInt32 kLeftKTable[] = { + KEYWORD_AUTO, NS_STYLE_LEFT_AUTO, + -1 +}; + +static PRInt32 kHeightKTable[] = { + KEYWORD_AUTO, NS_STYLE_HEIGHT_AUTO, + -1 +}; + +static PRInt32 kLineHeightKTable[] = { + KEYWORD_NORMAL, NS_STYLE_LINE_HEIGHT_NORMAL, + -1 +}; + +static PRInt32 kListStyleImageKTable[] = { + KEYWORD_NONE, NS_STYLE_LIST_STYLE_IMAGE_NONE, + -1 +}; + +static PRInt32 kListStylePositionKTable[] = { + KEYWORD_INSIDE, NS_STYLE_LIST_STYLE_POSITION_INSIDE, + KEYWORD_OUTSIDE, NS_STYLE_LIST_STYLE_POSITION_OUTSIDE, + -1 +}; + +static PRInt32 kListStyleKTable[] = { + KEYWORD_NONE, NS_STYLE_LIST_STYLE_NONE, + KEYWORD_DISC, NS_STYLE_LIST_STYLE_DISC, + KEYWORD_CIRCLE, NS_STYLE_LIST_STYLE_CIRCLE, + KEYWORD_SQUARE, NS_STYLE_LIST_STYLE_SQUARE, + KEYWORD_DECIMAL, NS_STYLE_LIST_STYLE_DECIMAL, + KEYWORD_LOWER_ROMAN, NS_STYLE_LIST_STYLE_LOWER_ROMAN, + KEYWORD_UPPER_ROMAN, NS_STYLE_LIST_STYLE_UPPER_ROMAN, + KEYWORD_LOWER_ALPHA, NS_STYLE_LIST_STYLE_LOWER_ALPHA, + KEYWORD_UPPER_ALPHA, NS_STYLE_LIST_STYLE_UPPER_ALPHA, + -1 +}; + +static PRInt32 kMarginSizeKTable[] = { + KEYWORD_AUTO, NS_STYLE_MARGIN_SIZE_AUTO, + -1 +}; + +static PRInt32 kSpacingKTable[] = { + KEYWORD_NORMAL, NS_STYLE_SPACING_NORMAL, + -1 +}; + +static PRInt32 kOverflowKTable[] = { + KEYWORD_VISIBLE, NS_STYLE_OVERFLOW_VISIBLE, + KEYWORD_HIDDEN, NS_STYLE_OVERFLOW_HIDDEN, + KEYWORD_SCROLL, NS_STYLE_OVERFLOW_SCROLL, + KEYWORD_AUTO, NS_STYLE_OVERFLOW_AUTO, + -1 +}; + +static PRInt32 kPositionKTable[] = { + KEYWORD_STATIC, NS_STYLE_POSITION_STATIC, + KEYWORD_RELATIVE, NS_STYLE_POSITION_RELATIVE, + KEYWORD_ABSOLUTE, NS_STYLE_POSITION_ABSOLUTE, + -1 +}; + +static PRInt32 kTextAlignKTable[] = { + KEYWORD_LEFT, NS_STYLE_TEXT_ALIGN_LEFT, + KEYWORD_RIGHT, NS_STYLE_TEXT_ALIGN_RIGHT, + KEYWORD_CENTER, NS_STYLE_TEXT_ALIGN_CENTER, + KEYWORD_JUSTIFY, NS_STYLE_TEXT_ALIGN_JUSTIFY, + -1 +}; + +static PRInt32 kTextTransformKTable[] = { + KEYWORD_NONE, NS_STYLE_TEXT_TRANSFORM_NONE, + KEYWORD_CAPITALIZE, NS_STYLE_TEXT_TRANSFORM_CAPITALIZE, + KEYWORD_LOWERCASE, NS_STYLE_TEXT_TRANSFORM_LOWERCASE, + KEYWORD_UPPERCASE, NS_STYLE_TEXT_TRANSFORM_UPPERCASE, + -1 +}; + +static PRInt32 kTopKTable[] = { + KEYWORD_AUTO, NS_STYLE_TOP_AUTO, + -1 +}; + +static PRInt32 kVerticalAlignKTable[] = { + KEYWORD_BASELINE, NS_STYLE_VERTICAL_ALIGN_BASELINE, + KEYWORD_SUB, NS_STYLE_VERTICAL_ALIGN_SUB, + KEYWORD_SUPER, NS_STYLE_VERTICAL_ALIGN_SUPER, + KEYWORD_TOP, NS_STYLE_VERTICAL_ALIGN_TOP, + KEYWORD_TEXT_TOP, NS_STYLE_VERTICAL_ALIGN_TEXT_TOP, + KEYWORD_MIDDLE, NS_STYLE_VERTICAL_ALIGN_MIDDLE, + KEYWORD_BOTTOM, NS_STYLE_VERTICAL_ALIGN_BOTTOM, + KEYWORD_TEXT_BOTTOM, NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM, + -1 +}; + +static PRInt32 kVisibilityKTable[] = { + KEYWORD_INHERIT, NS_STYLE_VISIBILITY_INHERIT, + KEYWORD_VISIBLE, NS_STYLE_VISIBILITY_VISIBLE, + KEYWORD_HIDDEN, NS_STYLE_VISIBILITY_HIDDEN, + -1 +}; + +static PRInt32 kWhitespaceKTable[] = { + KEYWORD_NORMAL, NS_STYLE_WHITESPACE_NORMAL, + KEYWORD_PRE, NS_STYLE_WHITESPACE_PRE, + KEYWORD_NOWRAP, NS_STYLE_WHITESPACE_NOWRAP, + -1 +}; + +static PRInt32 kWidthKTable[] = { + KEYWORD_AUTO, NS_STYLE_WIDTH_AUTO, + -1 +}; + +static PRInt32 kZIndexKTable[] = { + KEYWORD_AUTO, NS_STYLE_WIDTH_AUTO, + -1 +}; + +static const char* kBorderTopNames[] = { + "border-top-width", + "border-top-style", + "border-top-color", +}; +static const char* kBorderRightNames[] = { + "border-right-width", + "border-right-style", + "border-right-color", +}; +static const char* kBorderBottomNames[] = { + "border-bottom-width", + "border-bottom-style", + "border-bottom-color", +}; +static const char* kBorderLeftNames[] = { + "border-left-width", + "border-left-style", + "border-left-color", +}; + +PRInt32 CSSParserImpl::SearchKeywordTable(PRInt32 aID, PRInt32 aTable[]) +{ + PRInt32 i = 0; + for (;;) { + if (aTable[i] < 0) { + break; + } + if (aID == aTable[i]) { + return i; + } + i += 2; + } + return -1; +} + +PRBool CSSParserImpl::ParseEnum(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName, PRInt32* aTable) +{ + nsString* ident = NextIdent(aErrorCode); + if (nsnull == ident) { + return PR_FALSE; + } + char cbuf[50]; + ident->ToCString(cbuf, sizeof(cbuf)); + PRInt32 id = nsCSSKeywords::LookupName(cbuf); + if (id >= 0) { + PRInt32 ix = SearchKeywordTable(id, aTable); + if (ix >= 0) { + aDeclaration->AddValue(aName, nsCSSValue(aTable[ix+1], eCSSUnit_Enumerated)); + return PR_TRUE; + } + } + + // Put the unknown identifier back and return + UngetToken(); + return PR_FALSE; +} + +PRBool CSSParserImpl::TranslateLength(nsICSSDeclaration* aDeclaration, + const char* aName, + float aNumber, + const nsString& aDimension) +{ + nsCSSUnit units; + if (0 != aDimension.Length()) { + char cbuf[50]; + aDimension.ToCString(cbuf, sizeof(cbuf)); + PRInt32 id = nsCSSKeywords::LookupName(cbuf); + switch (id) { + case KEYWORD_EM: units = eCSSUnit_EM; break; + case KEYWORD_EX: units = eCSSUnit_XHeight; break; + case KEYWORD_PX: units = eCSSUnit_Pixel; break; + case KEYWORD_IN: units = eCSSUnit_Inch; break; + case KEYWORD_CM: units = eCSSUnit_Centimeter; break; + case KEYWORD_MM: units = eCSSUnit_Millimeter; break; + case KEYWORD_PT: units = eCSSUnit_Point; break; + case KEYWORD_PC: units = eCSSUnit_Pica; break; + default: + // unknown dimension + return PR_FALSE; + } + } else { + // Must be a zero number... + units = eCSSUnit_Point; + } + aDeclaration->AddValue(aName, nsCSSValue(aNumber, units)); + return PR_TRUE; +} + + +PRBool CSSParserImpl::ParseVariant(PRInt32* aErrorCode, + nsICSSDeclaration* aDeclaration, + const char* aName, + PRInt32 aVariants, PRInt32* aTable) +{ + nsCSSToken* tk = &mToken; + if (!GetToken(aErrorCode, PR_TRUE)) { + return PR_FALSE; + } + if (((aVariants & VARIANT_KEYWORD) != 0) && + (eCSSToken_Ident == tk->mType)) { + char cbuf[50]; + tk->mIdent.ToCString(cbuf, sizeof(cbuf)); + PRInt32 sid = nsCSSKeywords::LookupName(cbuf); + if (sid >= 0) { + PRInt32 ix = SearchKeywordTable(sid, aTable); + if (ix >= 0) { + aDeclaration->AddValue(aName, nsCSSValue(aTable[ix+1], eCSSUnit_Enumerated)); + return PR_TRUE; + } + } + } + if (((aVariants & VARIANT_LENGTH) != 0) && tk->isDimension()) { + return TranslateLength(aDeclaration, aName, tk->mNumber, tk->mIdent); + } + if (((aVariants & VARIANT_PERCENT) != 0) && + (eCSSToken_Percentage == tk->mType)) { + aDeclaration->AddValue(aName, nsCSSValue(tk->mNumber, eCSSUnit_Percent)); + return PR_TRUE; + } + if (((aVariants & VARIANT_NUMBER) != 0) && + (eCSSToken_Number == tk->mType)) { + aDeclaration->AddValue(aName, nsCSSValue(tk->mNumber, eCSSUnit_Number)); + return PR_TRUE; + } + if (((aVariants & VARIANT_INTEGER) != 0) && + (eCSSToken_Number == tk->mType) && tk->mIntegerValid) { + aDeclaration->AddValue(aName, nsCSSValue(tk->mInteger, eCSSUnit_Absolute)); + return PR_TRUE; + } + if (((aVariants & VARIANT_URL) != 0) && + (eCSSToken_URL == tk->mType)) { + aDeclaration->AddValue(aName, nsCSSValue(tk->mIdent)); + return PR_TRUE; + } + if ((aVariants & VARIANT_COLOR) != 0) { + if ((eCSSToken_ID == tk->mType) || (eCSSToken_Ident == tk->mType)) { + // Put token back so that parse color can get it + UngetToken(); + nscolor rgba; + // XXX This loses the original input format (e.g. a name which + // should be preserved when editing) + if (ParseColor(aErrorCode, &rgba)) { + aDeclaration->AddValue(aName, nsCSSValue(rgba)); + return PR_TRUE; + } + return PR_FALSE; + } + } + UngetToken(); + return PR_FALSE; +} + +PRInt32 CSSParserImpl::ParseChoice(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aNames[], PRInt32 aNumNames) +{ + PRInt32 found = 0; + for (int i = 0; i < aNumNames; i++) { + // Try each property parser in order + for (int j = 0; j < aNumNames; j++) { + PRInt32 bit = 1 << j; + if ((found & bit) == 0) { + PRInt32 id = nsCSSProps::LookupName(aNames[j]); + if (ParseProperty(aErrorCode, aNames[j], aDeclaration, id)) { + found |= bit; + } + } + } + } + return found; +} + +/** + * Parse a "box" property. Box properties have 1 to 4 values. When less + * than 4 values are provided a standard mapping is used to replicate + * existing values. Note that the replication requires renaming the + * values. + */ +PRBool CSSParserImpl::ParseBoxProperties(PRInt32* aErrorCode, + nsICSSDeclaration* aDeclaration, + const char* aNames[]) +{ + // Get up to four values for the property + PRInt32 count = 0; + for (int i = 0; i < 4; i++) { + PRInt32 id = nsCSSProps::LookupName(aNames[i]); + if (!ParseProperty(aErrorCode, aNames[i], aDeclaration, id)) { + break; + } + count++; + } + if (count == 0) { + return PR_FALSE; + } + + // Provide missing values by replicating some of the values found + nsCSSValue value; + switch (count) { + case 1: // Make right == top + aDeclaration->GetValue(aNames[0], value); + aDeclaration->AddValue(aNames[1], value); + case 2: // Make bottom == top + aDeclaration->GetValue(aNames[0], value); + aDeclaration->AddValue(aNames[2], value); + case 3: // Make left == right + aDeclaration->GetValue(aNames[1], value); + aDeclaration->AddValue(aNames[3], value); + } + + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseProperty(PRInt32* aErrorCode, + const char* aName, + nsICSSDeclaration* aDeclaration) +{ + PRInt32 id = nsCSSProps::LookupName(aName); + if (id < 0) { + return PR_FALSE; + } + + // Strip out properties we use internally. These properties are used + // by compound property parsing routines (e.g. "background-position"). + switch (id) { + case PROP_BACKGROUND_X_POSITION: + case PROP_BACKGROUND_Y_POSITION: + case PROP_BORDER_TOP_COLOR: + case PROP_BORDER_RIGHT_COLOR: + case PROP_BORDER_BOTTOM_COLOR: + case PROP_BORDER_LEFT_COLOR: + case PROP_BORDER_TOP_STYLE: + case PROP_BORDER_RIGHT_STYLE: + case PROP_BORDER_BOTTOM_STYLE: + case PROP_BORDER_LEFT_STYLE: + case PROP_CLIP_BOTTOM: + case PROP_CLIP_LEFT: + case PROP_CLIP_RIGHT: + case PROP_CLIP_TOP: + // The user can't use these + return PR_FALSE; + } + + return ParseProperty(aErrorCode, aName, aDeclaration, id); +} + +PRBool CSSParserImpl::ParseProperty(PRInt32* aErrorCode, + const char* aName, + nsICSSDeclaration* aDeclaration, + PRInt32 aID) +{ + switch (aID) { + case PROP_BACKGROUND: + return ParseBackground(aErrorCode, aDeclaration); + case PROP_BACKGROUND_ATTACHMENT: + return ParseEnum(aErrorCode, aDeclaration, aName, kBackgroundAttachmentKTable); + case PROP_BACKGROUND_COLOR: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_CK, + kBackgroundColorKTable); + case PROP_BACKGROUND_FILTER: + return ParseBackgroundFilter(aErrorCode, aDeclaration, aName); + case PROP_BACKGROUND_IMAGE: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_UK, + kBackgroundImageKTable); + case PROP_BACKGROUND_POSITION: + return ParseBackgroundPosition(aErrorCode, aDeclaration, aName); + case PROP_BACKGROUND_REPEAT: + return ParseEnum(aErrorCode, aDeclaration, aName, kBackgroundRepeatKTable); + case PROP_BORDER: + return ParseBorder(aErrorCode, aDeclaration); + case PROP_BORDER_COLOR: + return ParseBorderColor(aErrorCode, aDeclaration); + case PROP_BORDER_STYLE: + return ParseBorderStyle(aErrorCode, aDeclaration); + case PROP_BORDER_BOTTOM: + return ParseBorderSide(aErrorCode, aDeclaration, kBorderBottomNames, 0); + case PROP_BORDER_LEFT: + return ParseBorderSide(aErrorCode, aDeclaration, kBorderLeftNames, 1); + case PROP_BORDER_RIGHT: + return ParseBorderSide(aErrorCode, aDeclaration, kBorderRightNames, 2); + case PROP_BORDER_TOP: + return ParseBorderSide(aErrorCode, aDeclaration, kBorderTopNames, 3); + case PROP_BORDER_BOTTOM_COLOR: + case PROP_BORDER_LEFT_COLOR: + case PROP_BORDER_RIGHT_COLOR: + case PROP_BORDER_TOP_COLOR: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_C, nsnull); + case PROP_BORDER_BOTTOM_STYLE: + case PROP_BORDER_LEFT_STYLE: + case PROP_BORDER_RIGHT_STYLE: + case PROP_BORDER_TOP_STYLE: + return ParseEnum(aErrorCode, aDeclaration, aName, kBorderStyleKTable); + case PROP_BORDER_BOTTOM_WIDTH: + case PROP_BORDER_LEFT_WIDTH: + case PROP_BORDER_RIGHT_WIDTH: + case PROP_BORDER_TOP_WIDTH: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KL, + kBorderWidthKTable); + case PROP_BORDER_WIDTH: + return ParseBorderWidth(aErrorCode, aDeclaration); + case PROP_CLEAR: + return ParseEnum(aErrorCode, aDeclaration, aName, kClearKTable); + case PROP_CLIP: + return ParseClip(aErrorCode, aDeclaration); + case PROP_COLOR: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_COLOR, nsnull); + case PROP_DISPLAY: + return ParseEnum(aErrorCode, aDeclaration, aName, kDisplayKTable); + case PROP_FILTER: + return ParseForegroundFilter(aErrorCode, aDeclaration, aName); + case PROP_FLOAT: + return ParseEnum(aErrorCode, aDeclaration, aName, kFloatKTable); + case PROP_FONT: + return ParseFont(aErrorCode, aDeclaration, aName); + case PROP_FONT_FAMILY: + return ParseFontFamily(aErrorCode, aDeclaration, aName); + case PROP_FONT_SIZE: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KLP, + kFontSizeKTable); + case PROP_FONT_STYLE: + return ParseEnum(aErrorCode, aDeclaration, aName, kFontStyleKTable); + case PROP_FONT_VARIANT: + return ParseEnum(aErrorCode, aDeclaration, aName, kFontVariantKTable); + case PROP_FONT_WEIGHT: + return ParseFontWeight(aErrorCode, aDeclaration, aName); + case PROP_HEIGHT: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KL, kHeightKTable); + case PROP_LEFT: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KLP, kLeftKTable); + case PROP_LINE_HEIGHT: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KLPN, + kLineHeightKTable); + case PROP_LIST_STYLE: + return ParseListStyle(aErrorCode, aDeclaration); + case PROP_LIST_STYLE_IMAGE: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_UK, + kListStyleImageKTable); + case PROP_LIST_STYLE_POSITION: + return ParseEnum(aErrorCode, aDeclaration, aName, kListStylePositionKTable); + case PROP_LIST_STYLE_TYPE: + return ParseEnum(aErrorCode, aDeclaration, aName, kListStyleKTable); + case PROP_MARGIN: + return ParseMargin(aErrorCode, aDeclaration); + case PROP_MARGIN_BOTTOM: + case PROP_MARGIN_LEFT: + case PROP_MARGIN_RIGHT: + case PROP_MARGIN_TOP: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KLP, + kMarginSizeKTable); + case PROP_PADDING: + return ParsePadding(aErrorCode, aDeclaration); + case PROP_PADDING_BOTTOM: + case PROP_PADDING_LEFT: + case PROP_PADDING_RIGHT: + case PROP_PADDING_TOP: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_LP, nsnull); + case PROP_OVERFLOW: + return ParseEnum(aErrorCode, aDeclaration, aName, kOverflowKTable); + case PROP_POSITION: + return ParseEnum(aErrorCode, aDeclaration, aName, kPositionKTable); + case PROP_TEXT_ALIGN: + return ParseEnum(aErrorCode, aDeclaration, aName, kTextAlignKTable); + case PROP_TEXT_DECORATION: + return ParseTextDecoration(aErrorCode, aDeclaration, aName); + case PROP_TEXT_INDENT: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_LP, nsnull); + case PROP_TEXT_TRANSFORM: + return ParseEnum(aErrorCode, aDeclaration, aName, kTextTransformKTable); + case PROP_TOP: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KLP, kTopKTable); + case PROP_VERTICAL_ALIGN: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KP, + kVerticalAlignKTable); + case PROP_VISIBILITY: + return ParseEnum(aErrorCode, aDeclaration, aName, kVisibilityKTable); + case PROP_WHITE_SPACE: + return ParseEnum(aErrorCode, aDeclaration, aName, kWhitespaceKTable); + case PROP_WIDTH: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KLP, kWidthKTable); + case PROP_LETTER_SPACING: + case PROP_WORD_SPACING: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KL, kSpacingKTable); + case PROP_Z_INDEX: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KI, kZIndexKTable); + } + return PR_FALSE; +} + +PRBool CSSParserImpl::ParseBackground(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + static const char* kBackgroundNames[] = { + "background-color", + "background-image", + "background-repeat", + "background-attachment", + "background-position", + "background-filter", + }; + + PRInt32 found = ParseChoice(aErrorCode, aDeclaration, kBackgroundNames, 6); + if (0 == found) { + return PR_FALSE; + } + + // Provide missing values + if ((found & 1) == 0) { + aDeclaration->AddValue(kBackgroundNames[0], + nsCSSValue(NS_STYLE_BG_COLOR_TRANSPARENT, + eCSSUnit_Enumerated)); + } + if ((found & 2) == 0) { + aDeclaration->AddValue(kBackgroundNames[1], + nsCSSValue(NS_STYLE_BG_IMAGE_NONE, + eCSSUnit_Enumerated)); + } + if ((found & 4) == 0) { + aDeclaration->AddValue(kBackgroundNames[2], + nsCSSValue(NS_STYLE_BG_REPEAT_XY, + eCSSUnit_Enumerated)); + } + if ((found & 8) == 0) { + aDeclaration->AddValue(kBackgroundNames[3], + nsCSSValue(NS_STYLE_BG_ATTACHMENT_SCROLL, + eCSSUnit_Enumerated)); + } + if ((found & 16) == 0) { + aDeclaration->AddValue("background-x-position", nsCSSValue(0.0f, eCSSUnit_Percent)); + aDeclaration->AddValue("background-y-position", nsCSSValue(0.0f, eCSSUnit_Percent)); + } + + // XXX Note: no default for filter (yet) + return PR_TRUE; +} + +// Bits used in determining which background position info we have +#define BG_CENTER 0 +#define BG_TOP 1 +#define BG_BOTTOM 2 +#define BG_LEFT 4 +#define BG_RIGHT 8 +#define BG_CENTER1 16 +#define BG_CENTER2 32 + +PRBool CSSParserImpl::ParseBackgroundPosition(PRInt32* aErrorCode, + nsICSSDeclaration* aDeclaration, + const char* aName) +{ + static PRInt32 kBackgroundPositionNames[] = { + PROP_BACKGROUND_X_POSITION, + PROP_BACKGROUND_Y_POSITION, + }; + + // Note: Don't change this table unless you update + // parseBackgroundPosition! + + static PRInt32 kBackgroundXYPositionKTable[] = { + KEYWORD_CENTER, BG_CENTER, + KEYWORD_TOP, BG_TOP, + KEYWORD_BOTTOM, BG_BOTTOM, + KEYWORD_LEFT, BG_LEFT, + KEYWORD_RIGHT, BG_RIGHT, + -1, + }; + + const char* bxp = "background-x-position"; + const char* byp = "background-y-position"; + + // First try a number or a length value + if (ParseVariant(aErrorCode, aDeclaration, bxp, VARIANT_LP, nsnull)) { + // We have one number/length. Get the optional second number/length. + if (ParseVariant(aErrorCode, aDeclaration, byp, VARIANT_LP, nsnull)) { + // We have two numbers + return PR_TRUE; + } + + // We have one number which is the x position. Create an value for + // the vertical position which is of value 50% + aDeclaration->AddValue(byp, nsCSSValue(0.5f, eCSSUnit_Percent)); + // XXX shouldn't this be CENTER enum instead? + return PR_TRUE; + } + + // Now try keywords. We do this manually to allow for the first + // appearance of "center" to apply to the either the x or y + // position (it's ambiguous so we have to disambiguate). Each + // allowed keyword value is assigned it's own bit. We don't allow + // any duplicate keywords other than center. We try to get two + // keywords but it's okay if there is only one. + PRInt32 mask = 0; + PRInt32 centerBit = BG_CENTER1; + for (PRInt32 i = 0; i < 2; i++) { + nsString* ident = NextIdent(aErrorCode); + if (nsnull == ident) { + break; + } + char cbuf[50]; + ident->ToCString(cbuf, sizeof(cbuf)); + PRInt32 ix = SearchKeywordTable(nsCSSKeywords::LookupName(cbuf), + kBackgroundXYPositionKTable); + if (ix >= 0) { + PRInt32 bit = kBackgroundXYPositionKTable[ix + 1]; + if (bit == 0) { + // Special hack for center bits: We can have two of them + mask |= centerBit; + centerBit <<= 1; + continue; + } else if ((mask & bit) != 0) { + // no duplicate values allowed (other than center) + return PR_FALSE; + } + mask |= bit; + } else { + UngetToken(); + break; + } + } + + // Check for bad input. Bad input consists of no matching keywords, + // or pairs of x keywords or pairs of y keywords. + if ((mask == 0) || (mask == (BG_TOP | BG_BOTTOM)) || + (mask == (BG_LEFT | BG_RIGHT))) { + return PR_FALSE; + } + + // Map good input + int xValue = 50; + if ((mask & (BG_LEFT | BG_RIGHT)) != 0) { + // We have an x value + xValue = ((mask & BG_LEFT) != 0) ? 0 : 100; + } + int yValue = 50; + if ((mask & (BG_TOP | BG_BOTTOM)) != 0) { + // We have a y value + yValue = ((mask & BG_TOP) != 0) ? 0 : 100; + } + + // Create style values + aDeclaration->AddValue(bxp, nsCSSValue(xValue, eCSSUnit_Enumerated)); + aDeclaration->AddValue(byp, nsCSSValue(yValue, eCSSUnit_Enumerated)); + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseBackgroundFilter(PRInt32* aErrorCode, + nsICSSDeclaration* aDeclaration, + const char* aName) +{ + // XXX not yet supported + return PR_FALSE; +} + +PRBool CSSParserImpl::ParseForegroundFilter(PRInt32* aErrorCode, + nsICSSDeclaration* aDeclaration, + const char* aName) +{ + // XXX not yet supported + return PR_FALSE; +} + +// These must be in alphabetical order for aWhich based indexing to work +static const char* kBorderStyleNames[] = { + "border-bottom-style", + "border-left-style", + "border-right-style", + "border-top-style", +}; +static const char* kBorderWidthNames[] = { + "border-bottom-width", + "border-left-width", + "border-right-width", + "border-top-width", +}; + + +PRBool CSSParserImpl::ParseBorder(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + static const char* kBorderNames[] = { + "border-width", + "border-style", + "border-color" + }; + PRInt32 found = ParseChoice(aErrorCode, aDeclaration, kBorderNames, 3); + if (0 == found) { + return PR_FALSE; + } + if (0 == (found & 1)) { + // provide missing border width's + for (int i = 0; i < 4; i++) { + aDeclaration->AddValue(kBorderWidthNames[i], + nsCSSValue(NS_STYLE_BORDER_WIDTH_MEDIUM, + eCSSUnit_Enumerated)); + } + } + if (0 == (found & 2)) { + // provide missing border style's + for (int i = 0; i < 4; i++) { + aDeclaration->AddValue(kBorderStyleNames[i], + nsCSSValue(NS_STYLE_BORDER_STYLE_NONE, + eCSSUnit_Enumerated)); + } + } + + // Do NOT provide a missing color value as the default is to be + // the color of the element itself which must be determined later. + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseBorderColor(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + static const char* kBoxBorderColorNames[] = { + "border-top-color", + "border-right-color", + "border-bottom-color", + "border-left-color", + }; + return ParseBoxProperties(aErrorCode, aDeclaration, kBoxBorderColorNames); +} + +PRBool CSSParserImpl::ParseBorderSide(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aNames[], PRInt32 aWhich) +{ + PRInt32 found = ParseChoice(aErrorCode, aDeclaration, aNames, 3); + if (found == 0) return PR_FALSE; + if ((found & 1) == 0) { + // Provide default border-width + aDeclaration->AddValue(kBorderWidthNames[aWhich], + nsCSSValue(NS_STYLE_BORDER_WIDTH_MEDIUM, eCSSUnit_Enumerated)); + } + if ((found & 2) == 0) { + // Provide default border-style + aDeclaration->AddValue(kBorderStyleNames[aWhich], + nsCSSValue(NS_STYLE_BORDER_STYLE_NONE, eCSSUnit_Enumerated)); + } + + // Do NOT provide a missing color value as the default is to be + // the color of the element itself which must be determined later. + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseBorderStyle(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + // in top, right, bottom, left order + static const char* kBoxBorderStyleNames[] = { + "border-top-style", + "border-right-style", + "border-bottom-style", + "border-left-style", + }; + return ParseBoxProperties(aErrorCode, aDeclaration, kBoxBorderStyleNames); +} + +PRBool CSSParserImpl::ParseBorderWidth(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + static const char* kBoxBorderWidthNames[] = { + "border-top-width", + "border-right-width", + "border-bottom-width", + "border-left-width", + }; + return ParseBoxProperties(aErrorCode, aDeclaration, kBoxBorderWidthNames); +} + +PRBool CSSParserImpl::ParseClip(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + static const char* kClipNames[] = { + "clip-top", + "clip-right", + "clip-bottom", + "clip-left", + }; + nsString* ident = NextIdent(aErrorCode); + if (nsnull == ident) { + return PR_FALSE; + } + if (ident->EqualsIgnoreCase("auto")) { + for (int i = 0; i < 4; i++) { + aDeclaration->AddValue(kClipNames[i], + nsCSSValue(NS_STYLE_CLIP_AUTO, eCSSUnit_Enumerated)); + } + return PR_TRUE; + } else if (ident->EqualsIgnoreCase("rect")) { + if (!ExpectSymbol(aErrorCode, '(', PR_TRUE)) { + return PR_FALSE; + } + for (int i = 0; i < 4; i++) { + if (!ParseVariant(aErrorCode, aDeclaration, kClipNames[i], VARIANT_KL, + kClipKTable)) { + return PR_FALSE; + } + } + if (!ExpectSymbol(aErrorCode, ')', PR_TRUE)) { + return PR_FALSE; + } + return PR_TRUE; + } else { + UngetToken(); + } + return PR_FALSE; +} + +PRBool CSSParserImpl::ParseFont(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName) +{ + static const char* fontNames[] = { + "font-style", + "font-variant", + "font-weight", + }; + + // Get optional font-style, font-variant and font-weight (in any order) + PRInt32 found = ParseChoice(aErrorCode, aDeclaration, fontNames, 3); + if ((found & 1) == 0) { + // Provide default font-style + aDeclaration->AddValue(fontNames[0], + nsCSSValue(NS_STYLE_FONT_STYLE_NORMAL, eCSSUnit_Enumerated)); + } + if ((found & 2) == 0) { + // Provide default font-variant + aDeclaration->AddValue(fontNames[1], + nsCSSValue(NS_STYLE_FONT_VARIANT_NORMAL, eCSSUnit_Enumerated)); + } + if ((found & 4) == 0) { + // Provide default font-weight + aDeclaration->AddValue(fontNames[2], + nsCSSValue(NS_STYLE_FONT_WEIGHT_NORMAL, eCSSUnit_Enumerated)); + } + + // Get mandatory font-size + if (!ParseVariant(aErrorCode, aDeclaration, "font-size", + VARIANT_KLP, kFontSizeKTable)) { + return PR_FALSE; + } + + // Get optional "/" line-height + if (ExpectSymbol(aErrorCode, '/', PR_TRUE)) { + if (!ParseVariant(aErrorCode, aDeclaration, "line-height", + VARIANT_KLPN, kLineHeightKTable)) { + return PR_FALSE; + } + } + + // Get final mandatory font-family + return ParseFontFamily(aErrorCode, aDeclaration, "font-family"); +} + +PRBool CSSParserImpl::ParseFontFamily(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName) +{ + nsCSSToken* tk = &mToken; + nsAutoString family; + PRBool firstOne = PR_TRUE; + for (;;) { + if (!GetToken(aErrorCode, PR_TRUE)) { + break; + } + if (eCSSToken_Ident == tk->mType) { + if (!firstOne) { + family.Append(PRUnichar(',')); + } + family.Append(PRUnichar('"')); + family.Append(tk->mIdent); + for (;;) { + if (!GetToken(aErrorCode, PR_FALSE)) { + break; + } + if (eCSSToken_Ident == tk->mType) { + family.Append(tk->mIdent); + } else if (eCSSToken_WhiteSpace == tk->mType) { + // Lookahead one token and drop whitespace if we ending the + // font name. + if (!GetToken(aErrorCode, PR_TRUE)) { + break; + } + if (eCSSToken_Ident != tk->mType) { + UngetToken(); + break; + } + UngetToken(); + family.Append(PRUnichar(' ')); + } else { + UngetToken(); + break; + } + } + family.Append(PRUnichar('"')); + firstOne = PR_FALSE; + } else if (eCSSToken_String == tk->mType) { + if (!firstOne) { + family.Append(PRUnichar(',')); + } + family.Append(PRUnichar('"')); + family.Append(tk->mIdent); + family.Append(PRUnichar('"')); + firstOne = PR_FALSE; + } else if (eCSSToken_Symbol == tk->mType) { + if (',' != tk->mSymbol) { + UngetToken(); + break; + } + } else { + UngetToken(); + break; + } + } + if (family.Length() == 0) { + return PR_FALSE; + } + aDeclaration->AddValue(aName, nsCSSValue(family)); + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseFontWeight(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName) +{ + static PRInt32 kFontWeightKTable[] = { + KEYWORD_NORMAL, NS_STYLE_FONT_WEIGHT_NORMAL, + KEYWORD_BOLD, NS_STYLE_FONT_WEIGHT_BOLD, + KEYWORD_BOLDER, NS_STYLE_FONT_WEIGHT_BOLDER, + KEYWORD_LIGHTER, NS_STYLE_FONT_WEIGHT_LIGHTER, + -1, + }; + nsCSSToken* tk = &mToken; + if (!GetToken(aErrorCode, PR_TRUE)) { + return PR_FALSE; + } + if (eCSSToken_Ident == tk->mType) { + char cbuf[50]; + tk->mIdent.ToCString(cbuf, sizeof(cbuf)); + PRInt32 kid = nsCSSKeywords::LookupName(cbuf); + PRInt32 ix = SearchKeywordTable(kid, kFontWeightKTable); + if (ix < 0) { + UngetToken(); + return PR_FALSE; + } + aDeclaration->AddValue(aName, nsCSSValue(kFontWeightKTable[ix+1], eCSSUnit_Enumerated)); + } else if (eCSSToken_Number == tk->mType) { + PRInt32 v = (PRInt32) tk->mNumber; + if (v < 100) v = 100; + else if (v > 900) v = 900; + v = v - (v % 100); + aDeclaration->AddValue(aName, nsCSSValue(v, eCSSUnit_Absolute)); + } else { + UngetToken(); + return PR_FALSE; + } + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseListStyle(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + const char* lst = "list-style-type"; + const char* lsp = "list-style-position"; + const char* lsi = "list-style-image"; + int found = 0; + for (int i = 0; i < 3; i++) { + if (((found & 1) == 0) && + ParseEnum(aErrorCode, aDeclaration, lst, kListStyleKTable)) { + found |= 1; + continue; + } + if (((found & 2) == 0) && + ParseEnum(aErrorCode, aDeclaration, lsp, kListStylePositionKTable)) { + found |= 2; + continue; + } + if ((found & 4) == 0) { + if (!GetToken(aErrorCode, PR_TRUE)) { + break; + } + if (eCSSToken_URL == mToken.mType) { + aDeclaration->AddValue(lsi, nsCSSValue(mToken.mIdent)); + found |= 4; + continue; + } else { + if (eCSSToken_Symbol == mToken.mType) { + PRUnichar symbol = mToken.mSymbol; + if ((';' == symbol) || ('}' == symbol)) { + UngetToken(); + break; + } + } + + // We got something strange. That's an error. + UngetToken(); + return PR_FALSE; + } + } + } + if (found == 0) { + return PR_FALSE; + } + + // Provide default values + if ((found & 1) == 0) { + aDeclaration->AddValue(lst, nsCSSValue(NS_STYLE_LIST_STYLE_DISC, eCSSUnit_Enumerated)); + } + if ((found & 2) == 0) { + aDeclaration->AddValue(lsp, nsCSSValue(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE, eCSSUnit_Enumerated)); + } + if ((found & 4) == 0) { + aDeclaration->AddValue(lsi, nsCSSValue(NS_STYLE_LIST_STYLE_IMAGE_NONE, eCSSUnit_Enumerated)); + } + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseMargin(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + static const char* kBoxMarginSideNames[] = { + "margin-top", + "margin-right", + "margin-bottom", + "margin-left", + }; + return ParseBoxProperties(aErrorCode, aDeclaration, kBoxMarginSideNames); +} + +PRBool CSSParserImpl::ParsePadding(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + static const char* kBoxPaddingSideNames[] = { + "padding-top", + "padding-right", + "padding-bottom", + "padding-left", + }; + return ParseBoxProperties(aErrorCode, aDeclaration, kBoxPaddingSideNames); +} + +PRBool CSSParserImpl::ParseTextDecoration(PRInt32* aErrorCode, + nsICSSDeclaration* aDeclaration, + const char* aName) +{ + static PRInt32 kTextDecorationNoneKTable[] = { + KEYWORD_NONE, NS_STYLE_TEXT_DECORATION_NONE, + -1 + }; + static PRInt32 kTextDecorationKTable[] = { + KEYWORD_UNDERLINE, NS_STYLE_TEXT_DECORATION_UNDERLINE, + KEYWORD_OVERLINE, NS_STYLE_TEXT_DECORATION_OVERLINE, + KEYWORD_LINE_THROUGH, NS_STYLE_TEXT_DECORATION_LINE_THROUGH, + KEYWORD_BLINK, NS_STYLE_TEXT_DECORATION_BLINK, + -1, + }; + + if (ParseEnum(aErrorCode, aDeclaration, aName, kTextDecorationNoneKTable)) { + return PR_TRUE; + } + + PRInt32 decoration = 0; + for (int i = 0; i < 4; i++) { + nsString* ident = NextIdent(aErrorCode); + if (nsnull == ident) { + break; + } + char cbuf[50]; + ident->ToCString(cbuf, sizeof(cbuf)); + PRInt32 id = nsCSSKeywords::LookupName(cbuf); + PRInt32 ix = SearchKeywordTable(id, kTextDecorationKTable); + if (ix < 0) { + UngetToken(); + break; + } + decoration |= kTextDecorationKTable[ix+1]; + } + if (0 == decoration) { + return PR_FALSE; + } + aDeclaration->AddValue(aName, nsCSSValue(decoration, eCSSUnit_Absolute)); + return PR_TRUE; +} diff --git a/mozilla/content/html/style/src/nsCSSProps.h b/mozilla/content/html/style/src/nsCSSProps.h new file mode 100644 index 00000000000..29bd8de6945 --- /dev/null +++ b/mozilla/content/html/style/src/nsCSSProps.h @@ -0,0 +1,40 @@ +/* -*- 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. + */ +#ifndef nsCSSProps_h___ +#define nsCSSProps_h___ + +#include "nslayout.h" +#include "nsCSSPropIDs.h" + +class NS_LAYOUT nsCSSProps { +public: + // Given a null terminated string of 7 bit characters, return the + // tag id (see nsCSSPropIDs.h) for the tag or -1 if the tag is not + // known. The lookup function uses a perfect hash. + static PRInt32 LookupName(const char* str); + + struct NameTableEntry { + const char* name; + PRInt32 id; + }; + + // A table whose index is the tag id (from nsCSSPropIDs) + static const NameTableEntry kNameTable[]; +}; + +#endif /* nsCSSProps_h___ */ diff --git a/mozilla/content/html/style/src/nsCSSScanner.cpp b/mozilla/content/html/style/src/nsCSSScanner.cpp new file mode 100644 index 00000000000..50f64a93f29 --- /dev/null +++ b/mozilla/content/html/style/src/nsCSSScanner.cpp @@ -0,0 +1,585 @@ +/* -*- 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 "nsCSSScanner.h" +#include "nsIInputStream.h" +#include "nsIUnicharInputStream.h" +#include "nsString.h" +#include "nsCRT.h" + +#ifdef NS_DEBUG +static char* kNullPointer = "null pointer"; +#endif + +// Don't bother collecting whitespace characters in token's mIdent buffer +#undef COLLECT_WHITESPACE + +#define BUFFER_SIZE 256 + +static const PRUnichar CSS_ESCAPE = PRUnichar('\\'); + +static const PRUint8 IS_LATIN1 = 0x01; +static const PRUint8 IS_DIGIT = 0x02; +static const PRUint8 IS_HEX_DIGIT = 0x04; +static const PRUint8 IS_ALPHA = 0x08; +static const PRUint8 START_IDENT = 0x10; +static const PRUint8 IS_IDENT = 0x20; +static const PRUint8 IS_WHITESPACE = 0x40; + +static PRUint8* gLexTable; + +static void BuildLexTable() +{ + PRUint8* lt = new PRUint8[256]; + nsCRT::zero(lt, 256); + gLexTable = lt; + + int i; + lt[CSS_ESCAPE] = START_IDENT; + lt['-'] |= IS_IDENT; + // XXX add in other whitespace chars + lt[' '] |= IS_WHITESPACE; + lt['\t'] |= IS_WHITESPACE; + lt['\r'] |= IS_WHITESPACE; + lt['\n'] |= IS_WHITESPACE; + for (i = 161; i <= 255; i++) { + lt[i] |= IS_LATIN1 | IS_IDENT | START_IDENT; + } + for (i = '0'; i <= '9'; i++) { + lt[i] |= IS_DIGIT | IS_HEX_DIGIT | IS_IDENT; + } + for (i = 'A'; i <= 'Z'; i++) { + if ((i >= 'A') && (i <= 'F')) { + lt[i] |= IS_HEX_DIGIT; + lt[i+32] |= IS_HEX_DIGIT; + } + lt[i] |= IS_ALPHA | IS_IDENT | START_IDENT; + lt[i+32] |= IS_ALPHA | IS_IDENT | START_IDENT; + } +} + +nsCSSToken::nsCSSToken() +{ + mType = eCSSToken_Symbol; +} + +nsCSSScanner::nsCSSScanner() +{ + if (nsnull == gLexTable) { + // XXX need a monitor + BuildLexTable(); + } + mInput = nsnull; + mBuffer = new PRUnichar[BUFFER_SIZE]; + mOffset = 0; + mCount = 0; + mLookAhead = -1; +} + +nsCSSScanner::~nsCSSScanner() +{ + Close(); + if (nsnull != mBuffer) { + delete mBuffer; + mBuffer = nsnull; + } +} + +void nsCSSScanner::Init(nsIUnicharInputStream* aInput) +{ + NS_PRECONDITION(nsnull != aInput, kNullPointer); + Close(); + mInput = aInput; + if (nsnull != aInput) { + aInput->AddRef(); + } +} + +void nsCSSScanner::Close() +{ + NS_IF_RELEASE(mInput); +} + +// Returns -1 on error or eof +PRInt32 nsCSSScanner::Read(PRInt32* aErrorCode) +{ + PRInt32 rv; + if (mLookAhead >= 0) { + rv = mLookAhead; + mLookAhead = -1; + } else { + if (mCount < 0) { + return -1; + } + if (mOffset == mCount) { + mOffset = 0; + mCount = mInput->Read(aErrorCode, mBuffer, 0, BUFFER_SIZE); + if (mCount <= 0) { + return -1; + } + } + rv = PRInt32(mBuffer[mOffset++]); + } + mLastRead = rv; +//printf("Read => %x\n", rv); + return rv; +} + +PRInt32 nsCSSScanner::Peek(PRInt32* aErrorCode) +{ + if (mLookAhead < 0) { + mLookAhead = Read(aErrorCode); + if (mLookAhead < 0) { + return -1; + } + } +//printf("Peek => %x\n", mLookAhead); + return mLookAhead; +} + +void nsCSSScanner::Unread() +{ + NS_PRECONDITION((mLastRead >= 0) && (mLookAhead < 0), "double pushback"); + mLookAhead = mLastRead; + mLastRead = -1; +} + +PRBool nsCSSScanner::LookAhead(PRInt32* aErrorCode, PRUnichar aChar) +{ + PRInt32 ch = Read(aErrorCode); + if (ch < 0) { + return PR_FALSE; + } + if (ch == aChar) { + return PR_TRUE; + } + Unread(); + return PR_FALSE; +} + +PRBool nsCSSScanner::EatWhiteSpace(PRInt32* aErrorCode) +{ + PRBool eaten = PR_FALSE; + for (;;) { + PRInt32 ch = Read(aErrorCode); + if (ch < 0) { + break; + } + if ((ch == ' ') || (ch == '\n') || (ch == '\r') || (ch == '\t')) { + eaten = PR_TRUE; + continue; + } + Unread(); + break; + } + return eaten; +} + +PRBool nsCSSScanner::EatNewline(PRInt32* aErrorCode) +{ + PRInt32 ch = Read(aErrorCode); + if (ch < 0) { + return PR_FALSE; + } + PRBool eaten = PR_FALSE; + if (ch == '\r') { + eaten = PR_TRUE; + ch = Peek(aErrorCode); + if (ch == '\n') { + (void) Read(aErrorCode); + } + } else if (ch == '\n') { + eaten = PR_TRUE; + } else { + Unread(); + } + return eaten; +} + +PRBool nsCSSScanner::Next(PRInt32* aErrorCode, nsCSSToken* aToken) +{ + PRInt32 ch = Read(aErrorCode); + if (ch < 0) { + return PR_FALSE; + } + if (ch < 256) { + PRUint8* lexTable = gLexTable; + + // IDENT + if ((lexTable[ch] & START_IDENT) != 0) { + return ParseIdent(aErrorCode, ch, aToken); + } + + // AT_KEYWORD + if (ch == '@') { + PRInt32 nextChar = Peek(aErrorCode); + if ((nextChar >= 0) && (nextChar <= 255)) { + if ((lexTable[nextChar] & START_IDENT) != 0) { + return ParseAtKeyword(aErrorCode, ch, aToken); + } + } + } + + // NUMBER or DIM + if ((ch == '.') || (ch == '+') || (ch == '-')) { + PRInt32 nextChar = Peek(aErrorCode); + if ((nextChar >= 0) && (nextChar <= 255)) { + if ((lexTable[nextChar] & IS_DIGIT) != 0) { + return ParseNumber(aErrorCode, ch, aToken); + } + } + } + if ((lexTable[ch] & IS_DIGIT) != 0) { + return ParseNumber(aErrorCode, ch, aToken); + } + + // ID + if (ch == '#') { + return ParseID(aErrorCode, ch, aToken); + } + + // STRING + if ((ch == '"') || (ch == '\'')) { + return ParseString(aErrorCode, ch, aToken); + } + + // WS + if ((lexTable[ch] & IS_WHITESPACE) != 0) { + aToken->mType = eCSSToken_WhiteSpace; + aToken->mIdent.SetLength(0); + aToken->mIdent.Append(PRUnichar(ch)); + (void) EatWhiteSpace(aErrorCode); + return PR_TRUE; + } + if (ch == '/') { + PRInt32 nextChar = Peek(aErrorCode); + if (nextChar == '/') { + (void) Read(aErrorCode); + aToken->mIdent.SetLength(0); + aToken->mIdent.Append(PRUnichar(ch)); + aToken->mIdent.Append(PRUnichar(ch)); + return ParseEOLComment(aErrorCode, aToken); + } else if (nextChar == '*') { + (void) Read(aErrorCode); + aToken->mIdent.SetLength(0); + aToken->mIdent.Append(PRUnichar(ch)); + aToken->mIdent.Append(PRUnichar(nextChar)); + return ParseCComment(aErrorCode, aToken); + } + } + } + aToken->mType = eCSSToken_Symbol; + aToken->mSymbol = ch; + return PR_TRUE; +} + +PRInt32 nsCSSScanner::ParseEscape(PRInt32* aErrorCode) +{ + PRUint8* lexTable = gLexTable; + PRInt32 ch = Peek(aErrorCode); + if (ch < 0) { + return CSS_ESCAPE; + } + if ((ch <= 255) && ((lexTable[ch] & IS_HEX_DIGIT) != 0)) { + PRInt32 rv = 0; + for (int i = 0; i < 4; i++) { + ch = Read(aErrorCode); + if (ch < 0) { + // Whoops: error or premature eof + break; + } + if ((lexTable[ch] & IS_HEX_DIGIT) != 0) { + if ((lexTable[ch] & IS_DIGIT) != 0) { + rv = rv * 16 + (ch - '0'); + } else { + // Note: c&7 just keeps the low three bits which causes + // upper and lower case alphabetics to both yield their + // "relative to 10" value for computing the hex value. + rv = rv * 16 + (ch & 0x7) + 10; + } + } else { + Unread(); + break; + } + } + return rv; + } else { + // "Any character except a hexidecimal digit can be escaped to + // remove its special meaning by putting a backslash in front" + // -- CSS1 spec section 7.1 + (void) Read(aErrorCode); + return ch; + } +} + +/** + * Gather up the characters in an identifier. The identfier was + * started by "aChar" which will be appended to aIdent. The result + * will be aIdent with all of the identifier characters appended + * until the first non-identifier character is seen. The termination + * character is unread for the future re-reading. + */ +PRBool nsCSSScanner::GatherIdent(PRInt32* aErrorCode, PRInt32 aChar, + nsString& aIdent) +{ + if (aChar == CSS_ESCAPE) { + aChar = ParseEscape(aErrorCode); + } + for (;;) { + aChar = Read(aErrorCode); + if (aChar < 0) break; + if (aChar == CSS_ESCAPE) { + aChar = ParseEscape(aErrorCode); + aIdent.Append(PRUnichar(aChar)); + } else if ((aChar <= 255) && ((gLexTable[aChar] & IS_IDENT) != 0)) { + aIdent.Append(PRUnichar(aChar)); + } else { + Unread(); + break; + } + } + return PR_TRUE; +} + +PRBool nsCSSScanner::ParseID(PRInt32* aErrorCode, + PRInt32 aChar, + nsCSSToken* aToken) +{ + aToken->mIdent.SetLength(0); + aToken->mType = eCSSToken_ID; + return GatherIdent(aErrorCode, aChar, aToken->mIdent); +} + +PRBool nsCSSScanner::ParseIdent(PRInt32* aErrorCode, + PRInt32 aChar, + nsCSSToken* aToken) +{ + nsString& ident = aToken->mIdent; + ident.SetLength(0); + ident.Append(PRUnichar(aChar)); + if (!GatherIdent(aErrorCode, aChar, ident)) { + return PR_FALSE; + } + + // Process a url lexical token. A CSS1 url token can contain + // characters beyond identifier characters (e.g. '/', ':', etc.) + // Because of this the normal rules for tokenizing the input don't + // apply very well. To simplify the parser and relax some of the + // requirements on the scanner we parse url's here. If we find a + // malformed URL then we emit a token of type "InvalidURL" so that + // the CSS1 parser can ignore the invalid input. We attempt to eat + // the right amount of input data when an invalid URL is presented. + nsCSSTokenType tokenType = eCSSToken_Ident; + if (ident.EqualsIgnoreCase("url")) { + tokenType = eCSSToken_InvalidURL; + if (LookAhead(aErrorCode, '(')) { + // Skip leading whitespace + (void) EatWhiteSpace(aErrorCode); + ident.SetLength(0); + + PRInt32 c = Read(aErrorCode); + if (c == ')') { + // empty url spec: this is invalid + } else if ((c == '"') || (c == '\'')) { + // start of a quoted url + if (!GatherString(aErrorCode, c, ident)) { + return PR_FALSE; + } + if (!EatWhiteSpace(aErrorCode)) { + return PR_FALSE; + } + if (LookAhead(aErrorCode, ')')) { + tokenType = eCSSToken_URL; + } + } else { + // start of a non-quoted url + Unread(); + PRBool ok = PR_TRUE; + for (;;) { + c = Read(aErrorCode); + if (c < 0) break; + if (c == CSS_ESCAPE) { + c = ParseEscape(aErrorCode); + ident.Append(PRUnichar(c)); + } else if ((c == '"') || (c == '\'') || (c == '(')) { + // This is an invalid URL spec + ok = PR_FALSE; + } else if ((256 >= c) && ((gLexTable[c] & IS_WHITESPACE) != 0)) { + // Whitespace is allowed at the end of the URL + (void) EatWhiteSpace(aErrorCode); + if (LookAhead(aErrorCode, ')')) { + // done! + break; + } + // Whitespace is followed by something other than a + // ")". This is an invalid url spec. + ok = PR_FALSE; + } else if (c == ')') { + // All done + break; + } else { + // A regular url character. + ident.Append(PRUnichar(c)); + } + } + + // If the result of the above scanning is ok then change the token + // type to a useful one. + if (ok) { + tokenType = eCSSToken_URL; + } + } + } + } + aToken->mType = tokenType; + return PR_TRUE; +} + +PRBool nsCSSScanner::ParseAtKeyword(PRInt32* aErrorCode, PRInt32 aChar, + nsCSSToken* aToken) +{ + aToken->mIdent.SetLength(0); + aToken->mType = eCSSToken_AtKeyword; + return GatherIdent(aErrorCode, aChar, aToken->mIdent); +} + +PRBool nsCSSScanner::ParseNumber(PRInt32* aErrorCode, PRInt32 c, + nsCSSToken* aToken) +{ + nsString& ident = aToken->mIdent; + ident.SetLength(0); + PRBool gotDot = (c == '.') ? PR_TRUE : PR_FALSE; + if (c != '+') { + ident.Append(PRUnichar(c)); + } + + // Gather up characters that make up the number + PRUint8* lexTable = gLexTable; + for (;;) { + c = Read(aErrorCode); + if (c < 0) break; + if (!gotDot && (c == '.')) { + gotDot = PR_TRUE; + } else if ((c > 255) || ((lexTable[c] & IS_DIGIT) == 0)) { + break; + } + ident.Append(PRUnichar(c)); + } + + // Convert number to floating point + nsCSSTokenType type = eCSSToken_Number; + PRInt32 ec; + float value = ident.ToFloat(&ec); + + // Look at character that terminated the number + aToken->mIntegerValid = PR_FALSE; + if (c >= 0) { + if ((c <= 255) && ((lexTable[c] & START_IDENT) != 0)) { + ident.SetLength(0); + ident.Append(PRUnichar(c)); + if (!GatherIdent(aErrorCode, c, ident)) { + return PR_FALSE; + } + type = eCSSToken_Dimension; + } else if ('%' == c) { + type = eCSSToken_Percentage; + value = value / 100.0f; + } else { + // Put back character that stopped numeric scan + Unread(); + if (!gotDot) { + aToken->mInteger = ident.ToInteger(&ec); + aToken->mIntegerValid = PR_TRUE; + } + ident.SetLength(0); + } + } + aToken->mNumber = value; + aToken->mType = type; + return PR_TRUE; +} + +PRBool nsCSSScanner::ParseCComment(PRInt32* aErrorCode, nsCSSToken* aToken) +{ + nsString& ident = aToken->mIdent; + for (;;) { + PRInt32 ch = Read(aErrorCode); + if (ch < 0) break; + if (ch == '*') { + if (LookAhead(aErrorCode, '/')) { + ident.Append(PRUnichar(ch)); + ident.Append('/'); + break; + } + } +#ifdef COLLECT_WHITESPACE + ident.Append(PRUnichar(ch)); +#endif + } + aToken->mType = eCSSToken_WhiteSpace; + return PR_TRUE; +} + +PRBool nsCSSScanner::ParseEOLComment(PRInt32* aErrorCode, nsCSSToken* aToken) +{ + nsString& ident = aToken->mIdent; + ident.SetLength(0); + for (;;) { + if (EatNewline(aErrorCode)) { + break; + } + PRInt32 ch = Read(aErrorCode); + if (ch < 0) { + break; + } +#ifdef COLLECT_WHITESPACE + ident.Append(PRUnichar(ch)); +#endif + } + aToken->mType = eCSSToken_WhiteSpace; + return PR_TRUE; +} + +PRBool nsCSSScanner::GatherString(PRInt32* aErrorCode, PRInt32 aStop, + nsString& aBuffer) +{ + for (;;) { + PRInt32 ch = Read(aErrorCode); + if (ch < 0) { + return PR_FALSE; + } + if (ch == aStop) { + break; + } + if (ch == CSS_ESCAPE) { + ch = ParseEscape(aErrorCode); + if (ch < 0) { + return PR_FALSE; + } + } + aBuffer.Append(PRUnichar(ch)); + } + return PR_TRUE; +} + +PRBool nsCSSScanner::ParseString(PRInt32* aErrorCode, PRInt32 aStop, + nsCSSToken* aToken) +{ + aToken->mIdent.SetLength(0); + aToken->mType = eCSSToken_String; + return GatherString(aErrorCode, aStop, aToken->mIdent); +} diff --git a/mozilla/content/html/style/src/nsCSSScanner.h b/mozilla/content/html/style/src/nsCSSScanner.h new file mode 100644 index 00000000000..afbe1da67fd --- /dev/null +++ b/mozilla/content/html/style/src/nsCSSScanner.h @@ -0,0 +1,118 @@ +/* -*- 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. + */ +#ifndef nsCSSScanner_h___ +#define nsCSSScanner_h___ + +#include "nsString.h" +class nsIUnicharInputStream; + +// Token types +enum nsCSSTokenType { + // A css identifier (e.g. foo) + eCSSToken_Ident = 0, + + // A css at keyword (e.g. @foo) + eCSSToken_AtKeyword = 1, + + // A css number without a percentage or dimension; with percentage; + // without percentage but with a dimension + eCSSToken_Number = 2, + eCSSToken_Percentage = 3, + eCSSToken_Dimension = 4, + + // A css string (e.g. "foo" or 'foo') + eCSSToken_String = 5, + + // Whitespace (e.g. " " or "/* abc */" or "// foo ") + eCSSToken_WhiteSpace = 6, + + // A css symbol (e.g. ':', ';', '+', etc.) + eCSSToken_Symbol = 7, + + eCSSToken_URL = 8, // use getString + eCSSToken_InvalidURL = 9, // doesn't matter + + // A css1 id (e.g. #foo3) + eCSSToken_ID = 10, // use getString() +}; + +struct nsCSSToken { + nsCSSTokenType mType; + nsAutoString mIdent; + float mNumber; + PRInt32 mInteger; + PRUnichar mSymbol; + PRBool mIntegerValid; + + nsCSSToken(); + + PRBool isDimension() { + return (PRBool) + ((eCSSToken_Dimension == mType) || + ((eCSSToken_Number == mType) && (mNumber == 0.0f))); + } +}; + +// CSS Scanner API. Used to tokenize an input stream using the CSS +// forward compatible tokenization rules. This implementation is +// private to this package and is only used internally by the css +// parser. +class nsCSSScanner { + public: + nsCSSScanner(); + ~nsCSSScanner(); + + // Init the scanner. + void Init(nsIUnicharInputStream* aInput); + + // Get the next token. Return nsfalse on EOF or ERROR. aTokenResult + // is filled in with the data for the token. + PRBool Next(PRInt32* aErrorCode, nsCSSToken* aTokenResult); + +protected: + void Close(); + PRInt32 Read(PRInt32* aErrorCode); + PRInt32 Peek(PRInt32* aErrorCode); + void Unread(); + PRBool LookAhead(PRInt32* aErrorCode, PRUnichar aChar); + PRBool EatWhiteSpace(PRInt32* aErrorCode); + PRBool EatNewline(PRInt32* aErrorCode); + + PRInt32 ParseEscape(PRInt32* aErrorCode); + PRBool ParseIdent(PRInt32* aErrorCode, PRInt32 aChar, nsCSSToken* aResult); + PRBool ParseAtKeyword(PRInt32* aErrorCode, PRInt32 aChar, + nsCSSToken* aResult); + PRBool ParseNumber(PRInt32* aErrorCode, PRInt32 aChar, nsCSSToken* aResult); + PRBool ParseID(PRInt32* aErrorCode, PRInt32 aChar, nsCSSToken* aResult); + PRBool ParseString(PRInt32* aErrorCode, PRInt32 aChar, nsCSSToken* aResult); + PRBool ParseEOLComment(PRInt32* aErrorCode, nsCSSToken* aResult); + PRBool ParseCComment(PRInt32* aErrorCode, nsCSSToken* aResult); + + PRBool GatherString(PRInt32* aErrorCode, PRInt32 aStop, + nsString& aString); + PRBool GatherIdent(PRInt32* aErrorCode, PRInt32 aChar, nsString& aIdent); + + nsIUnicharInputStream* mInput; + PRUnichar* mBuffer; + PRInt32 mOffset; + PRInt32 mCount; + PRInt32 mLookAhead; + PRInt32 mLastRead; +}; + +#endif /* nsCSSScanner_h___ */ diff --git a/mozilla/content/html/style/src/nsCSSStruct.cpp b/mozilla/content/html/style/src/nsCSSStruct.cpp new file mode 100644 index 00000000000..2f9d7ac6155 --- /dev/null +++ b/mozilla/content/html/style/src/nsCSSStruct.cpp @@ -0,0 +1,1350 @@ +/* -*- 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 "nsICSSDeclaration.h" +#include "nsString.h" +#include "nsCRT.h" +#include "nsCSSProps.h" +#include "nsCSSPropIDs.h" +#include "nsUnitConversion.h" + +static NS_DEFINE_IID(kCSSFontSID, NS_CSS_FONT_SID); +static NS_DEFINE_IID(kCSSColorSID, NS_CSS_COLOR_SID); +static NS_DEFINE_IID(kCSSTextSID, NS_CSS_TEXT_SID); +static NS_DEFINE_IID(kCSSMarginSID, NS_CSS_MARGIN_SID); +static NS_DEFINE_IID(kCSSPositionSID, NS_CSS_POSITION_SID); +static NS_DEFINE_IID(kCSSListSID, NS_CSS_LIST_SID); +static NS_DEFINE_IID(kICSSDeclarationIID, NS_ICSS_DECLARATION_IID); + + +nsCSSValue::nsCSSValue(void) + : mUnit(eCSSUnit_Null) +{ + mValue.mInt = 0; +} + +nsCSSValue::nsCSSValue(PRInt32 aValue, nsCSSUnit aUnit) + : mUnit(aUnit) +{ + mValue.mInt = aValue; +} + +nsCSSValue::nsCSSValue(float aValue, nsCSSUnit aUnit) + : mUnit(aUnit) +{ + mValue.mFloat = aValue; +} + +nsCSSValue::nsCSSValue(const nsString& aValue) + : mUnit(eCSSUnit_String) +{ + mValue.mString = aValue.ToNewString(); +} + +nsCSSValue::nsCSSValue(nscolor aValue) + : mUnit(eCSSUnit_Color) +{ + mValue.mColor = aValue; +} + +nsCSSValue::nsCSSValue(const nsCSSValue& aCopy) + : mUnit(aCopy.mUnit) +{ + if (eCSSUnit_String == mUnit) { + if (nsnull != aCopy.mValue.mString) { + mValue.mString = (aCopy.mValue.mString)->ToNewString(); + } + else { + mValue.mString = nsnull; + } + } + else if ((eCSSUnit_Absolute <= mUnit) && (mUnit <= eCSSUnit_Enumerated)) { + mValue.mInt = aCopy.mValue.mInt; + } + else if (eCSSUnit_Color == mUnit){ + mValue.mColor = aCopy.mValue.mColor; + } + else { + mValue.mFloat = aCopy.mValue.mFloat; + } +} + +nsCSSValue::~nsCSSValue(void) +{ + Reset(); +} + +nsCSSValue& nsCSSValue::operator=(const nsCSSValue& aCopy) +{ + Reset(); + mUnit = aCopy.mUnit; + if (eCSSUnit_String == mUnit) { + if (nsnull != aCopy.mValue.mString) { + mValue.mString = (aCopy.mValue.mString)->ToNewString(); + } + } + else if ((eCSSUnit_Absolute <= mUnit) && (mUnit <= eCSSUnit_Enumerated)) { + mValue.mInt = aCopy.mValue.mInt; + } + else if (eCSSUnit_Color == mUnit){ + mValue.mColor = aCopy.mValue.mColor; + } + else { + mValue.mFloat = aCopy.mValue.mFloat; + } + return *this; +} + +PRBool nsCSSValue::operator==(const nsCSSValue& aOther) const +{ + if (mUnit == aOther.mUnit) { + if (eCSSUnit_String == mUnit) { + if (nsnull == mValue.mString) { + if (nsnull == aOther.mValue.mString) { + return PR_TRUE; + } + } + else if (nsnull != aOther.mValue.mString) { + return mValue.mString->Equals(*(aOther.mValue.mString)); + } + } + else if ((eCSSUnit_Absolute <= mUnit) && (mUnit < eCSSUnit_Percent)) { + return PRBool(mValue.mInt == aOther.mValue.mInt); + } + else if (eCSSUnit_Color == mUnit){ + return PRBool(mValue.mColor == aOther.mValue.mColor); + } + else { + return PRBool(mValue.mFloat == aOther.mValue.mFloat); + } + } + return PR_FALSE; +} + +nscoord nsCSSValue::GetLengthTwips(void) const +{ + NS_ASSERTION(IsFixedLengthUnit(), "not a fixed length unit"); + + if (IsFixedLengthUnit()) { + switch (mUnit) { + case eCSSUnit_Inch: + return (nscoord)NS_INCHES_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Foot: + return (nscoord)NS_FEET_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Mile: + return (nscoord)NS_MILES_TO_TWIPS(mValue.mFloat); + + case eCSSUnit_Millimeter: + return (nscoord)NS_MILLIMETERS_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Centimeter: + return (nscoord)NS_CENTIMETERS_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Meter: + return (nscoord)NS_METERS_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Kilometer: + return (nscoord)NS_KILOMETERS_TO_TWIPS(mValue.mFloat); + + case eCSSUnit_Point: + return (nscoord)NS_POINTS_TO_TWIPS_FLOAT(mValue.mFloat); + case eCSSUnit_Pica: + return (nscoord)NS_PICAS_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Didot: + return (nscoord)NS_DIDOTS_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Cicero: + return (nscoord)NS_CICEROS_TO_TWIPS(mValue.mFloat); + } + } + return 0; +} + +void nsCSSValue::Reset(void) +{ + if ((eCSSUnit_String == mUnit) && (nsnull != mValue.mString)) { + delete mValue.mString; + } + mUnit = eCSSUnit_Null; + mValue.mInt = 0; +}; + +void nsCSSValue::Set(PRInt32 aValue, nsCSSUnit aUnit) +{ + Reset(); + mUnit = aUnit; + mValue.mInt = aValue; +} + +void nsCSSValue::Set(float aValue, nsCSSUnit aUnit) +{ + Reset(); + mUnit = aUnit; + mValue.mFloat = aValue; +} + +void nsCSSValue::Set(const nsString& aValue) +{ + Reset(); + mUnit = eCSSUnit_String; + mValue.mString = aValue.ToNewString(); +} + +void nsCSSValue::Set(nscolor aValue) +{ + Reset(); + mUnit = eCSSUnit_Color; + mValue.mColor = aValue; +} + +void nsCSSValue::AppendToString(nsString& aBuffer, PRInt32 aPropID) const +{ + if (eCSSUnit_Null == mUnit) { + return; + } + + if (-1 < aPropID) { + aBuffer.Append(nsCSSProps::kNameTable[aPropID].name); + aBuffer.Append(": "); + } + + if (eCSSUnit_String == mUnit) { + if (nsnull != mValue.mString) { + aBuffer.Append('"'); + aBuffer.Append(*(mValue.mString)); + aBuffer.Append('"'); + } + else { + aBuffer.Append("null str"); + } + } + else if ((eCSSUnit_Absolute <= mUnit) && (mUnit <= eCSSUnit_Enumerated)) { + aBuffer.Append(mValue.mInt, 10); + aBuffer.Append("[0x"); + aBuffer.Append(mValue.mInt, 16); + aBuffer.Append(']'); + } + else if (eCSSUnit_Color == mUnit){ + aBuffer.Append("(0x"); + aBuffer.Append(NS_GET_R(mValue.mColor), 16); + aBuffer.Append(" 0x"); + aBuffer.Append(NS_GET_G(mValue.mColor), 16); + aBuffer.Append(" 0x"); + aBuffer.Append(NS_GET_B(mValue.mColor), 16); + aBuffer.Append(" 0x"); + aBuffer.Append(NS_GET_A(mValue.mColor), 16); + aBuffer.Append(')'); + } + else if (eCSSUnit_Percent <= mUnit) { + aBuffer.Append(mValue.mFloat); + } + + switch (mUnit) { + case eCSSUnit_Null: break; + case eCSSUnit_Auto: aBuffer.Append("auto"); break; + case eCSSUnit_String: break; + case eCSSUnit_Absolute: aBuffer.Append("abs"); break; + case eCSSUnit_Enumerated: aBuffer.Append("enum"); break; + case eCSSUnit_Color: aBuffer.Append("rbga"); break; + case eCSSUnit_Percent: aBuffer.Append("%"); break; + case eCSSUnit_Number: aBuffer.Append("#"); break; + case eCSSUnit_Inch: aBuffer.Append("in"); break; + case eCSSUnit_Foot: aBuffer.Append("ft"); break; + case eCSSUnit_Mile: aBuffer.Append("mi"); break; + case eCSSUnit_Millimeter: aBuffer.Append("mm"); break; + case eCSSUnit_Centimeter: aBuffer.Append("cm"); break; + case eCSSUnit_Meter: aBuffer.Append("m"); break; + case eCSSUnit_Kilometer: aBuffer.Append("km"); break; + case eCSSUnit_Point: aBuffer.Append("pt"); break; + case eCSSUnit_Pica: aBuffer.Append("pc"); break; + case eCSSUnit_Didot: aBuffer.Append("dt"); break; + case eCSSUnit_Cicero: aBuffer.Append("cc"); break; + case eCSSUnit_EM: aBuffer.Append("em"); break; + case eCSSUnit_EN: aBuffer.Append("en"); break; + case eCSSUnit_XHeight: aBuffer.Append("ex"); break; + case eCSSUnit_CapHeight: aBuffer.Append("cap"); break; + case eCSSUnit_Pixel: aBuffer.Append("px"); break; + } + aBuffer.Append(' '); +} + +void nsCSSValue::ToString(nsString& aBuffer, PRInt32 aPropID) const +{ + aBuffer.SetLength(0); + AppendToString(aBuffer, aPropID); +} + +const nsID& nsCSSFont::GetID(void) +{ + return kCSSFontSID; +} + +void nsCSSFont::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + nsAutoString buffer; + + mFamily.AppendToString(buffer, PROP_FONT_FAMILY); + mStyle.AppendToString(buffer, PROP_FONT_STYLE); + mVariant.AppendToString(buffer, PROP_FONT_VARIANT); + mWeight.AppendToString(buffer, PROP_FONT_WEIGHT); + mSize.AppendToString(buffer, PROP_FONT_SIZE); + fputs(buffer, out); +} + + +const nsID& nsCSSColor::GetID(void) +{ + return kCSSColorSID; +} + +void nsCSSColor::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + nsAutoString buffer; + + mColor.AppendToString(buffer, PROP_COLOR); + mBackColor.AppendToString(buffer, PROP_BACKGROUND_COLOR); + mBackImage.AppendToString(buffer, PROP_BACKGROUND_IMAGE); + mBackRepeat.AppendToString(buffer, PROP_BACKGROUND_REPEAT); + mBackAttachment.AppendToString(buffer, PROP_BACKGROUND_ATTACHMENT); + mBackPositionX.AppendToString(buffer, PROP_BACKGROUND_X_POSITION); + mBackPositionY.AppendToString(buffer, PROP_BACKGROUND_Y_POSITION); + mBackFilter.AppendToString(buffer, PROP_BACKGROUND_FILTER); + fputs(buffer, out); +} + +const nsID& nsCSSText::GetID(void) +{ + return kCSSTextSID; +} + +void nsCSSText::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + nsAutoString buffer; + + mWordSpacing.AppendToString(buffer, PROP_WORD_SPACING); + mLetterSpacing.AppendToString(buffer, PROP_LETTER_SPACING); + mDecoration.AppendToString(buffer, PROP_TEXT_DECORATION); + mVertAlign.AppendToString(buffer, PROP_VERTICAL_ALIGN); + mTransform.AppendToString(buffer, PROP_TEXT_TRANSFORM); + mHorzAlign.AppendToString(buffer, PROP_TEXT_ALIGN); + mIndent.AppendToString(buffer, PROP_TEXT_INDENT); + mLineHeight.AppendToString(buffer, PROP_LINE_HEIGHT); + mWhiteSpace.AppendToString(buffer, PROP_WHITE_SPACE); + fputs(buffer, out); +} + +void nsCSSRect::List(FILE* out, PRInt32 aPropID, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + nsAutoString buffer; + + if (-1 < aPropID) { + buffer.Append(nsCSSProps::kNameTable[aPropID].name); + buffer.Append(": "); + } + + mTop.AppendToString(buffer); + mRight.AppendToString(buffer); + mBottom.AppendToString(buffer); + mLeft.AppendToString(buffer); + fputs(buffer, out); +} + +nsCSSMargin::nsCSSMargin(void) + : mMargin(nsnull), mPadding(nsnull), mBorder(nsnull), mColor(nsnull), mStyle(nsnull) +{ +} + +nsCSSMargin::~nsCSSMargin(void) +{ + if (nsnull != mMargin) { + delete mMargin; + } + if (nsnull != mPadding) { + delete mPadding; + } + if (nsnull != mBorder) { + delete mBorder; + } + if (nsnull != mColor) { + delete mColor; + } + if (nsnull != mStyle) { + delete mStyle; + } +} + +const nsID& nsCSSMargin::GetID(void) +{ + return kCSSMarginSID; +} + +void nsCSSMargin::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + if (nsnull != mMargin) { + mMargin->List(out, PROP_MARGIN, aIndent); + } + if (nsnull != mPadding) { + mPadding->List(out, PROP_PADDING, aIndent); + } + if (nsnull != mBorder) { + mBorder->List(out, PROP_BORDER_WIDTH, aIndent); + } + if (nsnull != mColor) { + mColor->List(out, PROP_BORDER_COLOR, aIndent); + } + if (nsnull != mStyle) { + mStyle->List(out, PROP_BORDER_STYLE, aIndent); + } +} + +nsCSSPosition::nsCSSPosition(void) + : mClip(nsnull) +{ +} + +nsCSSPosition::~nsCSSPosition(void) +{ + if (nsnull != mClip) { + delete mClip; + } +} + +const nsID& nsCSSPosition::GetID(void) +{ + return kCSSPositionSID; +} + +void nsCSSPosition::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + nsAutoString buffer; + + mPosition.AppendToString(buffer, PROP_POSITION); + mWidth.AppendToString(buffer, PROP_WIDTH); + mHeight.AppendToString(buffer, PROP_HEIGHT); + mLeft.AppendToString(buffer, PROP_LEFT); + mTop.AppendToString(buffer, PROP_TOP); + fputs(buffer, out); + if (nsnull != mClip) { + mClip->List(out, PROP_CLIP); + } + buffer.SetLength(0); + mOverflow.AppendToString(buffer, PROP_OVERFLOW); + mZIndex.AppendToString(buffer, PROP_OVERFLOW); + mVisibility.AppendToString(buffer, PROP_VISIBILITY); + mFloat.AppendToString(buffer, PROP_FLOAT); + mClear.AppendToString(buffer, PROP_CLEAR); + mDisplay.AppendToString(buffer, PROP_DISPLAY); + mFilter.AppendToString(buffer, PROP_FILTER); + fputs(buffer, out); +} + +const nsID& nsCSSList::GetID(void) +{ + return kCSSListSID; +} + +void nsCSSList::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + nsAutoString buffer; + + mType.AppendToString(buffer, PROP_LIST_STYLE_TYPE); + mImage.AppendToString(buffer, PROP_LIST_STYLE_IMAGE); + mPosition.AppendToString(buffer, PROP_LIST_STYLE_POSITION); + fputs(buffer, out); +} + + + +class CSSDeclarationImpl : public nsICSSDeclaration { +public: + void* operator new(size_t size); + + CSSDeclarationImpl(void); + ~CSSDeclarationImpl(void); + + NS_DECL_ISUPPORTS + + nsresult GetData(const nsID& aSID, nsCSSStruct** aData); + nsresult EnsureData(const nsID& aSID, nsCSSStruct** aData); + + nsresult AddValue(const char* aProperty, const nsCSSValue& aValue); + nsresult AddValue(PRInt32 aProperty, const nsCSSValue& aValue); + nsresult GetValue(const char* aProperty, nsCSSValue& aValue); + nsresult GetValue(PRInt32 aProperty, nsCSSValue& aValue); + + void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + +private: + CSSDeclarationImpl(const CSSDeclarationImpl& aCopy); + CSSDeclarationImpl& operator=(const CSSDeclarationImpl& aCopy); + PRBool operator==(const CSSDeclarationImpl& aCopy) const; + +protected: + nsCSSFont* mFont; + nsCSSColor* mColor; + nsCSSText* mText; + nsCSSMargin* mMargin; + nsCSSPosition* mPosition; + nsCSSList* mList; +}; + +void* CSSDeclarationImpl::operator new(size_t size) +{ + void* result = new char[size]; + + nsCRT::zero(result, size); + return result; +} + +CSSDeclarationImpl::CSSDeclarationImpl(void) +{ + NS_INIT_REFCNT(); +} + +CSSDeclarationImpl::~CSSDeclarationImpl(void) +{ + if (nsnull != mFont) { + delete mFont; + } + if (nsnull != mColor) { + delete mColor; + } + if (nsnull != mText) { + delete mText; + } + if (nsnull != mMargin) { + delete mMargin; + } + if (nsnull != mPosition) { + delete mPosition; + } + if (nsnull != mList) { + delete mList; + } +} + +NS_IMPL_ISUPPORTS(CSSDeclarationImpl, kICSSDeclarationIID); + +nsresult CSSDeclarationImpl::GetData(const nsID& aSID, nsCSSStruct** aDataPtr) +{ + if (nsnull == aDataPtr) { + return NS_ERROR_NULL_POINTER; + } + + if (aSID.Equals(kCSSFontSID)) { + *aDataPtr = mFont; + } + else if (aSID.Equals(kCSSColorSID)) { + *aDataPtr = mColor; + } + else if (aSID.Equals(kCSSTextSID)) { + *aDataPtr = mText; + } + else if (aSID.Equals(kCSSMarginSID)) { + *aDataPtr = mMargin; + } + else if (aSID.Equals(kCSSPositionSID)) { + *aDataPtr = mPosition; + } + else if (aSID.Equals(kCSSListSID)) { + *aDataPtr = mList; + } + else { + return NS_NOINTERFACE; + } + return NS_OK; +} + +nsresult CSSDeclarationImpl::EnsureData(const nsID& aSID, nsCSSStruct** aDataPtr) +{ + if (nsnull == aDataPtr) { + return NS_ERROR_NULL_POINTER; + } + + if (aSID.Equals(kCSSFontSID)) { + if (nsnull == mFont) { + mFont = new nsCSSFont(); + } + *aDataPtr = mFont; + } + else if (aSID.Equals(kCSSColorSID)) { + if (nsnull == mColor) { + mColor = new nsCSSColor(); + } + *aDataPtr = mColor; + } + else if (aSID.Equals(kCSSTextSID)) { + if (nsnull == mText) { + mText = new nsCSSText(); + } + *aDataPtr = mText; + } + else if (aSID.Equals(kCSSMarginSID)) { + if (nsnull == mMargin) { + mMargin = new nsCSSMargin(); + } + *aDataPtr = mMargin; + } + else if (aSID.Equals(kCSSPositionSID)) { + if (nsnull == mPosition) { + mPosition = new nsCSSPosition(); + } + *aDataPtr = mPosition; + } + else if (aSID.Equals(kCSSListSID)) { + if (nsnull == mList) { + mList = new nsCSSList(); + } + *aDataPtr = mList; + } + else { + return NS_NOINTERFACE; + } + if (nsnull == *aDataPtr) { + return NS_ERROR_OUT_OF_MEMORY; + } + return NS_OK; +} + +nsresult CSSDeclarationImpl::AddValue(const char* aProperty, const nsCSSValue& aValue) +{ + return AddValue(nsCSSProps::LookupName(aProperty), aValue); +} + +nsresult CSSDeclarationImpl::AddValue(PRInt32 aProperty, const nsCSSValue& aValue) +{ + nsresult result = NS_OK; + + switch (aProperty) { + // nsCSSFont + case PROP_FONT_FAMILY: + case PROP_FONT_STYLE: + case PROP_FONT_VARIANT: + case PROP_FONT_WEIGHT: + case PROP_FONT_SIZE: + if (nsnull == mFont) { + mFont = new nsCSSFont(); + } + if (nsnull != mFont) { + switch (aProperty) { + case PROP_FONT_FAMILY: mFont->mFamily = aValue; break; + case PROP_FONT_STYLE: mFont->mStyle = aValue; break; + case PROP_FONT_VARIANT: mFont->mVariant = aValue; break; + case PROP_FONT_WEIGHT: mFont->mWeight = aValue; break; + case PROP_FONT_SIZE: mFont->mSize = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + // nsCSSColor + case PROP_COLOR: + case PROP_BACKGROUND_COLOR: + case PROP_BACKGROUND_IMAGE: + case PROP_BACKGROUND_REPEAT: + case PROP_BACKGROUND_ATTACHMENT: + case PROP_BACKGROUND_X_POSITION: + case PROP_BACKGROUND_Y_POSITION: + case PROP_BACKGROUND_FILTER: + if (nsnull == mColor) { + mColor = new nsCSSColor(); + } + if (nsnull != mColor) { + switch (aProperty) { + case PROP_COLOR: mColor->mColor = aValue; break; + case PROP_BACKGROUND_COLOR: mColor->mBackColor = aValue; break; + case PROP_BACKGROUND_IMAGE: mColor->mBackImage = aValue; break; + case PROP_BACKGROUND_REPEAT: mColor->mBackRepeat = aValue; break; + case PROP_BACKGROUND_ATTACHMENT: mColor->mBackAttachment = aValue; break; + case PROP_BACKGROUND_X_POSITION: mColor->mBackPositionX = aValue; break; + case PROP_BACKGROUND_Y_POSITION: mColor->mBackPositionY = aValue; break; + case PROP_BACKGROUND_FILTER: mColor->mBackFilter = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + // nsCSSText + case PROP_WORD_SPACING: + case PROP_LETTER_SPACING: + case PROP_TEXT_DECORATION: + case PROP_VERTICAL_ALIGN: + case PROP_TEXT_TRANSFORM: + case PROP_TEXT_ALIGN: + case PROP_TEXT_INDENT: + case PROP_LINE_HEIGHT: + case PROP_WHITE_SPACE: + if (nsnull == mText) { + mText = new nsCSSText(); + } + if (nsnull != mText) { + switch (aProperty) { + case PROP_WORD_SPACING: mText->mWordSpacing = aValue; break; + case PROP_LETTER_SPACING: mText->mLetterSpacing = aValue; break; + case PROP_TEXT_DECORATION: mText->mDecoration = aValue; break; + case PROP_VERTICAL_ALIGN: mText->mVertAlign = aValue; break; + case PROP_TEXT_TRANSFORM: mText->mTransform = aValue; break; + case PROP_TEXT_ALIGN: mText->mHorzAlign = aValue; break; + case PROP_TEXT_INDENT: mText->mIndent = aValue; break; + case PROP_LINE_HEIGHT: mText->mLineHeight = aValue; break; + case PROP_WHITE_SPACE: mText->mWhiteSpace = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + // nsCSSMargin + case PROP_MARGIN_TOP: + case PROP_MARGIN_RIGHT: + case PROP_MARGIN_BOTTOM: + case PROP_MARGIN_LEFT: + if (nsnull == mMargin) { + mMargin = new nsCSSMargin(); + } + if (nsnull != mMargin) { + if (nsnull == mMargin->mMargin) { + mMargin->mMargin = new nsCSSRect(); + } + if (nsnull != mMargin->mMargin) { + switch (aProperty) { + case PROP_MARGIN_TOP: mMargin->mMargin->mTop = aValue; break; + case PROP_MARGIN_RIGHT: mMargin->mMargin->mRight = aValue; break; + case PROP_MARGIN_BOTTOM: mMargin->mMargin->mBottom = aValue; break; + case PROP_MARGIN_LEFT: mMargin->mMargin->mLeft = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + case PROP_PADDING_TOP: + case PROP_PADDING_RIGHT: + case PROP_PADDING_BOTTOM: + case PROP_PADDING_LEFT: + if (nsnull == mMargin) { + mMargin = new nsCSSMargin(); + } + if (nsnull != mMargin) { + if (nsnull == mMargin->mPadding) { + mMargin->mPadding = new nsCSSRect(); + } + if (nsnull != mMargin->mPadding) { + switch (aProperty) { + case PROP_PADDING_TOP: mMargin->mPadding->mTop = aValue; break; + case PROP_PADDING_RIGHT: mMargin->mPadding->mRight = aValue; break; + case PROP_PADDING_BOTTOM: mMargin->mPadding->mBottom = aValue; break; + case PROP_PADDING_LEFT: mMargin->mPadding->mLeft = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + case PROP_BORDER_TOP_WIDTH: + case PROP_BORDER_RIGHT_WIDTH: + case PROP_BORDER_BOTTOM_WIDTH: + case PROP_BORDER_LEFT_WIDTH: + if (nsnull == mMargin) { + mMargin = new nsCSSMargin(); + } + if (nsnull != mMargin) { + if (nsnull == mMargin->mBorder) { + mMargin->mBorder = new nsCSSRect(); + } + if (nsnull != mMargin->mBorder) { + switch (aProperty) { + case PROP_BORDER_TOP_WIDTH: mMargin->mBorder->mTop = aValue; break; + case PROP_BORDER_RIGHT_WIDTH: mMargin->mBorder->mRight = aValue; break; + case PROP_BORDER_BOTTOM_WIDTH: mMargin->mBorder->mBottom = aValue; break; + case PROP_BORDER_LEFT_WIDTH: mMargin->mBorder->mLeft = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + case PROP_BORDER_TOP_COLOR: + case PROP_BORDER_RIGHT_COLOR: + case PROP_BORDER_BOTTOM_COLOR: + case PROP_BORDER_LEFT_COLOR: + if (nsnull == mMargin) { + mMargin = new nsCSSMargin(); + } + if (nsnull != mMargin) { + if (nsnull == mMargin->mColor) { + mMargin->mColor = new nsCSSRect(); + } + if (nsnull != mMargin->mColor) { + switch (aProperty) { + case PROP_BORDER_TOP_COLOR: mMargin->mColor->mTop = aValue; break; + case PROP_BORDER_RIGHT_COLOR: mMargin->mColor->mRight = aValue; break; + case PROP_BORDER_BOTTOM_COLOR: mMargin->mColor->mBottom = aValue; break; + case PROP_BORDER_LEFT_COLOR: mMargin->mColor->mLeft = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + case PROP_BORDER_TOP_STYLE: + case PROP_BORDER_RIGHT_STYLE: + case PROP_BORDER_BOTTOM_STYLE: + case PROP_BORDER_LEFT_STYLE: + if (nsnull == mMargin) { + mMargin = new nsCSSMargin(); + } + if (nsnull != mMargin) { + if (nsnull == mMargin->mStyle) { + mMargin->mStyle = new nsCSSRect(); + } + if (nsnull != mMargin->mStyle) { + switch (aProperty) { + case PROP_BORDER_TOP_STYLE: mMargin->mStyle->mTop = aValue; break; + case PROP_BORDER_RIGHT_STYLE: mMargin->mStyle->mRight = aValue; break; + case PROP_BORDER_BOTTOM_STYLE: mMargin->mStyle->mBottom = aValue; break; + case PROP_BORDER_LEFT_STYLE: mMargin->mStyle->mLeft = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + // nsCSSPosition + case PROP_POSITION: + case PROP_WIDTH: + case PROP_HEIGHT: + case PROP_LEFT: + case PROP_TOP: + case PROP_OVERFLOW: + case PROP_Z_INDEX: + case PROP_VISIBILITY: + case PROP_FLOAT: + case PROP_CLEAR: + case PROP_DISPLAY: + case PROP_FILTER: + if (nsnull == mPosition) { + mPosition = new nsCSSPosition(); + } + if (nsnull != mPosition) { + switch (aProperty) { + case PROP_POSITION: mPosition->mPosition = aValue; break; + case PROP_WIDTH: mPosition->mWidth = aValue; break; + case PROP_HEIGHT: mPosition->mHeight = aValue; break; + case PROP_LEFT: mPosition->mLeft = aValue; break; + case PROP_TOP: mPosition->mTop = aValue; break; + case PROP_OVERFLOW: mPosition->mOverflow = aValue; break; + case PROP_Z_INDEX: mPosition->mZIndex = aValue; break; + case PROP_VISIBILITY: mPosition->mVisibility = aValue; break; + case PROP_FLOAT: mPosition->mFloat = aValue; break; + case PROP_CLEAR: mPosition->mClear = aValue; break; + case PROP_DISPLAY: mPosition->mDisplay = aValue; break; + case PROP_FILTER: mPosition->mFilter = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + case PROP_CLIP_TOP: + case PROP_CLIP_RIGHT: + case PROP_CLIP_BOTTOM: + case PROP_CLIP_LEFT: + if (nsnull == mPosition) { + mPosition = new nsCSSPosition(); + } + if (nsnull != mPosition) { + if (nsnull == mPosition->mClip) { + mPosition->mClip = new nsCSSRect(); + } + if (nsnull != mPosition->mClip) { + switch(aProperty) { + case PROP_CLIP_TOP: mPosition->mClip->mTop = aValue; break; + case PROP_CLIP_RIGHT: mPosition->mClip->mRight = aValue; break; + case PROP_CLIP_BOTTOM: mPosition->mClip->mBottom = aValue; break; + case PROP_CLIP_LEFT: mPosition->mClip->mLeft = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + // nsCSSList + case PROP_LIST_STYLE_TYPE: + case PROP_LIST_STYLE_IMAGE: + case PROP_LIST_STYLE_POSITION: + if (nsnull == mList) { + mList = new nsCSSList(); + } + if (nsnull != mList) { + switch (aProperty) { + case PROP_LIST_STYLE_TYPE: mList->mType = aValue; break; + case PROP_LIST_STYLE_IMAGE: mList->mImage = aValue; break; + case PROP_LIST_STYLE_POSITION: mList->mPosition = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + case PROP_BACKGROUND: + case PROP_BORDER: + case PROP_CLIP: + case PROP_FONT: + case PROP_LIST_STYLE: + case PROP_MARGIN: + case PROP_PADDING: + case PROP_BACKGROUND_POSITION: + case PROP_BORDER_TOP: + case PROP_BORDER_RIGHT: + case PROP_BORDER_BOTTOM: + case PROP_BORDER_LEFT: + case PROP_BORDER_COLOR: + case PROP_BORDER_STYLE: + case PROP_BORDER_WIDTH: + NS_ERROR("can't query for shorthand properties"); + default: + result = NS_ERROR_ILLEGAL_VALUE; + break; + } + return result; +} + +nsresult CSSDeclarationImpl::GetValue(const char* aProperty, nsCSSValue& aValue) +{ + return GetValue(nsCSSProps::LookupName(aProperty), aValue); +} + +nsresult CSSDeclarationImpl::GetValue(PRInt32 aProperty, nsCSSValue& aValue) +{ + nsresult result = NS_OK; + + switch (aProperty) { + // nsCSSFont + case PROP_FONT_FAMILY: + case PROP_FONT_STYLE: + case PROP_FONT_VARIANT: + case PROP_FONT_WEIGHT: + case PROP_FONT_SIZE: + if (nsnull != mFont) { + switch (aProperty) { + case PROP_FONT_FAMILY: aValue = mFont->mFamily; break; + case PROP_FONT_STYLE: aValue = mFont->mStyle; break; + case PROP_FONT_VARIANT: aValue = mFont->mVariant; break; + case PROP_FONT_WEIGHT: aValue = mFont->mWeight; break; + case PROP_FONT_SIZE: aValue = mFont->mSize; break; + } + } + else { + aValue.Reset(); + } + break; + + // nsCSSColor + case PROP_COLOR: + case PROP_BACKGROUND_COLOR: + case PROP_BACKGROUND_IMAGE: + case PROP_BACKGROUND_REPEAT: + case PROP_BACKGROUND_ATTACHMENT: + case PROP_BACKGROUND_X_POSITION: + case PROP_BACKGROUND_Y_POSITION: + case PROP_BACKGROUND_FILTER: + if (nsnull != mColor) { + switch (aProperty) { + case PROP_COLOR: aValue = mColor->mColor; break; + case PROP_BACKGROUND_COLOR: aValue = mColor->mBackColor; break; + case PROP_BACKGROUND_IMAGE: aValue = mColor->mBackImage; break; + case PROP_BACKGROUND_REPEAT: aValue = mColor->mBackRepeat; break; + case PROP_BACKGROUND_ATTACHMENT: aValue = mColor->mBackAttachment; break; + case PROP_BACKGROUND_X_POSITION: aValue = mColor->mBackPositionX; break; + case PROP_BACKGROUND_Y_POSITION: aValue = mColor->mBackPositionY; break; + case PROP_BACKGROUND_FILTER: aValue = mColor->mBackFilter; break; + } + } + else { + aValue.Reset(); + } + break; + + // nsCSSText + case PROP_WORD_SPACING: + case PROP_LETTER_SPACING: + case PROP_TEXT_DECORATION: + case PROP_VERTICAL_ALIGN: + case PROP_TEXT_TRANSFORM: + case PROP_TEXT_ALIGN: + case PROP_TEXT_INDENT: + case PROP_LINE_HEIGHT: + case PROP_WHITE_SPACE: + if (nsnull != mText) { + switch (aProperty) { + case PROP_WORD_SPACING: aValue = mText->mWordSpacing; break; + case PROP_LETTER_SPACING: aValue = mText->mLetterSpacing; break; + case PROP_TEXT_DECORATION: aValue = mText->mDecoration; break; + case PROP_VERTICAL_ALIGN: aValue = mText->mVertAlign; break; + case PROP_TEXT_TRANSFORM: aValue = mText->mTransform; break; + case PROP_TEXT_ALIGN: aValue = mText->mHorzAlign; break; + case PROP_TEXT_INDENT: aValue = mText->mIndent; break; + case PROP_LINE_HEIGHT: aValue = mText->mLineHeight; break; + case PROP_WHITE_SPACE: aValue = mText->mWhiteSpace; break; + } + } + else { + aValue.Reset(); + } + break; + + // nsCSSMargin + case PROP_MARGIN_TOP: + case PROP_MARGIN_RIGHT: + case PROP_MARGIN_BOTTOM: + case PROP_MARGIN_LEFT: + if ((nsnull != mMargin) && (nsnull != mMargin->mMargin)) { + switch (aProperty) { + case PROP_MARGIN_TOP: aValue = mMargin->mMargin->mTop; break; + case PROP_MARGIN_RIGHT: aValue = mMargin->mMargin->mRight; break; + case PROP_MARGIN_BOTTOM: aValue = mMargin->mMargin->mBottom; break; + case PROP_MARGIN_LEFT: aValue = mMargin->mMargin->mLeft; break; + } + } + else { + aValue.Reset(); + } + break; + + case PROP_PADDING_TOP: + case PROP_PADDING_RIGHT: + case PROP_PADDING_BOTTOM: + case PROP_PADDING_LEFT: + if ((nsnull != mMargin) && (nsnull != mMargin->mPadding)) { + switch (aProperty) { + case PROP_PADDING_TOP: aValue = mMargin->mPadding->mTop; break; + case PROP_PADDING_RIGHT: aValue = mMargin->mPadding->mRight; break; + case PROP_PADDING_BOTTOM: aValue = mMargin->mPadding->mBottom; break; + case PROP_PADDING_LEFT: aValue = mMargin->mPadding->mLeft; break; + } + } + else { + aValue.Reset(); + } + break; + + case PROP_BORDER_TOP_WIDTH: + case PROP_BORDER_RIGHT_WIDTH: + case PROP_BORDER_BOTTOM_WIDTH: + case PROP_BORDER_LEFT_WIDTH: + if ((nsnull != mMargin) && (nsnull != mMargin->mBorder)) { + switch (aProperty) { + case PROP_BORDER_TOP_WIDTH: aValue = mMargin->mBorder->mTop; break; + case PROP_BORDER_RIGHT_WIDTH: aValue = mMargin->mBorder->mRight; break; + case PROP_BORDER_BOTTOM_WIDTH: aValue = mMargin->mBorder->mBottom; break; + case PROP_BORDER_LEFT_WIDTH: aValue = mMargin->mBorder->mLeft; break; + } + } + else { + aValue.Reset(); + } + break; + + case PROP_BORDER_TOP_COLOR: + case PROP_BORDER_RIGHT_COLOR: + case PROP_BORDER_BOTTOM_COLOR: + case PROP_BORDER_LEFT_COLOR: + if ((nsnull != mMargin) && (nsnull != mMargin->mColor)) { + switch (aProperty) { + case PROP_BORDER_TOP_COLOR: aValue = mMargin->mColor->mTop; break; + case PROP_BORDER_RIGHT_COLOR: aValue = mMargin->mColor->mRight; break; + case PROP_BORDER_BOTTOM_COLOR: aValue = mMargin->mColor->mBottom; break; + case PROP_BORDER_LEFT_COLOR: aValue = mMargin->mColor->mLeft; break; + } + } + else { + aValue.Reset(); + } + break; + + case PROP_BORDER_TOP_STYLE: + case PROP_BORDER_RIGHT_STYLE: + case PROP_BORDER_BOTTOM_STYLE: + case PROP_BORDER_LEFT_STYLE: + if ((nsnull != mMargin) && (nsnull != mMargin->mStyle)) { + switch (aProperty) { + case PROP_BORDER_TOP_STYLE: aValue = mMargin->mStyle->mTop; break; + case PROP_BORDER_RIGHT_STYLE: aValue = mMargin->mStyle->mRight; break; + case PROP_BORDER_BOTTOM_STYLE: aValue = mMargin->mStyle->mBottom; break; + case PROP_BORDER_LEFT_STYLE: aValue = mMargin->mStyle->mLeft; break; + } + } + else { + aValue.Reset(); + } + break; + + // nsCSSPosition + case PROP_POSITION: + case PROP_WIDTH: + case PROP_HEIGHT: + case PROP_LEFT: + case PROP_TOP: + case PROP_OVERFLOW: + case PROP_Z_INDEX: + case PROP_VISIBILITY: + case PROP_FLOAT: + case PROP_CLEAR: + case PROP_DISPLAY: + case PROP_FILTER: + if (nsnull != mPosition) { + switch (aProperty) { + case PROP_POSITION: aValue = mPosition->mPosition; break; + case PROP_WIDTH: aValue = mPosition->mWidth; break; + case PROP_HEIGHT: aValue = mPosition->mHeight; break; + case PROP_LEFT: aValue = mPosition->mLeft; break; + case PROP_TOP: aValue = mPosition->mTop; break; + case PROP_OVERFLOW: aValue = mPosition->mOverflow; break; + case PROP_Z_INDEX: aValue = mPosition->mZIndex; break; + case PROP_VISIBILITY: aValue = mPosition->mVisibility; break; + case PROP_FLOAT: aValue = mPosition->mFloat; break; + case PROP_CLEAR: aValue = mPosition->mClear; break; + case PROP_DISPLAY: aValue = mPosition->mDisplay; break; + case PROP_FILTER: aValue = mPosition->mFilter; break; + } + } + else { + aValue.Reset(); + } + break; + + case PROP_CLIP_TOP: + case PROP_CLIP_RIGHT: + case PROP_CLIP_BOTTOM: + case PROP_CLIP_LEFT: + if ((nsnull != mPosition) && (nsnull != mPosition->mClip)) { + switch(aProperty) { + case PROP_CLIP_TOP: aValue = mPosition->mClip->mTop; break; + case PROP_CLIP_RIGHT: aValue = mPosition->mClip->mRight; break; + case PROP_CLIP_BOTTOM: aValue = mPosition->mClip->mBottom; break; + case PROP_CLIP_LEFT: aValue = mPosition->mClip->mLeft; break; + } + } + else { + aValue.Reset(); + } + break; + + // nsCSSList + case PROP_LIST_STYLE_TYPE: + case PROP_LIST_STYLE_IMAGE: + case PROP_LIST_STYLE_POSITION: + if (nsnull != mList) { + switch (aProperty) { + case PROP_LIST_STYLE_TYPE: aValue = mList->mType; break; + case PROP_LIST_STYLE_IMAGE: aValue = mList->mImage; break; + case PROP_LIST_STYLE_POSITION: aValue = mList->mPosition; break; + } + } + else { + aValue.Reset(); + } + break; + + case PROP_BACKGROUND: + case PROP_BORDER: + case PROP_CLIP: + case PROP_FONT: + case PROP_LIST_STYLE: + case PROP_MARGIN: + case PROP_PADDING: + case PROP_BACKGROUND_POSITION: + case PROP_BORDER_TOP: + case PROP_BORDER_RIGHT: + case PROP_BORDER_BOTTOM: + case PROP_BORDER_LEFT: + case PROP_BORDER_COLOR: + case PROP_BORDER_STYLE: + case PROP_BORDER_WIDTH: + NS_ERROR("can't query for shorthand properties"); + default: + result = NS_ERROR_ILLEGAL_VALUE; + break; + } + return result; +} + +void CSSDeclarationImpl::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + fputs("{ ", out); + + if (nsnull != mFont) { + mFont->List(out); + } + if (nsnull != mColor) { + mColor->List(out); + } + if (nsnull != mText) { + mText->List(out); + } + if (nsnull != mMargin) { + mMargin->List(out); + } + if (nsnull != mPosition) { + mPosition->List(out); + } + if (nsnull != mList) { + mList->List(out); + } + + fputs("}", out); +} + +NS_HTML nsresult + NS_NewCSSDeclaration(nsICSSDeclaration** aInstancePtrResult) +{ + if (aInstancePtrResult == nsnull) { + return NS_ERROR_NULL_POINTER; + } + + CSSDeclarationImpl *it = new CSSDeclarationImpl(); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(kICSSDeclarationIID, (void **) aInstancePtrResult); +} + + +/* +font +=========== + +'font-family', string (list) +'font-style', enum +'font-variant' enum (ie: small caps) +'font-weight' enum +'font-size' abs, pct, enum, +-1 + + +color/background +============= + +color: color +background-color: color +background-image: url(string) +background-repeat: enum +background-attachment: enum +background-position-x -y: abs, pct, enum (left/top center right/bottom (pct?)) + + + +text +======= +word-spacing: abs, "normal" +letter-spacing: abs, "normal" +text-decoration: enum +vertical-align: enum, pct +text-transform: enum +text-align: enum +text-indent: abs, pct +line-height: "normal", abs, pct, number-factor +white-space: enum + +margin +======= +margin-top -right -bottom -left: "auto", abs, pct +padding-top -right -bottom -left: abs, pct +border-top -right -bottom -left-width: enum, abs +border-top -right -bottom -left-color: color +border-top -right -bottom -left-style: enum + +size +======= +position: enum +width: abs, pct, "auto" +height: abs, pct, "auto" +left: abs, pct, "auto" +top: abs, pct, "auto" +clip: shape, "auto" (shape: rect - abs, auto) +overflow: enum +z-index: int, auto +visibity: enum + +float: enum +clear: enum + +display: enum + +filter: string + +list +======== +list-style-type: enum +list-style-image: url, "none" +list-style-position: enum (bool? in/out) + +*/ + + + diff --git a/mozilla/content/html/style/src/nsCSSStyleRule.cpp b/mozilla/content/html/style/src/nsCSSStyleRule.cpp new file mode 100644 index 00000000000..c19372058b9 --- /dev/null +++ b/mozilla/content/html/style/src/nsCSSStyleRule.cpp @@ -0,0 +1,683 @@ +/* -*- 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 "nsICSSStyleRule.h" +#include "nsICSSDeclaration.h" +#include "nsIStyleContext.h" +#include "nsIPresContext.h" +#include "nsIArena.h" +#include "nsIAtom.h" +#include "nsCRT.h" +#include "nsString.h" +#include "nsStyleConsts.h" +#include "nsUnitConversion.h" + +static NS_DEFINE_IID(kIStyleRuleIID, NS_ISTYLE_RULE_IID); +static NS_DEFINE_IID(kICSSDeclarationIID, NS_ICSS_DECLARATION_IID); +static NS_DEFINE_IID(kICSSStyleRuleIID, NS_ICSS_STYLE_RULE_IID); + +static NS_DEFINE_IID(kStyleFontSID, NS_STYLEFONT_SID); +static NS_DEFINE_IID(kStyleColorSID, NS_STYLECOLOR_SID); +static NS_DEFINE_IID(kStyleListSID, NS_STYLELIST_SID); + +static NS_DEFINE_IID(kCSSFontSID, NS_CSS_FONT_SID); +static NS_DEFINE_IID(kCSSColorSID, NS_CSS_COLOR_SID); +static NS_DEFINE_IID(kCSSTextSID, NS_CSS_TEXT_SID); +static NS_DEFINE_IID(kCSSMarginSID, NS_CSS_MARGIN_SID); +static NS_DEFINE_IID(kCSSPositionSID, NS_CSS_POSITION_SID); +static NS_DEFINE_IID(kCSSListSID, NS_CSS_LIST_SID); + + +// -- nsCSSSelector ------------------------------- + +nsCSSSelector::nsCSSSelector() + : mTag(nsnull), mID(nsnull), mClass(nsnull), mPseudoClass(nsnull), + mNext(nsnull) +{ +} + +nsCSSSelector::nsCSSSelector(nsIAtom* aTag, nsIAtom* aID, nsIAtom* aClass, nsIAtom* aPseudoClass) + : mTag(aTag), mID(aID), mClass(aClass), mPseudoClass(aPseudoClass), + mNext(nsnull) +{ + NS_IF_ADDREF(mTag); + NS_IF_ADDREF(mID); + NS_IF_ADDREF(mClass); + NS_IF_ADDREF(mPseudoClass); +} + +nsCSSSelector::nsCSSSelector(const nsCSSSelector& aCopy) + : mTag(aCopy.mTag), mID(aCopy.mID), mClass(aCopy.mClass), mPseudoClass(aCopy.mPseudoClass), + mNext(nsnull) +{ // implmented to support extension to CSS2 (when we have to copy the array) + NS_IF_ADDREF(mTag); + NS_IF_ADDREF(mID); + NS_IF_ADDREF(mClass); + NS_IF_ADDREF(mPseudoClass); +} + +nsCSSSelector::~nsCSSSelector() +{ + NS_IF_RELEASE(mTag); + NS_IF_RELEASE(mID); + NS_IF_RELEASE(mClass); + NS_IF_RELEASE(mPseudoClass); +} + +nsCSSSelector& nsCSSSelector::operator=(const nsCSSSelector& aCopy) +{ + NS_IF_RELEASE(mTag); + NS_IF_RELEASE(mID); + NS_IF_RELEASE(mClass); + NS_IF_RELEASE(mPseudoClass); + mTag = aCopy.mTag; + mID = aCopy.mID; + mClass = aCopy.mClass; + mPseudoClass = aCopy.mPseudoClass; + NS_IF_ADDREF(mTag); + NS_IF_ADDREF(mID); + NS_IF_ADDREF(mClass); + NS_IF_ADDREF(mPseudoClass); + return *this; +} + +PRBool nsCSSSelector::Equals(const nsCSSSelector* aOther) const +{ + if (nsnull != aOther) { + return (PRBool)((aOther->mTag == mTag) && (aOther->mID == mID) && + (aOther->mClass == mClass) && (aOther->mPseudoClass == mPseudoClass)); + } + return PR_FALSE; +} + + +void nsCSSSelector::Set(const nsString& aTag, const nsString& aID, + const nsString& aClass, const nsString& aPseudoClass) +{ + NS_IF_RELEASE(mTag); + NS_IF_RELEASE(mID); + NS_IF_RELEASE(mClass); + NS_IF_RELEASE(mPseudoClass); + if (0 < aTag.Length()) { + mTag = NS_NewAtom(aTag); + } + if (0 < aID.Length()) { + mID = NS_NewAtom(aID); + } + if (0 < aClass.Length()) { + mClass = NS_NewAtom(aClass); + } + if (0 < aPseudoClass.Length()) { + mPseudoClass = NS_NewAtom(aPseudoClass); + } +} + +// -- nsCSSStyleRule ------------------------------- + +class CSSStyleRuleImpl : public nsICSSStyleRule { +public: + void* operator new(size_t size); + void* operator new(size_t size, nsIArena* aArena); + void operator delete(void* ptr); + + CSSStyleRuleImpl(const nsCSSSelector& aSelector); + + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + + virtual PRBool Equals(const nsIStyleRule* aRule) const; + virtual PRUint32 HashValue(void) const; + + virtual nsCSSSelector* FirstSelector(void); + virtual void AddSelector(const nsCSSSelector& aSelector); + virtual void DeleteSelector(nsCSSSelector* aSelector); + + virtual nsICSSDeclaration* GetDeclaration(void) const; + virtual void SetDeclaration(nsICSSDeclaration* aDeclaration); + + virtual PRInt32 GetWeight(void) const; + virtual void SetWeight(PRInt32 aWeight); + + virtual nscoord CalcLength(const nsCSSValue& aValue, nsStyleFont* aFont, + nsIPresContext* aPresContext); + virtual void MapStyleInto(nsIStyleContext* aContext, nsIPresContext* aPresContext); + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + +private: + // These are not supported and are not implemented! + CSSStyleRuleImpl(const CSSStyleRuleImpl& aCopy); + CSSStyleRuleImpl& operator=(const CSSStyleRuleImpl& aCopy); + +protected: + virtual ~CSSStyleRuleImpl(); + +protected: + PRUint32 mInHeap : 1; + PRUint32 mRefCnt : 31; + + nsCSSSelector mSelector; + nsICSSDeclaration* mDeclaration; + PRInt32 mWeight; +}; + + +void* CSSStyleRuleImpl::operator new(size_t size) +{ + CSSStyleRuleImpl* rv = (CSSStyleRuleImpl*) ::operator new(size); +#ifdef NS_DEBUG + if (nsnull != rv) { + nsCRT::memset(rv, 0xEE, size); + } +#endif + rv->mInHeap = 1; + return (void*) rv; +} + +void* CSSStyleRuleImpl::operator new(size_t size, nsIArena* aArena) +{ + CSSStyleRuleImpl* rv = (CSSStyleRuleImpl*) aArena->Alloc(PRInt32(size)); +#ifdef NS_DEBUG + if (nsnull != rv) { + nsCRT::memset(rv, 0xEE, size); + } +#endif + rv->mInHeap = 0; + return (void*) rv; +} + +void CSSStyleRuleImpl::operator delete(void* ptr) +{ + CSSStyleRuleImpl* rule = (CSSStyleRuleImpl*) ptr; + if (nsnull != rule) { + if (rule->mInHeap) { + ::delete ptr; + } + } +} + + + +CSSStyleRuleImpl::CSSStyleRuleImpl(const nsCSSSelector& aSelector) + : mSelector(aSelector), mDeclaration(nsnull), mWeight(0) +{ + NS_INIT_REFCNT(); +} + +CSSStyleRuleImpl::~CSSStyleRuleImpl() +{ + nsCSSSelector* next = mSelector.mNext; + + while (nsnull != next) { + nsCSSSelector* selector = next; + next = selector->mNext; + delete selector; + } + NS_IF_RELEASE(mDeclaration); +} + +NS_IMPL_ADDREF(CSSStyleRuleImpl) +NS_IMPL_RELEASE(CSSStyleRuleImpl) + +nsresult CSSStyleRuleImpl::QueryInterface(const nsIID& aIID, + void** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + if (aIID.Equals(kICSSStyleRuleIID)) { + *aInstancePtrResult = (void*) ((nsICSSStyleRule*)this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIStyleRuleIID)) { + *aInstancePtrResult = (void*) ((nsIStyleRule*)this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kISupportsIID)) { + *aInstancePtrResult = (void*) ((nsISupports*)this); + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + + +PRBool CSSStyleRuleImpl::Equals(const nsIStyleRule* aRule) const +{ + nsICSSStyleRule* iCSSRule; + + if (this == aRule) { + return PR_TRUE; + } + + if ((nsnull != aRule) && + (NS_OK == ((nsIStyleRule*)aRule)->QueryInterface(kICSSStyleRuleIID, (void**) &iCSSRule))) { + + CSSStyleRuleImpl* rule = (CSSStyleRuleImpl*)iCSSRule; + const nsCSSSelector* local = &mSelector; + const nsCSSSelector* other = &(rule->mSelector); + PRBool result = PR_TRUE; + + while ((PR_TRUE == result) && (nsnull != local) && (nsnull != other)) { + if (! local->Equals(other)) { + result = PR_FALSE; + } + local = local->mNext; + other = other->mNext; + } + if ((nsnull != local) || (nsnull != other)) { // more were left + result = PR_FALSE; + } + if ((rule->mDeclaration != mDeclaration) || + (rule->mWeight != mWeight)) { + result = PR_FALSE; + } + NS_RELEASE(iCSSRule); + return result; + } + return PR_FALSE; +} + +PRUint32 CSSStyleRuleImpl::HashValue(void) const +{ + return (PRUint32)this; +} + +nsCSSSelector* CSSStyleRuleImpl::FirstSelector(void) +{ + return &mSelector; +} + +void CSSStyleRuleImpl::AddSelector(const nsCSSSelector& aSelector) +{ + nsCSSSelector* selector = new nsCSSSelector(aSelector); + nsCSSSelector* last = &mSelector; + + while (nsnull != last->mNext) { + last = last->mNext; + } + last->mNext = selector; +} + + +void CSSStyleRuleImpl::DeleteSelector(nsCSSSelector* aSelector) +{ + if (nsnull != aSelector) { + if (&mSelector == aSelector) { // handle first selector + mSelector = *aSelector; // assign value + mSelector.mNext = aSelector->mNext; + delete aSelector; + } + else { + nsCSSSelector* selector = &mSelector; + + while (nsnull != selector->mNext) { + if (aSelector == selector->mNext) { + selector->mNext = aSelector->mNext; + delete aSelector; + return; + } + selector = selector->mNext; + } + } + } +} + +nsICSSDeclaration* CSSStyleRuleImpl::GetDeclaration(void) const +{ + NS_IF_ADDREF(mDeclaration); + return mDeclaration; +} + +void CSSStyleRuleImpl::SetDeclaration(nsICSSDeclaration* aDeclaration) +{ + NS_IF_RELEASE(mDeclaration); + mDeclaration = aDeclaration; + NS_IF_ADDREF(mDeclaration); +} + +PRInt32 CSSStyleRuleImpl::GetWeight(void) const +{ + return mWeight; +} + +void CSSStyleRuleImpl::SetWeight(PRInt32 aWeight) +{ + mWeight = aWeight; +} + +nscoord CSSStyleRuleImpl::CalcLength(const nsCSSValue& aValue, nsStyleFont* aFont, + nsIPresContext* aPresContext) +{ + NS_ASSERTION(aValue.IsLengthUnit(), "not a length unit"); + if (aValue.IsFixedLengthUnit()) { + return aValue.GetLengthTwips(); + } + nsCSSUnit unit = aValue.GetUnit(); + switch (unit) { + case eCSSUnit_EM: + return aFont->mFont.size; + case eCSSUnit_EN: + return (aFont->mFont.size / 2); + case eCSSUnit_XHeight: + NS_NOTYETIMPLEMENTED("x height unit"); + return ((aFont->mFont.size / 3) * 2); // XXX HACK! + case eCSSUnit_CapHeight: + NS_NOTYETIMPLEMENTED("cap height unit"); + return ((aFont->mFont.size / 3) * 2); // XXX HACK! + + case eCSSUnit_Pixel: + return (nscoord)(aPresContext->GetPixelsToTwips() * aValue.GetFloatValue()); + } + return 0; +} + +void CSSStyleRuleImpl::MapStyleInto(nsIStyleContext* aContext, nsIPresContext* aPresContext) +{ + if (nsnull != mDeclaration) { + nsStyleFont* font = (nsStyleFont*)aContext->GetData(kStyleFontSID); + + nsCSSFont* ourFont; + if (NS_OK == mDeclaration->GetData(kCSSFontSID, (nsCSSStruct**)&ourFont)) { + if (nsnull != ourFont) { + nsStyleFont* parentFont = font; + nsIStyleContext* parentContext = aContext->GetParent(); + if (nsnull != parentContext) { + parentFont = (nsStyleFont*)parentContext->GetData(kStyleFontSID); + } + + // font-family: string list + if (ourFont->mFamily.GetUnit() == eCSSUnit_String) { + nsAutoString familyList; + ourFont->mFamily.GetStringValue(familyList); + // XXX meeds font support to determine usable fonts + // parse up the CSS string & remove the quotes + // XXX only does first until we can tell what are installed fonts + nsAutoString family; + PRInt32 index = familyList.Find(PRUnichar(',')); + if (-1 < index) { + familyList.Left(family, index); + } + else { + family.Append(familyList); + } + family.StripChars("\""); + family.StripWhitespace(); + + font->mFont.name = family; + } + + // font-style: enum + if (ourFont->mStyle.GetUnit() == eCSSUnit_Enumerated) { + font->mFont.style = ourFont->mStyle.GetIntValue(); + } + + // font-variant: enum + if (ourFont->mVariant.GetUnit() == eCSSUnit_Enumerated) { + font->mFont.variant = ourFont->mVariant.GetIntValue(); + } + + // font-weight: abs, enum + if (ourFont->mWeight.GetUnit() == eCSSUnit_Absolute) { + font->mFont.style = ourFont->mWeight.GetIntValue(); + } + else if (ourFont->mWeight.GetUnit() == eCSSUnit_Enumerated) { + PRInt32 value = ourFont->mWeight.GetIntValue(); + switch (value) { + case NS_STYLE_FONT_WEIGHT_NORMAL: + case NS_STYLE_FONT_WEIGHT_BOLD: + font->mFont.weight = value; + break; + case NS_STYLE_FONT_WEIGHT_BOLDER: + case NS_STYLE_FONT_WEIGHT_LIGHTER: + font->mFont.weight = (parentFont->mFont.weight + value); + break; + } + } + + // font-size: enum, length, percent + if (ourFont->mSize.GetUnit() == eCSSUnit_Enumerated) { + static float kFontScale[7] = { + 0.5f, // xx-small + 0.666667f, // x-small + 0.833333f, // small + 1.0f, // medium + 1.5f, // large + 1.5f * 1.5f, // x-large + 1.5f * 1.5f * 1.5f, // xx-large + }; + PRInt32 value = ourFont->mSize.GetIntValue(); + + const nsFont& normal = aPresContext->GetDefaultFont(); // use normal font or body font?? + if ((NS_STYLE_FONT_SIZE_XXSMALL <= value) && + (value <= NS_STYLE_FONT_SIZE_XXLARGE)) { + font->mFont.size = (nscoord)((float)normal.size * kFontScale[value]); + } + else if (NS_STYLE_FONT_SIZE_LARGER == value) { + PRInt32 index; + for (index = NS_STYLE_FONT_SIZE_XXSMALL; + index < NS_STYLE_FONT_SIZE_XXLARGE; index++) + if (parentFont->mFont.size < (nscoord)((float)normal.size * kFontScale[index])) + break; + font->mFont.size = (nscoord)((float)normal.size * kFontScale[index]); + } + else if (NS_STYLE_FONT_SIZE_SMALLER == value) { + PRInt32 index; + for (index = NS_STYLE_FONT_SIZE_XXLARGE; + index > NS_STYLE_FONT_SIZE_XXSMALL; index--) + if (parentFont->mFont.size > (nscoord)((float)normal.size * kFontScale[index])) + break; + font->mFont.size = (nscoord)((float)normal.size * kFontScale[index]); + } + } + else if (ourFont->mSize.IsLengthUnit()) { + font->mFont.size = CalcLength(ourFont->mSize, parentFont, aPresContext); + } + else if (ourFont->mSize.GetUnit() == eCSSUnit_Percent) { + font->mFont.size = (nscoord)((float)(parentFont->mFont.size) * ourFont->mSize.GetFloatValue()); + } + + NS_IF_RELEASE(parentContext); + } + } + + nsCSSText* ourText; + if (NS_OK == mDeclaration->GetData(kCSSTextSID, (nsCSSStruct**)&ourText)) { + if (nsnull != ourText) { + + // text-decoration: enum, absolute (bit field) + if (ourText->mDecoration.GetUnit() == eCSSUnit_Enumerated) { + font->mFont.decorations = ourText->mDecoration.GetIntValue(); + } + else if (ourText->mDecoration.GetUnit() == eCSSUnit_Absolute) { + font->mFont.decorations = ourText->mDecoration.GetIntValue(); + } + } + } + + + nsCSSColor* ourColor; + if (NS_OK == mDeclaration->GetData(kCSSColorSID, (nsCSSStruct**)&ourColor)) { + if (nsnull != ourColor) { + nsStyleColor* color = (nsStyleColor*)aContext->GetData(kStyleColorSID); + + // color: color + if (ourColor->mColor.GetUnit() == eCSSUnit_Color) { + color->mColor = ourColor->mColor.GetColorValue(); + } + + // background-color: color, enum (flags) + if (ourColor->mBackColor.GetUnit() == eCSSUnit_Color) { + color->mBackgroundColor = ourColor->mBackColor.GetColorValue(); + color->mBackgroundFlags &= ~NS_STYLE_BG_COLOR_TRANSPARENT; + } + else if (ourColor->mBackColor.GetUnit() == eCSSUnit_Enumerated) { + color->mBackgroundFlags |= NS_STYLE_BG_COLOR_TRANSPARENT; + } + + // background-image: string, enum (flags) + if (ourColor->mBackImage.GetUnit() == eCSSUnit_String) { + ourColor->mBackImage.GetStringValue(color->mBackgroundImage); + color->mBackgroundFlags &= ~NS_STYLE_BG_IMAGE_NONE; + } + else if (ourColor->mBackImage.GetUnit() == eCSSUnit_Enumerated) { + color->mBackgroundFlags |= NS_STYLE_BG_IMAGE_NONE; + } + + // background-repeat: enum + if (ourColor->mBackRepeat.GetUnit() == eCSSUnit_Enumerated) { + color->mBackgroundRepeat = ourColor->mBackRepeat.GetIntValue(); + } + + // background-attachment: enum + if (ourColor->mBackAttachment.GetUnit() == eCSSUnit_Enumerated) { + color->mBackgroundAttachment = ourColor->mBackAttachment.GetIntValue(); + } + + // background-position: length, percent (flags) + if (ourColor->mBackPositionX.GetUnit() == eCSSUnit_Percent) { + color->mBackgroundXPosition = (nscoord)(TWIPS_CONST_FLOAT * ourColor->mBackPositionX.GetFloatValue()); + color->mBackgroundFlags |= NS_STYLE_BG_X_POSITION_PCT; + color->mBackgroundFlags &= ~NS_STYLE_BG_X_POSITION_LENGTH; + } + else if (ourColor->mBackPositionX.IsLengthUnit()) { + color->mBackgroundXPosition = CalcLength(ourColor->mBackPositionX, + font, aPresContext); + color->mBackgroundFlags |= NS_STYLE_BG_X_POSITION_LENGTH; + color->mBackgroundFlags &= ~NS_STYLE_BG_X_POSITION_PCT; + } + if (ourColor->mBackPositionY.GetUnit() == eCSSUnit_Percent) { + color->mBackgroundYPosition = (nscoord)(TWIPS_CONST_FLOAT * ourColor->mBackPositionY.GetFloatValue()); + color->mBackgroundFlags |= NS_STYLE_BG_Y_POSITION_PCT; + color->mBackgroundFlags &= ~NS_STYLE_BG_Y_POSITION_LENGTH; + } + else if (ourColor->mBackPositionY.IsLengthUnit()) { + color->mBackgroundYPosition = CalcLength(ourColor->mBackPositionY, + font, aPresContext); + color->mBackgroundFlags |= NS_STYLE_BG_Y_POSITION_LENGTH; + color->mBackgroundFlags &= ~NS_STYLE_BG_Y_POSITION_PCT; + } + + // XXX: NYI nsCSSValue mBackFilter; + } + } + + + nsCSSList* ourList; + if (NS_OK == mDeclaration->GetData(kCSSListSID, (nsCSSStruct**)&ourList)) { + if (nsnull != ourList) { + nsStyleList* list = (nsStyleList*)aContext->GetData(kStyleListSID); + + // list-style-type: enum + if (ourList->mType.GetUnit() == eCSSUnit_Enumerated) { + list->mListStyleType = ourList->mType.GetIntValue(); + } + + // list-style-image: string + if (ourList->mImage.GetUnit() == eCSSUnit_String) { + ourList->mImage.GetStringValue(list->mListStyleImage); + } + else if (ourList->mImage.GetUnit() == eCSSUnit_Enumerated) { // handle "none" + list->mListStyleImage = ""; + } + + // list-style-position: enum + if (ourList->mPosition.GetUnit() == eCSSUnit_Enumerated) { + list->mListStyleType = ourList->mPosition.GetIntValue(); + } + } + } + + } + +} + + + +static void ListSelector(FILE* out, const nsCSSSelector* aSelector) +{ + nsAutoString buffer; + + if (nsnull != aSelector->mTag) { + aSelector->mTag->ToString(buffer); + fputs(buffer, out); + } + if (nsnull != aSelector->mID) { + aSelector->mID->ToString(buffer); + fputs("#", out); + fputs(buffer, out); + } + if (nsnull != aSelector->mClass) { + aSelector->mClass->ToString(buffer); + fputs(".", out); + fputs(buffer, out); + } + if (nsnull != aSelector->mPseudoClass) { + aSelector->mPseudoClass->ToString(buffer); + fputs(":", out); + fputs(buffer, out); + } +} + +void CSSStyleRuleImpl::List(FILE* out, PRInt32 aIndent) const +{ + // Indent + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + const nsCSSSelector* selector = &mSelector; + + while (nsnull != selector) { + ListSelector(out, selector); + fputs(" ", out); + selector = selector->mNext; + } + + nsAutoString buffer; + + buffer.Append("weight: "); + buffer.Append(mWeight, 10); + buffer.Append(" "); + fputs(buffer, out); + if (nsnull != mDeclaration) { + mDeclaration->List(out); + } + else { + fputs("{ null declaration }", out); + } + fputs("\n", out); +} + +NS_HTML nsresult + NS_NewCSSStyleRule(nsICSSStyleRule** aInstancePtrResult, const nsCSSSelector& aSelector) +{ + if (aInstancePtrResult == nsnull) { + return NS_ERROR_NULL_POINTER; + } + + CSSStyleRuleImpl *it = new CSSStyleRuleImpl(aSelector); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(kICSSStyleRuleIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/content/html/style/src/nsCSSStyleSheet.cpp b/mozilla/content/html/style/src/nsCSSStyleSheet.cpp new file mode 100644 index 00000000000..14d80e149fe --- /dev/null +++ b/mozilla/content/html/style/src/nsCSSStyleSheet.cpp @@ -0,0 +1,364 @@ +/* -*- 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 "nsICSSStyleSheet.h" +#include "nsIArena.h" +#include "nsCRT.h" +#include "nsIAtom.h" +#include "nsIURL.h" +#include "nsISupportsArray.h" +#include "nsICSSStyleRule.h" +#include "nsIHTMLContent.h" +#include "nsIFrame.h" +#include "nsString.h" + +static NS_DEFINE_IID(kICSSStyleSheetIID, NS_ICSS_STYLE_SHEET_IID); +static NS_DEFINE_IID(kIStyleSheetIID, NS_ISTYLE_SHEET_IID); +static NS_DEFINE_IID(kIStyleRuleIID, NS_ISTYLE_RULE_IID); +static NS_DEFINE_IID(kIHTMLContentIID, NS_IHTMLCONTENT_IID); + + +class CSSStyleSheetImpl : public nsICSSStyleSheet { +public: + void* operator new(size_t size); + void* operator new(size_t size, nsIArena* aArena); + void operator delete(void* ptr); + + CSSStyleSheetImpl(nsIURL* aURL); + + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + + virtual PRBool SelectorMatches(nsCSSSelector* aSelector, + nsIContent* aContent); + virtual PRInt32 RulesMatching(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsISupportsArray* aResults); + + virtual nsIURL* GetURL(void); + + virtual PRBool ContainsStyleSheet(nsIURL* aURL); + + virtual void AppendStyleSheet(nsICSSStyleSheet* aSheet); + + // XXX do these belong here or are they generic? + virtual void PrependStyleRule(nsICSSStyleRule* aRule); + virtual void AppendStyleRule(nsICSSStyleRule* aRule); + + // XXX style rule enumerations + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + +private: + // These are not supported and are not implemented! + CSSStyleSheetImpl(const CSSStyleSheetImpl& aCopy); + CSSStyleSheetImpl& operator=(const CSSStyleSheetImpl& aCopy); + +protected: + virtual ~CSSStyleSheetImpl(); + +protected: + PRUint32 mInHeap : 1; + PRUint32 mRefCnt : 31; + + nsIURL* mURL; + CSSStyleSheetImpl* mFirstChild; + nsISupportsArray* mRules; + CSSStyleSheetImpl* mNext; +}; + + +void* CSSStyleSheetImpl::operator new(size_t size) +{ + CSSStyleSheetImpl* rv = (CSSStyleSheetImpl*) ::operator new(size); +#ifdef NS_DEBUG + if (nsnull != rv) { + nsCRT::memset(rv, 0xEE, size); + } +#endif + rv->mInHeap = 1; + return (void*) rv; +} + +void* CSSStyleSheetImpl::operator new(size_t size, nsIArena* aArena) +{ + CSSStyleSheetImpl* rv = (CSSStyleSheetImpl*) aArena->Alloc(PRInt32(size)); +#ifdef NS_DEBUG + if (nsnull != rv) { + nsCRT::memset(rv, 0xEE, size); + } +#endif + rv->mInHeap = 0; + return (void*) rv; +} + +void CSSStyleSheetImpl::operator delete(void* ptr) +{ + CSSStyleSheetImpl* sheet = (CSSStyleSheetImpl*) ptr; + if (nsnull != sheet) { + if (sheet->mInHeap) { + ::delete ptr; + } + } +} + + + +CSSStyleSheetImpl::CSSStyleSheetImpl(nsIURL* aURL) + : nsICSSStyleSheet(), + mURL(aURL), mFirstChild(nsnull), mRules(nsnull), mNext(nsnull) +{ + NS_INIT_REFCNT(); + NS_ADDREF(mURL); +} + +CSSStyleSheetImpl::~CSSStyleSheetImpl() +{ + NS_RELEASE(mURL); + NS_IF_RELEASE(mFirstChild); + NS_IF_RELEASE(mRules); + NS_IF_RELEASE(mNext); +} + +NS_IMPL_ADDREF(CSSStyleSheetImpl) +NS_IMPL_RELEASE(CSSStyleSheetImpl) + +nsresult CSSStyleSheetImpl::QueryInterface(const nsIID& aIID, + void** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + if (aIID.Equals(kICSSStyleSheetIID)) { + *aInstancePtrResult = (void*) ((nsICSSStyleSheet*)this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIStyleSheetIID)) { + *aInstancePtrResult = (void*) ((nsIStyleSheet*)this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kISupportsIID)) { + *aInstancePtrResult = (void*) ((nsISupports*)this); + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +PRBool CSSStyleSheetImpl::SelectorMatches(nsCSSSelector* aSelector, nsIContent* aContent) +{ + PRBool result = PR_FALSE; + + if ((nsnull == aSelector->mTag) || (aSelector->mTag == aContent->GetTag())) { + if ((nsnull != aSelector->mClass) || (nsnull != aSelector->mTag)) { + nsIHTMLContent* htmlContent; + if (NS_OK == aContent->QueryInterface(kIHTMLContentIID, (void**)&htmlContent)) { + if ((nsnull == aSelector->mClass) || (aSelector->mClass == htmlContent->GetClass())) { + if ((nsnull == aSelector->mID) || (aSelector->mID == htmlContent->GetID())) { + result = PR_TRUE; + } + } + NS_RELEASE(htmlContent); + } + } + else { + result = PR_TRUE; + } + } + return result; +} + +PRInt32 CSSStyleSheetImpl::RulesMatching(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsISupportsArray* aResults) +{ + NS_PRECONDITION(nsnull != aPresContext, "null arg"); + NS_PRECONDITION(nsnull != aContent, "null arg"); +// NS_PRECONDITION(nsnull != aParentFrame, "null arg"); + NS_PRECONDITION(nsnull != aResults, "null arg"); + + PRInt32 matchCount = 0; + CSSStyleSheetImpl* child = mFirstChild; + while (nsnull != child) { + matchCount += child->RulesMatching(aPresContext, aContent, aParentFrame, aResults); + child = child->mNext; + } + + PRInt32 count = ((nsnull != mRules) ? mRules->Count() : 0); + + for (PRInt32 index = 0; index < count; index++) { + nsICSSStyleRule* rule = (nsICSSStyleRule*)mRules->ElementAt(index); + + nsCSSSelector* selector = rule->FirstSelector(); + if (SelectorMatches(selector, aContent)) { + selector = selector->mNext; + nsIFrame* frame = aParentFrame; + while ((nsnull != selector) && (nsnull != frame)) { // check compound selectors + nsIContent* content = frame->GetContent(); + if (SelectorMatches(selector, content)) { + selector = selector->mNext; + } + frame = frame->GetGeometricParent(); + NS_RELEASE(content); + } + if (nsnull == selector) { // ran out, it matched + nsIStyleRule* iRule; + if (NS_OK == rule->QueryInterface(kIStyleRuleIID, (void**)&iRule)) { + aResults->AppendElement(iRule); + NS_RELEASE(iRule); + matchCount++; + } + } + } + NS_RELEASE(rule); + } + return matchCount; +} + +nsIURL* CSSStyleSheetImpl::GetURL(void) +{ + NS_ADDREF(mURL); + return mURL; +} + +PRBool CSSStyleSheetImpl::ContainsStyleSheet(nsIURL* aURL) +{ + NS_PRECONDITION(nsnull != aURL, "null arg"); + + PRBool result = (*mURL == *aURL); + + CSSStyleSheetImpl* child = mFirstChild; + while ((PR_FALSE == result) && (nsnull != child)) { + result = child->ContainsStyleSheet(aURL); + child = child->mNext; + } + return result; +} + +void CSSStyleSheetImpl::AppendStyleSheet(nsICSSStyleSheet* aSheet) +{ + NS_PRECONDITION(nsnull != aSheet, "null arg"); + + if (nsnull == mFirstChild) { + mFirstChild = (CSSStyleSheetImpl*)aSheet; + } + else { + CSSStyleSheetImpl* child = mFirstChild; + while (nsnull != child->mNext) { + child = child->mNext; + } + child->mNext = (CSSStyleSheetImpl*)aSheet; + } + NS_ADDREF(aSheet); +} + +void CSSStyleSheetImpl::PrependStyleRule(nsICSSStyleRule* aRule) +{ + NS_PRECONDITION(nsnull != aRule, "null arg"); + NS_ADDREF(aRule); + //XXX replace this with a binary search? + PRInt32 weight = aRule->GetWeight(); + if (nsnull == mRules) { + if (NS_OK != NS_NewISupportsArray(&mRules)) + return; + } + PRInt32 index = mRules->Count(); + while (0 <= --index) { + nsICSSStyleRule* rule = (nsICSSStyleRule*)mRules->ElementAt(index); + if (rule->GetWeight() > weight) { // insert before rules with equal or lesser weight + NS_RELEASE(rule); + break; + } + NS_RELEASE(rule); + } + mRules->InsertElementAt(aRule, index + 1); +} + +void CSSStyleSheetImpl::AppendStyleRule(nsICSSStyleRule* aRule) +{ + NS_PRECONDITION(nsnull != aRule, "null arg"); + NS_ADDREF(aRule); + + //XXX replace this with a binary search? + PRInt32 weight = aRule->GetWeight(); + if (nsnull == mRules) { + if (NS_OK != NS_NewISupportsArray(&mRules)) + return; + } + PRInt32 count = mRules->Count(); + PRInt32 index = -1; + while (++index < count) { + nsICSSStyleRule* rule = (nsICSSStyleRule*)mRules->ElementAt(index); + if (rule->GetWeight() < weight) { // insert after rules with equal or greater weight (before lower weight) + NS_RELEASE(rule); + break; + } + NS_RELEASE(rule); + } + mRules->InsertElementAt(aRule, index); +} + +void CSSStyleSheetImpl::List(FILE* out, PRInt32 aIndent) const +{ + nsAutoString buffer; + PRInt32 index; + + // Indent + for (index = aIndent; --index >= 0; ) fputs(" ", out); + + fputs("CSS Style Sheet: ", out); + mURL->ToString(buffer); + fputs(buffer, out); + fputs("\n", out); + + CSSStyleSheetImpl* child = mFirstChild; + while (nsnull != child) { + child->List(out, aIndent + 1); + child = child->mNext; + } + + PRInt32 count = ((nsnull != mRules) ? mRules->Count() : 0); + + for (index = 0; index < count; index++) { + nsICSSStyleRule* rule = (nsICSSStyleRule*)mRules->ElementAt(index); + rule->List(out, aIndent); + NS_RELEASE(rule); + } +} + +NS_HTML nsresult + NS_NewCSSStyleSheet(nsICSSStyleSheet** aInstancePtrResult, nsIURL* aURL) +{ + if (aInstancePtrResult == nsnull) { + return NS_ERROR_NULL_POINTER; + } + + CSSStyleSheetImpl *it = new CSSStyleSheetImpl(aURL); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(kICSSStyleSheetIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/content/html/style/src/nsHTMLAttributes.cpp b/mozilla/content/html/style/src/nsHTMLAttributes.cpp new file mode 100644 index 00000000000..895e98e277c --- /dev/null +++ b/mozilla/content/html/style/src/nsHTMLAttributes.cpp @@ -0,0 +1,672 @@ +/* -*- 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 "nsIHTMLAttributes.h" +#include "nsIStyleRule.h" +#include "nsString.h" +#include "nsISupportsArray.h" +#include "nsCRT.h" +#include "nsIArena.h" +#include "nsIStyleContext.h" +#include "nsHTMLAtoms.h" +#include "nsIHTMLContent.h" + +static NS_DEFINE_IID(kIHTMLAttributesIID, NS_IHTML_ATTRIBUTES_IID); +static NS_DEFINE_IID(kIStyleRuleIID, NS_ISTYLE_RULE_IID); + + +struct HTMLAttribute { + HTMLAttribute(nsIAtom* aAttribute, const nsString& aValue) + : mAttribute(aAttribute), + mValue(aValue), + mNext(nsnull) + { + NS_IF_ADDREF(mAttribute); + } + + HTMLAttribute(nsIAtom* aAttribute, const nsHTMLValue& aValue) + : mAttribute(aAttribute), + mValue(aValue), + mNext(nsnull) + { + NS_IF_ADDREF(mAttribute); + } + + HTMLAttribute(const HTMLAttribute& aCopy) + : mAttribute(aCopy.mAttribute), + mValue(aCopy.mValue), + mNext(nsnull) + { + NS_IF_ADDREF(mAttribute); + } + + ~HTMLAttribute(void) + { + NS_IF_RELEASE(mAttribute); + } + + HTMLAttribute& operator=(const HTMLAttribute& aCopy) + { + NS_IF_RELEASE(mAttribute); + mAttribute = aCopy.mAttribute; + NS_IF_ADDREF(mAttribute); + mValue = aCopy.mValue; + return *this; + } + + PRBool operator==(const HTMLAttribute& aOther) const + { + return PRBool((mAttribute == aOther.mAttribute) && + (mValue == aOther.mValue)); + } + + void Reset(void) + { + NS_IF_RELEASE(mAttribute); + mValue.Reset(); + } + + void AppendToString(nsString& aBuffer) const + { + if (nsnull != mAttribute) { + nsAutoString temp; + mAttribute->ToString(temp); + aBuffer.Append(temp); + if (eHTMLUnit_Null != mValue.GetUnit()) { + aBuffer.Append(" = "); + mValue.AppendToString(aBuffer); + } + } + else { + aBuffer.Append("null"); + } + } + + void ToString(nsString& aBuffer) const + { + if (nsnull != mAttribute) { + mAttribute->ToString(aBuffer); + if (eHTMLUnit_Null != mValue.GetUnit()) { + aBuffer.Append(" = "); + mValue.AppendToString(aBuffer); + } + } + else { + aBuffer.SetLength(0); + aBuffer.Append("null"); + } + } + + nsIAtom* mAttribute; + nsHTMLValue mValue; + HTMLAttribute* mNext; +}; + +// ---------------- + + +class HTMLAttributesImpl: public nsIHTMLAttributes, public nsIStyleRule { +public: + void* operator new(size_t size); + void* operator new(size_t size, nsIArena* aArena); + void operator delete(void* ptr); + + HTMLAttributesImpl(nsIHTMLContent* aContent); + ~HTMLAttributesImpl(void); + + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + + virtual PRBool Equals(const nsIStyleRule* aRule) const; + virtual PRUint32 HashValue(void) const; + + virtual PRInt32 SetAttribute(nsIAtom* aAttribute, const nsString& aValue); + virtual PRInt32 SetAttribute(nsIAtom* aAttribute, + const nsHTMLValue& aValue = nsHTMLValue::kNull); + virtual PRInt32 UnsetAttribute(nsIAtom* aAttribute); + virtual nsContentAttr GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aValue) const; + virtual PRInt32 GetAllAttributeNames(nsISupportsArray* aArray) const; + virtual PRInt32 Count(void) const; + + virtual PRInt32 SetID(nsIAtom* aID); + virtual nsIAtom* GetID(void) const; + virtual PRInt32 SetClass(nsIAtom* aClass); // XXX this will have to change for CSS2 + virtual nsIAtom* GetClass(void) const; // XXX this will have to change for CSS2 + + virtual void MapStyleInto(nsIStyleContext* aContext, nsIPresContext* aPresContext); + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + +private: + HTMLAttributesImpl(const HTMLAttributesImpl& aCopy); + HTMLAttributesImpl& operator=(const HTMLAttributesImpl& aCopy); + PRBool operator==(const HTMLAttributesImpl& aCopy) const; + +protected: + PRUint32 mInHeap : 1; + PRUint32 mRefCnt : 31; + + nsIHTMLContent* mContent; + PRInt32 mCount; + HTMLAttribute* mFirst; + nsIAtom* mID; + nsIAtom* mClass; +}; + +void* HTMLAttributesImpl::operator new(size_t size) +{ + HTMLAttributesImpl* rv = (HTMLAttributesImpl*) ::operator new(size); +#ifdef NS_DEBUG + if (nsnull != rv) { + nsCRT::memset(rv, 0xEE, size); + } +#endif + rv->mInHeap = 1; + return (void*) rv; +} + +void* HTMLAttributesImpl::operator new(size_t size, nsIArena* aArena) +{ + HTMLAttributesImpl* rv = (HTMLAttributesImpl*) aArena->Alloc(PRInt32(size)); +#ifdef NS_DEBUG + if (nsnull != rv) { + nsCRT::memset(rv, 0xEE, size); + } +#endif + rv->mInHeap = 0; + return (void*) rv; +} + +void HTMLAttributesImpl::operator delete(void* ptr) +{ + HTMLAttributesImpl* attr = (HTMLAttributesImpl*) ptr; + if (nsnull != attr) { + if (attr->mInHeap) { + ::delete ptr; + } + } +} + + +HTMLAttributesImpl::HTMLAttributesImpl(nsIHTMLContent* aContent) + : mContent(aContent), // weak ref + mFirst(nsnull), + mCount(0), + mID(nsnull), + mClass(nsnull) +{ + NS_INIT_REFCNT(); +} + +HTMLAttributesImpl::~HTMLAttributesImpl(void) +{ + HTMLAttribute* next = mFirst; + while (nsnull != next) { + HTMLAttribute* attr = next; + next = next->mNext; + delete attr; + } + NS_IF_RELEASE(mID); + NS_IF_RELEASE(mClass); +} + +NS_IMPL_ADDREF(HTMLAttributesImpl) +NS_IMPL_RELEASE(HTMLAttributesImpl) + +nsresult HTMLAttributesImpl::QueryInterface(const nsIID& aIID, + void** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + if (aIID.Equals(kIHTMLAttributesIID)) { + *aInstancePtrResult = (void*) ((nsIHTMLAttributes*)this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIStyleRuleIID)) { + *aInstancePtrResult = (void*) ((nsIStyleRule*)this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kISupportsIID)) { + *aInstancePtrResult = (void*) ((nsISupports*)(nsIHTMLAttributes*)this); + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + + +PRBool HTMLAttributesImpl::Equals(const nsIStyleRule* aRule) const +{ + nsIHTMLAttributes* iHTMLAttr; + + if (this == aRule) { + return PR_TRUE; + } + + if ((nsnull != aRule) && + (NS_OK == ((nsIStyleRule*)aRule)->QueryInterface(kIHTMLAttributesIID, (void**) &iHTMLAttr))) { + + const HTMLAttributesImpl* other = (HTMLAttributesImpl*)iHTMLAttr; + PRBool result = PR_FALSE; + + if (mCount == other->mCount) { + if ((mID == other->mID) && (mClass == other->mClass)) { + const HTMLAttribute* attr = mFirst; + const HTMLAttribute* otherAttr = other->mFirst; + + result = PR_TRUE; + while (nsnull != attr) { + if (! ((*attr) == (*otherAttr))) { + result = PR_FALSE; + break; + } + attr = attr->mNext; + otherAttr = otherAttr->mNext; + } + } + } + + NS_RELEASE(iHTMLAttr); + return result; + } + return PR_FALSE; +} + +PRUint32 HTMLAttributesImpl::HashValue(void) const +{ + return (PRUint32)this; +} + +PRInt32 HTMLAttributesImpl::SetAttribute(nsIAtom* aAttribute, const nsString& aValue) +{ + if (nsHTMLAtoms::id == aAttribute) { + nsIAtom* id = NS_NewAtom(aValue); + PRInt32 result = SetID (id); + NS_RELEASE(id); + return result; + } + if (nsHTMLAtoms::kClass == aAttribute) { + nsIAtom* classA = NS_NewAtom(aValue); + PRInt32 result = SetClass (classA); + NS_RELEASE(classA); + return result; + } + + HTMLAttribute* last = nsnull; + HTMLAttribute* attr = mFirst; + + while (nsnull != attr) { + if (attr->mAttribute == aAttribute) { + attr->mValue.Set (aValue); + return mCount; + } + last = attr; + attr = attr->mNext; + } + + attr = new HTMLAttribute(aAttribute, aValue); + if (nsnull == last) { + mFirst = attr; + } + else { + last->mNext = attr; + } + return ++mCount; +} + +PRInt32 HTMLAttributesImpl::SetAttribute(nsIAtom* aAttribute, const nsHTMLValue& aValue) +{ + if (nsHTMLAtoms::id == aAttribute) { + nsAutoString buffer; + nsIAtom* id = NS_NewAtom(aValue.GetStringValue(buffer)); + PRInt32 result = SetID (id); + NS_RELEASE(id); + return result; + } + if (nsHTMLAtoms::kClass == aAttribute) { + nsAutoString buffer; + nsIAtom* classA = NS_NewAtom(aValue.GetStringValue(buffer)); + PRInt32 result = SetClass (classA); + NS_RELEASE(classA); + return result; + } + + HTMLAttribute* last = nsnull; + HTMLAttribute* attr = mFirst; + + while (nsnull != attr) { + if (attr->mAttribute == aAttribute) { + attr->mValue = aValue; + return mCount; + } + last = attr; + attr = attr->mNext; + } + + attr = new HTMLAttribute(aAttribute, aValue); + if (nsnull == last) { + mFirst = attr; + } + else { + last->mNext = attr; + } + return ++mCount; +} + +PRInt32 HTMLAttributesImpl::UnsetAttribute(nsIAtom* aAttribute) +{ + if (nsHTMLAtoms::id == aAttribute) { + return SetID (nsnull); + } + if (nsHTMLAtoms::kClass == aAttribute) { + return SetClass (nsnull); + } + + HTMLAttribute* prev = nsnull; + HTMLAttribute* attr = mFirst; + + while (nsnull != attr) { + if (attr->mAttribute == aAttribute) { + if (nsnull == prev) { + mFirst = attr->mNext; + } + else { + prev->mNext = attr->mNext; + } + delete attr; + mCount--; + break; + } + prev = attr; + attr = attr->mNext; + } + return mCount; +} + +nsContentAttr HTMLAttributesImpl::GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aValue) const +{ + aValue.Reset(); + if (nsHTMLAtoms::id == aAttribute) { + nsIAtom* id = GetID(); + if (nsnull != id) { + nsAutoString buffer; + id->ToString(buffer); + aValue.Set(buffer); + NS_RELEASE(id); + return eContentAttr_HasValue; + } + return eContentAttr_NotThere; + } + if (nsHTMLAtoms::kClass == aAttribute) { + nsIAtom* classA = GetClass(); + if (nsnull != classA) { + nsAutoString buffer; + classA->ToString(buffer); + aValue.Set(buffer); + NS_RELEASE(classA); + return eContentAttr_HasValue; + } + return eContentAttr_NotThere; + } + + HTMLAttribute* attr = mFirst; + + while (nsnull != attr) { + if (attr->mAttribute == aAttribute) { + aValue = attr->mValue; + return ((attr->mValue.GetUnit() == eHTMLUnit_Null) ? eContentAttr_NoValue : eContentAttr_HasValue); + } + attr = attr->mNext; + } + return eContentAttr_NotThere; +} + +PRInt32 HTMLAttributesImpl::GetAllAttributeNames(nsISupportsArray* aArray) const +{ + NS_ASSERTION(nsnull != aArray, "null arg"); + + if (nsnull == aArray) { + return 0; + } + + if (nsnull != mID) { + aArray->AppendElement((nsIAtom*)nsHTMLAtoms::id); + } + if (nsnull != mClass) { + aArray->AppendElement((nsIAtom*)nsHTMLAtoms::kClass); + } + + HTMLAttribute* attr = mFirst; + + while (nsnull != attr) { + aArray->AppendElement(attr->mAttribute); + attr = attr->mNext; + } + return mCount; +} + +PRInt32 HTMLAttributesImpl::Count(void) const +{ + return mCount; +} + +PRInt32 HTMLAttributesImpl::SetID(nsIAtom* aID) +{ + if (aID != mID) { + if (nsnull != mID) { + NS_RELEASE(mID); + mCount--; + } + mID = aID; + if (nsnull != mID) { + NS_ADDREF(mID); + mCount++; + } + } + return mCount; +} + +nsIAtom* HTMLAttributesImpl::GetID(void) const +{ + NS_IF_ADDREF(mID); + return mID; +} + +PRInt32 HTMLAttributesImpl::SetClass(nsIAtom* aClass) +{ + if (aClass != mClass) { + if (nsnull != mClass) { + NS_RELEASE(mClass); + mCount--; + } + mClass = aClass; + if (nsnull != mClass) { + NS_ADDREF(mClass); + mCount++; + } + } + return mCount; +} + +nsIAtom* HTMLAttributesImpl::GetClass(void) const +{ + NS_IF_ADDREF(mClass); + return mClass; +} + +void HTMLAttributesImpl::MapStyleInto(nsIStyleContext* aContext, nsIPresContext* aPresContext) +{ + if (nsnull != mContent) { + mContent->MapAttributesInto(aContext, aPresContext); + } +} + + +void HTMLAttributesImpl::List(FILE* out, PRInt32 aIndent) const +{ + HTMLAttribute* attr = mFirst; + nsString buffer; + + while (nsnull != attr) { + fputs("\n", out); + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + attr->ToString(buffer); + fputs(buffer, out); + attr = attr->mNext; + } +} + +extern NS_HTML nsresult + NS_NewHTMLAttributes(nsIHTMLAttributes** aInstancePtrResult, nsIHTMLContent* aContent) +{ + if (aInstancePtrResult == nsnull) { + return NS_ERROR_NULL_POINTER; + } + + HTMLAttributesImpl *it = new HTMLAttributesImpl(aContent); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(kIHTMLAttributesIID, (void **) aInstancePtrResult); +} + + +#if 0 + + +marginwidth; marginheight: px + +border: px + +align(DIV): left, right, center, justify +align: left, right, center, abscenter +valign: baseline, top, bottom, middle, center +align(image): abscenter, left, right, texttop, absbottom, baseline, center, bottom, top, middle, absmiddle + +dir: rtl, ltr + +width: px, % +height: px, % + +vspace; hspace: px + +type(list): none, disc, (circle | round), square, decimal, lower-roman, upper-roman, lower-alpha, upper-alpha + +href: url +target: string +src: url(string?) +color: color +face: string +suppress: bool + +style: string +class: string (list) +id: string +name: string + +//a +link; vlink; alink: color + +//body +background: url +bgcolor: color +text: color + +//frameset +bordercolor: color + +//layer +background: url +bgcolor: color + +//q +lang: string + +//table +background: url +bgcolor: color +bordercolor: color +cellspacing: px +cellpadding: px +toppadding; leftpadding; bottompadding; rightpadding: px +cols: int + +//td +background: url +bgcolor: color +nowrap: bool +colspan; rowspan: int + +//tr +background: url +bgcolor: color + +//colgroup +span: int + +//col +repeat: int + +//ul;ol +compact: bool +start: int + +//li +value: int + +//hr;spacer +size: px + +//multicol +cols: int +gutter: px + +//input +type: string +value: string + +//factory methods: +GetStringData +GetBoolData +GetInvBoolData +GetPixelIntData +GetValueOrPctData +GetValueData + +//tag methods +getAttribute +getIntAttribute +getKeywordAttribute +getSignedAttribute +getValueOrPctAttribute + + +//notes +nsIAtom->value table + +#endif diff --git a/mozilla/content/html/style/src/nsHTMLStyleSheet.cpp b/mozilla/content/html/style/src/nsHTMLStyleSheet.cpp new file mode 100644 index 00000000000..687a1030ee4 --- /dev/null +++ b/mozilla/content/html/style/src/nsHTMLStyleSheet.cpp @@ -0,0 +1,214 @@ +/* -*- 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 "nsIHTMLStyleSheet.h" +#include "nsIArena.h" +#include "nsCRT.h" +#include "nsIAtom.h" +#include "nsIURL.h" +#include "nsISupportsArray.h" +#include "nsIHTMLContent.h" +#include "nsIStyleRule.h" + +static NS_DEFINE_IID(kIHTMLStyleSheetIID, NS_IHTML_STYLE_SHEET_IID); +static NS_DEFINE_IID(kIStyleSheetIID, NS_ISTYLE_SHEET_IID); +static NS_DEFINE_IID(kIHTMLContentIID, NS_IHTMLCONTENT_IID); + + +class HTMLStyleSheetImpl : public nsIHTMLStyleSheet { +public: + void* operator new(size_t size); + void* operator new(size_t size, nsIArena* aArena); + void operator delete(void* ptr); + + HTMLStyleSheetImpl(nsIURL* aURL); + + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + + virtual PRInt32 RulesMatching(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsISupportsArray* aResults); + + virtual nsIURL* GetURL(void); + + // XXX style rule enumerations + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + +private: + // These are not supported and are not implemented! + HTMLStyleSheetImpl(const HTMLStyleSheetImpl& aCopy); + HTMLStyleSheetImpl& operator=(const HTMLStyleSheetImpl& aCopy); + +protected: + virtual ~HTMLStyleSheetImpl(); + +protected: + PRUint32 mInHeap : 1; + PRUint32 mRefCnt : 31; + + nsIURL* mURL; +}; + + +void* HTMLStyleSheetImpl::operator new(size_t size) +{ + HTMLStyleSheetImpl* rv = (HTMLStyleSheetImpl*) ::operator new(size); +#ifdef NS_DEBUG + if (nsnull != rv) { + nsCRT::memset(rv, 0xEE, size); + } +#endif + rv->mInHeap = 1; + return (void*) rv; +} + +void* HTMLStyleSheetImpl::operator new(size_t size, nsIArena* aArena) +{ + HTMLStyleSheetImpl* rv = (HTMLStyleSheetImpl*) aArena->Alloc(PRInt32(size)); +#ifdef NS_DEBUG + if (nsnull != rv) { + nsCRT::memset(rv, 0xEE, size); + } +#endif + rv->mInHeap = 0; + return (void*) rv; +} + +void HTMLStyleSheetImpl::operator delete(void* ptr) +{ + HTMLStyleSheetImpl* sheet = (HTMLStyleSheetImpl*) ptr; + if (nsnull != sheet) { + if (sheet->mInHeap) { + ::delete ptr; + } + } +} + + + +HTMLStyleSheetImpl::HTMLStyleSheetImpl(nsIURL* aURL) + : nsIHTMLStyleSheet(), + mURL(aURL) +{ + NS_INIT_REFCNT(); + NS_ADDREF(mURL); +} + +HTMLStyleSheetImpl::~HTMLStyleSheetImpl() +{ + NS_RELEASE(mURL); +} + +NS_IMPL_ADDREF(HTMLStyleSheetImpl) +NS_IMPL_RELEASE(HTMLStyleSheetImpl) + +nsresult HTMLStyleSheetImpl::QueryInterface(const nsIID& aIID, + void** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + if (aIID.Equals(kIHTMLStyleSheetIID)) { + *aInstancePtrResult = (void*) ((nsIHTMLStyleSheet*)this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIStyleSheetIID)) { + *aInstancePtrResult = (void*) ((nsIStyleSheet*)this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kISupportsIID)) { + *aInstancePtrResult = (void*) ((nsISupports*)this); + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +PRInt32 HTMLStyleSheetImpl::RulesMatching(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsISupportsArray* aResults) +{ + NS_PRECONDITION(nsnull != aPresContext, "null arg"); + NS_PRECONDITION(nsnull != aContent, "null arg"); +// NS_PRECONDITION(nsnull != aParentFrame, "null arg"); + NS_PRECONDITION(nsnull != aResults, "null arg"); + + PRInt32 matchCount = 0; + + nsIHTMLContent* htmlContent; + + // for now, just get the one and only style rule from the content + // this may need some special handling for pseudo-frames + if (NS_OK == aContent->QueryInterface(kIHTMLContentIID, (void**)&htmlContent)) { + nsIStyleRule* rule = htmlContent->GetStyleRule(); + + if (nsnull != rule) { + aResults->AppendElement(rule); + NS_RELEASE(rule); + matchCount++; + } + + NS_RELEASE(htmlContent); + } + + return matchCount; +} + +nsIURL* HTMLStyleSheetImpl::GetURL(void) +{ + NS_ADDREF(mURL); + return mURL; +} + +void HTMLStyleSheetImpl::List(FILE* out, PRInt32 aIndent) const +{ + nsAutoString buffer; + + // Indent + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + fputs("HTML Style Sheet: ", out); + mURL->ToString(buffer); + fputs(buffer, out); + fputs("\n", out); + +} + +NS_HTML nsresult + NS_NewHTMLStyleSheet(nsIHTMLStyleSheet** aInstancePtrResult, nsIURL* aURL) +{ + if (aInstancePtrResult == nsnull) { + return NS_ERROR_NULL_POINTER; + } + + HTMLStyleSheetImpl *it = new HTMLStyleSheetImpl(aURL); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(kIHTMLStyleSheetIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/content/html/style/src/nsHTMLValue.cpp b/mozilla/content/html/style/src/nsHTMLValue.cpp new file mode 100644 index 00000000000..ed2df9aaab5 --- /dev/null +++ b/mozilla/content/html/style/src/nsHTMLValue.cpp @@ -0,0 +1,257 @@ +/* -*- 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 "nsHTMLValue.h" +#include "nsString.h" +#include "nsCRT.h" + +const nsHTMLValue nsHTMLValue::kNull; + +nsHTMLValue::nsHTMLValue(void) + : mUnit(eHTMLUnit_Null) +{ + mValue.mString = nsnull; +} + +nsHTMLValue::nsHTMLValue(PRInt32 aValue, nsHTMLUnit aUnit) + : mUnit(aUnit) +{ + mValue.mInt = aValue; +} + +nsHTMLValue::nsHTMLValue(float aValue, nsHTMLUnit aUnit) + : mUnit(aUnit) +{ + mValue.mFloat = aValue; +} + +nsHTMLValue::nsHTMLValue(const nsString& aValue) + : mUnit(eHTMLUnit_String) +{ + mValue.mString = aValue.ToNewString(); +} + +nsHTMLValue::nsHTMLValue(nsISupports* aValue) + : mUnit(eHTMLUnit_ISupports) +{ + mValue.mISupports = aValue; + NS_IF_ADDREF(mValue.mISupports); +} + +nsHTMLValue::nsHTMLValue(nscolor aValue) + : mUnit(eHTMLUnit_Color) +{ + mValue.mColor = aValue; +} + +nsHTMLValue::nsHTMLValue(const nsHTMLValue& aCopy) + : mUnit(aCopy.mUnit) +{ + if (eHTMLUnit_String == mUnit) { + if (nsnull != aCopy.mValue.mString) { + mValue.mString = aCopy.mValue.mString->ToNewString(); + } + else { + mValue.mString = nsnull; + } + } + else if (eHTMLUnit_ISupports == mUnit) { + mValue.mISupports = aCopy.mValue.mISupports; + NS_IF_ADDREF(mValue.mISupports); + } + else if (eHTMLUnit_Color == mUnit){ + mValue.mColor = aCopy.mValue.mColor; + } + else if (eHTMLUnit_Percent == mUnit) { + mValue.mFloat = aCopy.mValue.mFloat; + } + else { + mValue.mInt = aCopy.mValue.mInt; + } +} + +nsHTMLValue::~nsHTMLValue(void) +{ + Reset(); +} + +nsHTMLValue& nsHTMLValue::operator=(const nsHTMLValue& aCopy) +{ + Reset(); + mUnit = aCopy.mUnit; + if (eHTMLUnit_String == mUnit) { + if (nsnull != aCopy.mValue.mString) { + mValue.mString = aCopy.mValue.mString->ToNewString(); + } + } + else if (eHTMLUnit_ISupports == mUnit) { + mValue.mISupports = aCopy.mValue.mISupports; + NS_IF_ADDREF(mValue.mISupports); + } + else if (eHTMLUnit_Color == mUnit){ + mValue.mColor = aCopy.mValue.mColor; + } + else if (eHTMLUnit_Percent == mUnit) { + mValue.mFloat = aCopy.mValue.mFloat; + } + else { + mValue.mInt = aCopy.mValue.mInt; + } + return *this; +} + +PRBool nsHTMLValue::operator==(const nsHTMLValue& aOther) const +{ + if (mUnit == aOther.mUnit) { + if (eHTMLUnit_String == mUnit) { + if (nsnull == mValue.mString) { + if (nsnull == aOther.mValue.mString) { + return PR_TRUE; + } + } + else if (nsnull != aOther.mValue.mString) { + return mValue.mString->Equals(*(aOther.mValue.mString)); + } + } + else if (eHTMLUnit_ISupports == mUnit) { + return PRBool(mValue.mISupports == aOther.mValue.mISupports); + } + else if (eHTMLUnit_Color == mUnit){ + return PRBool(mValue.mColor == aOther.mValue.mColor); + } + else if (eHTMLUnit_Percent == mUnit) { + return PRBool(mValue.mFloat == aOther.mValue.mFloat); + } + else { + return PRBool(mValue.mInt == aOther.mValue.mInt); + } + } + return PR_FALSE; +} + +void nsHTMLValue::Reset(void) +{ + if (eHTMLUnit_String == mUnit) { + if (nsnull != mValue.mString) { + delete mValue.mString; + } + } + else if (eHTMLUnit_ISupports == mUnit) { + NS_IF_RELEASE(mValue.mISupports); + } + mUnit = eHTMLUnit_Null; + mValue.mString = nsnull; +} + + +void nsHTMLValue::Set(PRInt32 aValue, nsHTMLUnit aUnit) +{ + Reset(); + mUnit = aUnit; + mValue.mInt = aValue; +} + +void nsHTMLValue::Set(float aValue, nsHTMLUnit aUnit) +{ + Reset(); + mUnit = aUnit; + mValue.mFloat = aValue; +} + +void nsHTMLValue::Set(const nsString& aValue) +{ + Reset(); + mUnit = eHTMLUnit_String; + mValue.mString = aValue.ToNewString(); +} + +void nsHTMLValue::Set(nsISupports* aValue) +{ + Reset(); + mUnit = eHTMLUnit_ISupports; + mValue.mISupports = aValue; + NS_IF_ADDREF(mValue.mISupports); +} + +void nsHTMLValue::Set(nscolor aValue) +{ + Reset(); + mUnit = eHTMLUnit_Color; + mValue.mColor = aValue; +} + +void nsHTMLValue::AppendToString(nsString& aBuffer) const +{ + if (eHTMLUnit_Null == mUnit) { + return; + } + + if (eHTMLUnit_String == mUnit) { + if (nsnull != mValue.mString) { + aBuffer.Append('"'); + aBuffer.Append(*(mValue.mString)); + aBuffer.Append('"'); + } + else { + aBuffer.Append("null str"); + } + } + else if (eHTMLUnit_ISupports == mUnit) { + aBuffer.Append("0x"); + aBuffer.Append((PRInt32)mValue.mISupports, 16); + } + else if (eHTMLUnit_Color == mUnit){ + aBuffer.Append("(0x"); + aBuffer.Append(NS_GET_R(mValue.mColor), 16); + aBuffer.Append(" 0x"); + aBuffer.Append(NS_GET_G(mValue.mColor), 16); + aBuffer.Append(" 0x"); + aBuffer.Append(NS_GET_B(mValue.mColor), 16); + aBuffer.Append(" 0x"); + aBuffer.Append(NS_GET_A(mValue.mColor), 16); + aBuffer.Append(')'); + } + else if (eHTMLUnit_Percent == mUnit) { + aBuffer.Append(mValue.mFloat); + } + else { + aBuffer.Append(mValue.mInt, 10); + aBuffer.Append("[0x"); + aBuffer.Append(mValue.mInt, 16); + aBuffer.Append(']'); + } + + switch (mUnit) { + case eHTMLUnit_Null: break; + case eHTMLUnit_String: break; + case eHTMLUnit_ISupports: aBuffer.Append("ptr"); break; + case eHTMLUnit_Absolute: break; + case eHTMLUnit_Enumerated: aBuffer.Append("enum"); break; + case eHTMLUnit_Color: aBuffer.Append("rbga"); break; + case eHTMLUnit_Percent: aBuffer.Append("%"); break; + case eHTMLUnit_Pixel: aBuffer.Append("px"); break; + } + aBuffer.Append(' '); +} + +void nsHTMLValue::ToString(nsString& aBuffer) const +{ + aBuffer.SetLength(0); + AppendToString(aBuffer); +} + diff --git a/mozilla/content/html/style/src/nsHTMLValue.h b/mozilla/content/html/style/src/nsHTMLValue.h new file mode 100644 index 00000000000..a2f5309e614 --- /dev/null +++ b/mozilla/content/html/style/src/nsHTMLValue.h @@ -0,0 +1,138 @@ +/* -*- 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. + */ +#ifndef nsHTMLValue_h___ +#define nsHTMLValue_h___ + +#include "nscore.h" +#include "nsColor.h" +#include "nsString.h" +#include "nsISupports.h" + + +enum nsHTMLUnit { + eHTMLUnit_Null = 0, // (n/a) null unit, value is not specified + eHTMLUnit_String = 10, // (nsString) a string value + eHTMLUnit_ISupports = 20, // (nsISupports*) a ref counted interface + eHTMLUnit_Absolute = 50, // (int) simple value + eHTMLUnit_Enumerated = 51, // (int) value has enumerated meaning + eHTMLUnit_Color = 80, // (color) an RGBA value + eHTMLUnit_Percent = 90, // (float) 1.0 == 100%) value is percentage of something + + // Screen relative measure + eHTMLUnit_Pixel = 600, // (int) screen pixels +}; + +class nsHTMLValue { +public: + nsHTMLValue(void); + nsHTMLValue(PRInt32 aValue, nsHTMLUnit aUnit = eHTMLUnit_Absolute); + nsHTMLValue(float aValue, nsHTMLUnit aUnit = eHTMLUnit_Pixel); + nsHTMLValue(const nsString& aValue); + nsHTMLValue(nsISupports* aValue); + nsHTMLValue(nscolor aValue); + nsHTMLValue(const nsHTMLValue& aCopy); + ~nsHTMLValue(void); + + nsHTMLValue& operator=(const nsHTMLValue& aCopy); + PRBool operator==(const nsHTMLValue& aOther) const; + + nsHTMLUnit GetUnit(void) const { return mUnit; } + PRInt32 GetIntValue(void) const; + float GetFloatValue(void) const; + nsString& GetStringValue(nsString& aBuffer) const; + nsISupports* GetISupportsValue(void) const; + nscolor GetColorValue(void) const; + + void Reset(void); + void Set(PRInt32 aValue, nsHTMLUnit aUnit = eHTMLUnit_Absolute); + void Set(float aValue, nsHTMLUnit aUnit = eHTMLUnit_Pixel); + void Set(const nsString& aValue); + void Set(nsISupports* aValue); + void Set(nscolor aValue); + + void AppendToString(nsString& aBuffer) const; + void ToString(nsString& aBuffer) const; + +protected: + nsHTMLUnit mUnit; + union { + PRInt32 mInt; + float mFloat; + nsString* mString; + nsISupports* mISupports; + nscolor mColor; + } mValue; + +public: + static const nsHTMLValue kNull; +}; + +inline PRInt32 nsHTMLValue::GetIntValue(void) const +{ + NS_ASSERTION((mUnit == eHTMLUnit_Absolute) || + (mUnit == eHTMLUnit_Enumerated) || + (mUnit == eHTMLUnit_Pixel), "not an int value"); + if ((mUnit == eHTMLUnit_Absolute) || + (mUnit == eHTMLUnit_Enumerated) || + (mUnit == eHTMLUnit_Pixel)) { + return mValue.mInt; + } + return 0; +} + +inline float nsHTMLValue::GetFloatValue(void) const +{ + NS_ASSERTION(mUnit == eHTMLUnit_Percent, "not a float value"); + if (mUnit == eHTMLUnit_Percent) { + return mValue.mFloat; + } + return 0.0f; +} + +inline nsString& nsHTMLValue::GetStringValue(nsString& aBuffer) const +{ + NS_ASSERTION((mUnit == eHTMLUnit_String) || (mUnit == eHTMLUnit_Null), "not a string value"); + aBuffer.SetLength(0); + if ((mUnit == eHTMLUnit_String) && (nsnull != mValue.mString)) { + aBuffer.Append(*(mValue.mString)); + } + return aBuffer; +} + +inline nsISupports* nsHTMLValue::GetISupportsValue(void) const +{ + NS_ASSERTION(mUnit == eHTMLUnit_ISupports, "not an ISupports value"); + if (mUnit == eHTMLUnit_ISupports) { + NS_IF_ADDREF(mValue.mISupports); + return mValue.mISupports; + } + return nsnull; +} + +inline nscolor nsHTMLValue::GetColorValue(void) const +{ + NS_ASSERTION(mUnit == eHTMLUnit_Color, "not a color value"); + if (mUnit == eHTMLUnit_Color) { + return mValue.mColor; + } + return NS_RGB(0,0,0); +} + + +#endif /* nsHTMLValue_h___ */ + diff --git a/mozilla/content/html/style/src/nsICSSDeclaration.h b/mozilla/content/html/style/src/nsICSSDeclaration.h new file mode 100644 index 00000000000..62e8bceb61a --- /dev/null +++ b/mozilla/content/html/style/src/nsICSSDeclaration.h @@ -0,0 +1,305 @@ +/* -*- 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. + */ +#ifndef nsICSSDeclaration_h___ +#define nsICSSDeclaration_h___ + +#include "nslayout.h" +#include "nsISupports.h" +#include "nsColor.h" +#include "stdio.h" +#include "nsString.h" +#include "nsCoord.h" + + +enum nsCSSUnit { + eCSSUnit_Null = 0, // (n/a) null unit, value is not specified + eCSSUnit_Auto = 1, // (n/a) value is algorithmic + eCSSUnit_String = 10, // (nsString) a string value + eCSSUnit_Absolute = 50, // (int) simple value + eCSSUnit_Enumerated = 51, // (int) value has enumerated meaning + eCSSUnit_Color = 80, // (color) an RGBA value + eCSSUnit_Percent = 90, // (float) 1.0 == 100%) value is percentage of something + eCSSUnit_Number = 91, // (float) value is numeric (usually multiplier, different behavior that percent) + + // US English + eCSSUnit_Inch = 100, // (float) Standard length + eCSSUnit_Foot = 101, // (float) 12 inches + eCSSUnit_Mile = 102, // (float) 5280 feet + + // Metric + eCSSUnit_Millimeter = 207, // (float) 1/1000 meter + eCSSUnit_Centimeter = 208, // (float) 1/100 meter + eCSSUnit_Meter = 210, // (float) Standard length + eCSSUnit_Kilometer = 213, // (float) 1000 meters + + // US Typographic + eCSSUnit_Point = 300, // (float) 1/72 inch + eCSSUnit_Pica = 301, // (float) 12 points == 1/6 inch + + // European Typographic + eCSSUnit_Didot = 400, // (float) 15 didots == 16 points + eCSSUnit_Cicero = 401, // (float) 12 didots + + // relative units + // Font relative measure + eCSSUnit_EM = 800, // (float) == current font size + eCSSUnit_EN = 801, // (float) .5 em + eCSSUnit_XHeight = 802, // (float) distance from top of lower case x to baseline + eCSSUnit_CapHeight = 803, // (float) distance from top of uppercase case H to baseline + + // Screen relative measure + eCSSUnit_Pixel = 900 // (float) +}; + +struct nsCSSStruct { + virtual const nsID& GetID(void) = 0; +}; + +class nsCSSValue { +public: + nsCSSValue(void); + nsCSSValue(PRInt32 aValue, nsCSSUnit aUnit); + nsCSSValue(float aValue, nsCSSUnit aUnit); + nsCSSValue(const nsString& aValue); + nsCSSValue(nscolor aValue); + nsCSSValue(const nsCSSValue& aCopy); + ~nsCSSValue(void); + + nsCSSValue& operator=(const nsCSSValue& aCopy); + PRBool operator==(const nsCSSValue& aOther) const; + + nsCSSUnit GetUnit(void) const { return mUnit; }; + PRBool IsLengthUnit(void) const + { return PRBool(eCSSUnit_Inch <= mUnit); } + PRBool IsFixedLengthUnit(void) const + { return PRBool((eCSSUnit_Inch <= mUnit) && (mUnit < eCSSUnit_EM)); } + PRBool IsRelativeLengthUnit(void) const + { return PRBool(eCSSUnit_EM <= mUnit); } + + PRInt32 GetIntValue(void) const; + float GetFloatValue(void) const; + nsString& GetStringValue(nsString& aBuffer) const; + nscolor GetColorValue(void) const; + nscoord GetLengthTwips(void) const; + + void Reset(void); + void Set(PRInt32 aValue, nsCSSUnit aUnit); + void Set(float aValue, nsCSSUnit aUnit); + void Set(const nsString& aValue); + void Set(nscolor aValue); + + void AppendToString(nsString& aBuffer, PRInt32 aPropID = -1) const; + void ToString(nsString& aBuffer, PRInt32 aPropID = -1) const; + +protected: + nsCSSUnit mUnit; + union { + PRInt32 mInt; + float mFloat; + nsString* mString; + nscolor mColor; + } mValue; +}; + +inline PRInt32 nsCSSValue::GetIntValue(void) const +{ + NS_ASSERTION((mUnit == eCSSUnit_Absolute) || + (mUnit == eCSSUnit_Enumerated), "not an int value"); + if ((mUnit == eCSSUnit_Absolute) || + (mUnit == eCSSUnit_Enumerated)) { + return mValue.mInt; + } + return 0; +} + +inline float nsCSSValue::GetFloatValue(void) const +{ + NS_ASSERTION((mUnit != eCSSUnit_Null) && + (mUnit != eCSSUnit_Absolute) && + (mUnit != eCSSUnit_Enumerated) && + (mUnit != eCSSUnit_String) && + (mUnit != eCSSUnit_Color), "not a float value"); + if ((mUnit != eCSSUnit_Null) && + (mUnit != eCSSUnit_Absolute) && + (mUnit != eCSSUnit_Enumerated) && + (mUnit != eCSSUnit_String) && + (mUnit != eCSSUnit_Color)) { + return mValue.mFloat; + } + return 0.0f; +} + +inline nsString& nsCSSValue::GetStringValue(nsString& aBuffer) const +{ + NS_ASSERTION((mUnit == eCSSUnit_String), "not a string value"); + aBuffer.Truncate(); + if ((mUnit == eCSSUnit_String) && (nsnull != mValue.mString)) { + aBuffer.Append(*(mValue.mString)); + } + return aBuffer; +} + +inline nscolor nsCSSValue::GetColorValue(void) const +{ + NS_ASSERTION((mUnit == eCSSUnit_Color), "not a color value"); + if (mUnit == eCSSUnit_Color) { + return mValue.mColor; + } + return NS_RGB(0,0,0); +} + +// SID for the nsCSSFont struct {f645dbf8-b48a-11d1-9ca5-0060088f9ff7} +#define NS_CSS_FONT_SID \ +{0xf645dbf8, 0xb48a, 0x11d1, {0x9c, 0xa5, 0x00, 0x60, 0x08, 0x8f, 0x9f, 0xf7}} + +// SID for the nsCSSColor struct {fd825f22-b48a-11d1-9ca5-0060088f9ff7} +#define NS_CSS_COLOR_SID \ +{0xfd825f22, 0xb48a, 0x11d1, {0x9c, 0xa5, 0x00, 0x60, 0x08, 0x8f, 0x9f, 0xf7}} + +// SID for the nsCSSText struct {fe13ce94-b48a-11d1-9ca5-0060088f9ff7} +#define NS_CSS_TEXT_SID \ +{0xfe13ce94, 0xb48a, 0x11d1, {0x9c, 0xa5, 0x00, 0x60, 0x08, 0x8f, 0x9f, 0xf7}} + +// SID for the nsCSSMargin struct {fe6019d4-b48a-11d1-9ca5-0060088f9ff7} +#define NS_CSS_MARGIN_SID \ +{0xfe6019d4, 0xb48a, 0x11d1, {0x9c, 0xa5, 0x00, 0x60, 0x08, 0x8f, 0x9f, 0xf7}} + +// SID for the nsCSSPosition struct {fee33b2a-b48a-11d1-9ca5-0060088f9ff7} +#define NS_CSS_POSITION_SID \ +{0xfee33b2a, 0xb48a, 0x11d1, {0x9c, 0xa5, 0x00, 0x60, 0x08, 0x8f, 0x9f, 0xf7}} + +// SID for the nsCSSList struct {603f8266-b48b-11d1-9ca5-0060088f9ff7} +#define NS_CSS_LIST_SID \ +{0x603f8266, 0xb48b, 0x11d1, {0x9c, 0xa5, 0x00, 0x60, 0x08, 0x8f, 0x9f, 0xf7}} + +// IID for the nsICSSDeclaration interface {7b36b9ac-b48d-11d1-9ca5-0060088f9ff7} +#define NS_ICSS_DECLARATION_IID \ +{0x7b36b9ac, 0xb48d, 0x11d1, {0x9c, 0xa5, 0x00, 0x60, 0x08, 0x8f, 0x9f, 0xf7}} + +struct nsCSSFont : public nsCSSStruct { + const nsID& GetID(void); + void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + + nsCSSValue mFamily; + nsCSSValue mStyle; + nsCSSValue mVariant; + nsCSSValue mWeight; + nsCSSValue mSize; +}; + +struct nsCSSColor : public nsCSSStruct { + const nsID& GetID(void); + void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + + nsCSSValue mColor; + nsCSSValue mBackColor; + nsCSSValue mBackImage; + nsCSSValue mBackRepeat; + nsCSSValue mBackAttachment; + nsCSSValue mBackPositionX; + nsCSSValue mBackPositionY; + nsCSSValue mBackFilter; +}; + +struct nsCSSText : public nsCSSStruct { + const nsID& GetID(void); + void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + + nsCSSValue mWordSpacing; + nsCSSValue mLetterSpacing; + nsCSSValue mDecoration; + nsCSSValue mVertAlign; + nsCSSValue mTransform; + nsCSSValue mHorzAlign; + nsCSSValue mIndent; + nsCSSValue mLineHeight; + nsCSSValue mWhiteSpace; +}; + +struct nsCSSRect { + void List(FILE* out = 0, PRInt32 aPropID = -1, PRInt32 aIndent = 0) const; + + nsCSSValue mTop; + nsCSSValue mRight; + nsCSSValue mBottom; + nsCSSValue mLeft; +}; + +struct nsCSSMargin : public nsCSSStruct { + nsCSSMargin(void); + ~nsCSSMargin(void); + const nsID& GetID(void); + void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + + nsCSSRect* mMargin; + nsCSSRect* mPadding; + nsCSSRect* mBorder; + nsCSSRect* mColor; + nsCSSRect* mStyle; +}; + +struct nsCSSPosition : public nsCSSStruct { + nsCSSPosition(void); + ~nsCSSPosition(void); + const nsID& GetID(void); + void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + + nsCSSValue mPosition; + nsCSSValue mWidth; + nsCSSValue mHeight; + nsCSSValue mLeft; + nsCSSValue mTop; + nsCSSRect* mClip; + nsCSSValue mOverflow; + nsCSSValue mZIndex; + nsCSSValue mVisibility; + nsCSSValue mFloat; + nsCSSValue mClear; + nsCSSValue mDisplay; + nsCSSValue mFilter; +}; + +struct nsCSSList : public nsCSSStruct { + const nsID& GetID(void); + void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + + nsCSSValue mType; + nsCSSValue mImage; + nsCSSValue mPosition; +}; + + +class nsICSSDeclaration : public nsISupports { +public: + virtual nsresult GetData(const nsID& aIID, nsCSSStruct** aData) = 0; + virtual nsresult EnsureData(const nsID& aSID, nsCSSStruct** aData) = 0; + + virtual nsresult AddValue(const char* aProperty, const nsCSSValue& aValue) = 0; + virtual nsresult AddValue(PRInt32 aProperty, const nsCSSValue& aValue) = 0; +// XXX make nscolor a struct to avoid type conflicts + virtual nsresult GetValue(const char* aProperty, nsCSSValue& aValue) = 0; + virtual nsresult GetValue(PRInt32 aProperty, nsCSSValue& aValue) = 0; + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const = 0; +}; + +extern NS_HTML nsresult + NS_NewCSSDeclaration(nsICSSDeclaration** aInstancePtrResult); + +#endif /* nsICSSDeclaration_h___ */ + diff --git a/mozilla/content/html/style/src/nsICSSStyleRule.h b/mozilla/content/html/style/src/nsICSSStyleRule.h new file mode 100644 index 00000000000..153397fe876 --- /dev/null +++ b/mozilla/content/html/style/src/nsICSSStyleRule.h @@ -0,0 +1,76 @@ +/* -*- 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. + */ +#ifndef nsICSSStyleRule_h___ +#define nsICSSStyleRule_h___ + +#include +#include "nslayout.h" +#include "nsIStyleRule.h" +class nsIAtom; +class nsIArena; +class nsString; +class nsICSSDeclaration; + + +struct nsCSSSelector { +public: + nsCSSSelector(); + nsCSSSelector(nsIAtom* aTag, nsIAtom* aID, nsIAtom* aClass, nsIAtom* aPseudoClass); + nsCSSSelector(const nsCSSSelector& aCopy); + ~nsCSSSelector(); + + nsCSSSelector& operator=(const nsCSSSelector& aCopy); + PRBool Equals(const nsCSSSelector* aOther) const; + + void Set(const nsString& aTag, const nsString& aID, const nsString& aClass, const nsString& aPseudoClass); + +public: + nsIAtom* mTag; + nsIAtom* mID; + nsIAtom* mClass; // this'll have to be an array for CSS2 + nsIAtom* mPseudoClass; + + nsCSSSelector* mNext; +}; + +// IID for the nsICSSStyleRule interface {7c277af0-af19-11d1-8031-006008159b5a} +#define NS_ICSS_STYLE_RULE_IID \ +{0x7c277af0, 0xaf19, 0x11d1, {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}} + +class nsICSSStyleRule : public nsIStyleRule { +public: + virtual PRBool Equals(const nsIStyleRule* aRule) const = 0; + virtual PRUint32 HashValue(void) const = 0; + + virtual nsCSSSelector* FirstSelector(void) = 0; + virtual void AddSelector(const nsCSSSelector& aSelector) = 0; + virtual void DeleteSelector(nsCSSSelector* aSelector) = 0; + + virtual nsICSSDeclaration* GetDeclaration(void) const = 0; + virtual void SetDeclaration(nsICSSDeclaration* aDeclaration) = 0; + + virtual PRInt32 GetWeight(void) const = 0; + virtual void SetWeight(PRInt32 aWeight) = 0; + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const = 0; +}; + +extern NS_HTML nsresult + NS_NewCSSStyleRule(nsICSSStyleRule** aInstancePtrResult, const nsCSSSelector& aSelector); + +#endif /* nsICSSStyleRule_h___ */ diff --git a/mozilla/content/html/style/src/nsIHTMLAttributes.h b/mozilla/content/html/style/src/nsIHTMLAttributes.h new file mode 100644 index 00000000000..f3f2428401e --- /dev/null +++ b/mozilla/content/html/style/src/nsIHTMLAttributes.h @@ -0,0 +1,59 @@ +/* -*- 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. + */ +#ifndef nsIHTMLAttributes_h___ +#define nsIHTMLAttributes_h___ + +#include "nslayout.h" +#include "nsISupports.h" +#include "nsHTMLValue.h" +#include "nsIContent.h" +class nsIAtom; +class nsISupportsArray; +class nsIHTMLContent; + + +// IID for the nsIHTMLAttributes interface {a18f85f0-c058-11d1-8031-006008159b5a} +#define NS_IHTML_ATTRIBUTES_IID \ +{0xa18f85f0, 0xc058, 0x11d1, \ + {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}} + +class nsIHTMLAttributes : public nsISupports { +public: + virtual PRInt32 SetAttribute(nsIAtom* aAttribute, const nsString& aValue) = 0; + virtual PRInt32 SetAttribute(nsIAtom* aAttribute, + const nsHTMLValue& aValue = nsHTMLValue::kNull) = 0; + virtual PRInt32 UnsetAttribute(nsIAtom* aAttribute) = 0; + virtual nsContentAttr GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aValue) const = 0; + virtual PRInt32 GetAllAttributeNames(nsISupportsArray* aArray) const = 0; + + virtual PRInt32 Count(void) const = 0; + + virtual PRInt32 SetID(nsIAtom* aID) = 0; + virtual nsIAtom* GetID(void) const = 0; + virtual PRInt32 SetClass(nsIAtom* aClass) = 0; // XXX this will have to change for CSS2 + virtual nsIAtom* GetClass(void) const = 0; // XXX this will have to change for CSS2 + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const = 0; +}; + +extern NS_HTML nsresult + NS_NewHTMLAttributes(nsIHTMLAttributes** aInstancePtrResult, nsIHTMLContent* aContent); + +#endif /* nsIHTMLAttributes_h___ */ + diff --git a/mozilla/content/shared/public/nsCSSKeywords.h b/mozilla/content/shared/public/nsCSSKeywords.h new file mode 100644 index 00000000000..1db3cbe5ee3 --- /dev/null +++ b/mozilla/content/shared/public/nsCSSKeywords.h @@ -0,0 +1,40 @@ +/* -*- 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. + */ +#ifndef nsCSSKeywords_h___ +#define nsCSSKeywords_h___ + +#include "nslayout.h" +#include "nsCSSKeywordIDs.h" + +class NS_LAYOUT nsCSSKeywords { +public: + // Given a null terminated string of 7 bit characters, return the + // tag id (see nsHTMLTagIDs.h) for the tag or -1 if the tag is not + // known. The lookup function uses a perfect hash. + static PRInt32 LookupName(const char* str); + + struct NameTableEntry { + const char* name; + PRInt32 id; + }; + + // A table whose index is the tag id (from LookupName) + static const NameTableEntry kNameTable[]; +}; + +#endif /* nsCSSKeywords_h___ */ diff --git a/mozilla/content/shared/public/nsCSSProps.h b/mozilla/content/shared/public/nsCSSProps.h new file mode 100644 index 00000000000..29bd8de6945 --- /dev/null +++ b/mozilla/content/shared/public/nsCSSProps.h @@ -0,0 +1,40 @@ +/* -*- 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. + */ +#ifndef nsCSSProps_h___ +#define nsCSSProps_h___ + +#include "nslayout.h" +#include "nsCSSPropIDs.h" + +class NS_LAYOUT nsCSSProps { +public: + // Given a null terminated string of 7 bit characters, return the + // tag id (see nsCSSPropIDs.h) for the tag or -1 if the tag is not + // known. The lookup function uses a perfect hash. + static PRInt32 LookupName(const char* str); + + struct NameTableEntry { + const char* name; + PRInt32 id; + }; + + // A table whose index is the tag id (from nsCSSPropIDs) + static const NameTableEntry kNameTable[]; +}; + +#endif /* nsCSSProps_h___ */ diff --git a/mozilla/content/shared/public/nsHTMLAtoms.h b/mozilla/content/shared/public/nsHTMLAtoms.h new file mode 100644 index 00000000000..0f1eb0a8df1 --- /dev/null +++ b/mozilla/content/shared/public/nsHTMLAtoms.h @@ -0,0 +1,168 @@ +/* -*- 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. + */ +#ifndef nsHTMLAtoms_h___ +#define nsHTMLAtoms_h___ + +#include "nsIAtom.h" + +/** + * This class wraps up the creation (and destruction) of the standard + * set of html atoms used during normal html handling. This objects + * are created when the first html content object is created and they + * are destroyed when the last html content object is destroyed. + */ +class nsHTMLAtoms { +public: + + static void AddrefAtoms(); + static void ReleaseAtoms(); + + // Alphabetical list of html attribute atoms + static nsIAtom* a; + static nsIAtom* above; + static nsIAtom* action; + static nsIAtom* align; + static nsIAtom* alink; + static nsIAtom* alt; + static nsIAtom* archive; + + static nsIAtom* background; + static nsIAtom* below; + static nsIAtom* bgcolor; + static nsIAtom* body; + static nsIAtom* border; + static nsIAtom* bordercolor; + static nsIAtom* bottompadding; + static nsIAtom* br; + + static nsIAtom* cellpadding; + static nsIAtom* cellspacing; + static nsIAtom* checked; + static nsIAtom* kClass; + static nsIAtom* classid; + static nsIAtom* clear; + static nsIAtom* clip; + static nsIAtom* code; + static nsIAtom* codebase; + static nsIAtom* color; + static nsIAtom* cols; + static nsIAtom* colspan; + static nsIAtom* compact; + static nsIAtom* coords; + + static nsIAtom* data; + static nsIAtom* dir; + static nsIAtom* div; + static nsIAtom* dl; + + static nsIAtom* encoding; + + static nsIAtom* face; + static nsIAtom* font; + static nsIAtom* fontWeight; + static nsIAtom* frameborder; + + static nsIAtom* gutter; + + static nsIAtom* h1; + static nsIAtom* h2; + static nsIAtom* h3; + static nsIAtom* h4; + static nsIAtom* h5; + static nsIAtom* h6; + static nsIAtom* height; + static nsIAtom* hidden; + static nsIAtom* href; + static nsIAtom* hspace; + static nsIAtom* httpEquiv; + + static nsIAtom* id; + static nsIAtom* ismap; + + static nsIAtom* language; + static nsIAtom* li; + static nsIAtom* link; + static nsIAtom* left; + static nsIAtom* leftpadding; + static nsIAtom* lowsrc; + + static nsIAtom* marginheight; + static nsIAtom* marginwidth; + static nsIAtom* maxlength; + static nsIAtom* mayscript; + static nsIAtom* menu; + static nsIAtom* method; + static nsIAtom* multicol; + static nsIAtom* multiple; + + static nsIAtom* name; + static nsIAtom* noresize; + static nsIAtom* noshade; + static nsIAtom* nowrap; + + static nsIAtom* ol; + static nsIAtom* onblur; + static nsIAtom* onfocus; + static nsIAtom* onload; + static nsIAtom* onunload; + static nsIAtom* overflow; + + static nsIAtom* p; + static nsIAtom* pagex; + static nsIAtom* pagey; + static nsIAtom* pointSize; + static nsIAtom* pre; + static nsIAtom* prompt; + + static nsIAtom* rel; + static nsIAtom* rightpadding; + static nsIAtom* rows; + static nsIAtom* rowspan; + + static nsIAtom* scrolling; + static nsIAtom* selected; + static nsIAtom* shape; + static nsIAtom* size; + static nsIAtom* src; + static nsIAtom* start; + static nsIAtom* suppress; + + static nsIAtom* tabstop; + static nsIAtom* target; + static nsIAtom* text; + static nsIAtom* top; + static nsIAtom* toppadding; + static nsIAtom* type; + + static nsIAtom* ul; + static nsIAtom* usemap; + + static nsIAtom* valign; + static nsIAtom* value; + static nsIAtom* variable; + static nsIAtom* visibility; + static nsIAtom* vlink; + static nsIAtom* vspace; + + static nsIAtom* width; + static nsIAtom* wrap; + + static nsIAtom* zindex; +}; + +#endif /* nsHTMLAtoms_h___ */ diff --git a/mozilla/content/shared/public/nsHTMLValue.h b/mozilla/content/shared/public/nsHTMLValue.h new file mode 100644 index 00000000000..a2f5309e614 --- /dev/null +++ b/mozilla/content/shared/public/nsHTMLValue.h @@ -0,0 +1,138 @@ +/* -*- 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. + */ +#ifndef nsHTMLValue_h___ +#define nsHTMLValue_h___ + +#include "nscore.h" +#include "nsColor.h" +#include "nsString.h" +#include "nsISupports.h" + + +enum nsHTMLUnit { + eHTMLUnit_Null = 0, // (n/a) null unit, value is not specified + eHTMLUnit_String = 10, // (nsString) a string value + eHTMLUnit_ISupports = 20, // (nsISupports*) a ref counted interface + eHTMLUnit_Absolute = 50, // (int) simple value + eHTMLUnit_Enumerated = 51, // (int) value has enumerated meaning + eHTMLUnit_Color = 80, // (color) an RGBA value + eHTMLUnit_Percent = 90, // (float) 1.0 == 100%) value is percentage of something + + // Screen relative measure + eHTMLUnit_Pixel = 600, // (int) screen pixels +}; + +class nsHTMLValue { +public: + nsHTMLValue(void); + nsHTMLValue(PRInt32 aValue, nsHTMLUnit aUnit = eHTMLUnit_Absolute); + nsHTMLValue(float aValue, nsHTMLUnit aUnit = eHTMLUnit_Pixel); + nsHTMLValue(const nsString& aValue); + nsHTMLValue(nsISupports* aValue); + nsHTMLValue(nscolor aValue); + nsHTMLValue(const nsHTMLValue& aCopy); + ~nsHTMLValue(void); + + nsHTMLValue& operator=(const nsHTMLValue& aCopy); + PRBool operator==(const nsHTMLValue& aOther) const; + + nsHTMLUnit GetUnit(void) const { return mUnit; } + PRInt32 GetIntValue(void) const; + float GetFloatValue(void) const; + nsString& GetStringValue(nsString& aBuffer) const; + nsISupports* GetISupportsValue(void) const; + nscolor GetColorValue(void) const; + + void Reset(void); + void Set(PRInt32 aValue, nsHTMLUnit aUnit = eHTMLUnit_Absolute); + void Set(float aValue, nsHTMLUnit aUnit = eHTMLUnit_Pixel); + void Set(const nsString& aValue); + void Set(nsISupports* aValue); + void Set(nscolor aValue); + + void AppendToString(nsString& aBuffer) const; + void ToString(nsString& aBuffer) const; + +protected: + nsHTMLUnit mUnit; + union { + PRInt32 mInt; + float mFloat; + nsString* mString; + nsISupports* mISupports; + nscolor mColor; + } mValue; + +public: + static const nsHTMLValue kNull; +}; + +inline PRInt32 nsHTMLValue::GetIntValue(void) const +{ + NS_ASSERTION((mUnit == eHTMLUnit_Absolute) || + (mUnit == eHTMLUnit_Enumerated) || + (mUnit == eHTMLUnit_Pixel), "not an int value"); + if ((mUnit == eHTMLUnit_Absolute) || + (mUnit == eHTMLUnit_Enumerated) || + (mUnit == eHTMLUnit_Pixel)) { + return mValue.mInt; + } + return 0; +} + +inline float nsHTMLValue::GetFloatValue(void) const +{ + NS_ASSERTION(mUnit == eHTMLUnit_Percent, "not a float value"); + if (mUnit == eHTMLUnit_Percent) { + return mValue.mFloat; + } + return 0.0f; +} + +inline nsString& nsHTMLValue::GetStringValue(nsString& aBuffer) const +{ + NS_ASSERTION((mUnit == eHTMLUnit_String) || (mUnit == eHTMLUnit_Null), "not a string value"); + aBuffer.SetLength(0); + if ((mUnit == eHTMLUnit_String) && (nsnull != mValue.mString)) { + aBuffer.Append(*(mValue.mString)); + } + return aBuffer; +} + +inline nsISupports* nsHTMLValue::GetISupportsValue(void) const +{ + NS_ASSERTION(mUnit == eHTMLUnit_ISupports, "not an ISupports value"); + if (mUnit == eHTMLUnit_ISupports) { + NS_IF_ADDREF(mValue.mISupports); + return mValue.mISupports; + } + return nsnull; +} + +inline nscolor nsHTMLValue::GetColorValue(void) const +{ + NS_ASSERTION(mUnit == eHTMLUnit_Color, "not a color value"); + if (mUnit == eHTMLUnit_Color) { + return mValue.mColor; + } + return NS_RGB(0,0,0); +} + + +#endif /* nsHTMLValue_h___ */ + diff --git a/mozilla/content/shared/src/nsCSSKeywords.cpp b/mozilla/content/shared/src/nsCSSKeywords.cpp new file mode 100644 index 00000000000..e5f8c9b2654 --- /dev/null +++ b/mozilla/content/shared/src/nsCSSKeywords.cpp @@ -0,0 +1,389 @@ + +/* +** This is a generated file, do not edit it. This file is created by +** genhash.pl +*/ + +#include "plstr.h" +#include "nsCSSKeywords.h" +#define TOTAL_KEYWORDS 86 +#define MIN_WORD_LENGTH 2 +#define MAX_WORD_LENGTH 12 +#define MIN_HASH_VALUE 8 +#define MAX_HASH_VALUE 322 +/* maximum key range = 315, duplicates = 0 */ + + +struct StaticNameTable { + char* tag; + PRInt32 id; +}; + +static const unsigned char kLowerLookup[256] = { + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, + 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, + 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, + 64, + 97,98,99,100,101,102,103,104,105,106,107,108,109, + 110,111,112,113,114,115,116,117,118,119,120,121,122, + + 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, + + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 +}; + +#define MYLOWER(x) kLowerLookup[((x) & 0x7f)] + +/** + * Map a name to an ID or -1 + */ +PRInt32 nsCSSKeywords::LookupName(const char* str) +{ + static unsigned short asso_values[] = + { + 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 15, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 323, 323, 5, 125, 115, + 35, 0, 5, 55, 60, 110, 0, 5, 0, 5, + 75, 0, 90, 5, 0, 25, 0, 27, 0, 90, + 10, 0, 323, 323, 323, 323, 323, 323, + }; + static unsigned char lengthtable[] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 8, 4, 5, 6, 2, 0, + 0, 0, 0, 2, 0, 0, 0, 11, 2, 0, 0, 0, 11, 0, + 0, 0, 0, 0, 7, 6, 7, 0, 4, 0, 0, 0, 5, 0, + 7, 8, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, + 0, 7, 0, 7, 0, 6, 0, 6, 0, 5, 0, 0, 6, 0, + 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 6, 0, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0, 6, 0, + 8, 9, 0, 0, 0, 0, 9, 0, 6, 7, 8, 0, 0, 11, + 2, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, + 0, 2, 0, 0, 0, 6, 7, 0, 0, 5, 6, 0, 0, 0, + 0, 0, 7, 0, 0, 0, 6, 5, 0, 9, 5, 6, 0, 0, + 4, 0, 6, 7, 0, 0, 0, 0, 0, 8, 4, 5, 0, 0, + 0, 9, 5, 0, 7, 0, 0, 0, 11, 0, 0, 0, 5, 0, + 0, 3, 0, 10, 0, 0, 0, 4, 0, 6, 0, 0, 0, 0, + 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 5, 6, 0, 0, 0, 10, 9, 0, 0, + 0, 0, 0, 0, 11, 0, 0, 6, 0, 0, 0, 0, 6, 0, + 8, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 4, 0, 0, + 7, 0, 0, 0, 9, 0, 0, 0, 0, 6, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 6, 0, 0, 4, 0, 0, 0, 11, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, + 2, + }; + static struct StaticNameTable wordlist[] = + { + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"relative", 56}, + {"left", 32}, + {"large", 30}, + {"larger", 31}, + {"em", 18}, + {"",}, {"",}, {"",}, {"",}, + {"mm", 41}, + {"",}, {"",}, {"",}, + {"transparent", 76}, + {"ex", 19}, + {"",}, {"",}, {"",}, + {"text-bottom", 71}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"x-large", 82}, + {"outset", 48}, + {"outside", 49}, + {"",}, + {"auto", 1}, + {"",}, {"",}, {"",}, + {"small", 63}, + {"",}, + {"smaller", 65}, + {"xx-small", 85}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"medium", 39}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"x-small", 83}, + {"",}, + {"justify", 29}, + {"",}, + {"groove", 21}, + {"",}, + {"square", 67}, + {"",}, + {"solid", 66}, + {"",}, {"",}, + {"double", 17}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"dotted", 16}, + {"",}, {"",}, {"",}, {"",}, + {"normal", 44}, + {"",}, + {"overline", 50}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"pt", 54}, + {"pre", 53}, + {"",}, {"",}, + {"repeat", 57}, + {"",}, + {"xx-large", 84}, + {"no-repeat", 42}, + {"",}, {"",}, {"",}, {"",}, + {"lowercase", 38}, + {"",}, + {"dashed", 13}, + {"noshade", 45}, + {"text-top", 72}, + {"",}, {"",}, + {"lower-alpha", 36}, + {"px", 55}, + {"repeat-y", 59}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"repeat-x", 58}, + {"",}, {"",}, {"",}, + {"cm", 12}, + {"",}, {"",}, {"",}, + {"bolder", 6}, + {"oblique", 47}, + {"",}, {"",}, + {"block", 4}, + {"bottom", 8}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"visible", 81}, + {"",}, {"",}, {"",}, + {"scroll", 62}, + {"super", 70}, + {"",}, + {"list-item", 35}, + {"ridge", 60}, + {"static", 68}, + {"",}, {"",}, + {"none", 43}, + {"",}, + {"middle", 40}, + {"decimal", 14}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"absolute", 0}, + {"bold", 5}, + {"fixed", 20}, + {"",}, {"",}, {"",}, + {"paragraph", 51}, + {"right", 61}, + {"",}, + {"lighter", 33}, + {"",}, {"",}, {"",}, + {"lower-roman", 37}, + {"",}, {"",}, {"",}, + {"thick", 73}, + {"",}, {"",}, + {"top", 75}, + {"",}, + {"small-caps", 64}, + {"",}, {"",}, {"",}, + {"both", 7}, + {"",}, + {"inline", 25}, + {"",}, {"",}, {"",}, {"",}, + {"center", 10}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + + {"inset", 26}, + {"inside", 27}, + {"",}, {"",}, {"",}, + {"capitalize", 9}, + {"uppercase", 80}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"upper-alpha", 78}, + {"",}, {"",}, + {"circle", 11}, + {"",}, {"",}, {"",}, {"",}, + {"italic", 28}, + {"",}, + {"baseline", 2}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"blink", 3}, + {"",}, {"",}, {"",}, + {"thin", 74}, + {"",}, {"",}, + {"inherit", 24}, + {"",}, {"",}, {"",}, + {"underline", 77}, + {"",}, {"",}, {"",}, {"",}, + {"nowrap", 46}, + {"in", 23}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"hidden", 22}, + {"",}, {"",}, + {"disc", 15}, + {"",}, {"",}, {"",}, + {"upper-roman", 79}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, + {"sub", 69}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, + {"line-through", 34}, + {"",}, {"",}, {"",}, {"",}, + {"pc", 52}, + }; + + if (str != NULL) { + int len = PL_strlen(str); + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) { + register int hval = len; + + switch (hval) + { + default: + case 7: + hval += asso_values[MYLOWER(str[6])]; + case 6: + case 5: + case 4: + case 3: + hval += asso_values[MYLOWER(str[2])]; + case 2: + hval += asso_values[MYLOWER(str[1])]; + case 1: + hval += asso_values[MYLOWER(str[0])]; + break; + } + hval += asso_values[MYLOWER(str[len - 1])]; + if (hval <= MAX_HASH_VALUE && hval >= MIN_HASH_VALUE) { + if (len == lengthtable[hval]) { + register const char *tag = wordlist[hval].tag; + + /* + ** While not at the end of the string, if they ever differ + ** they are not equal. We know "tag" is already lower case. + */ + while ((*tag != '\0')&&(*str != '\0')) { + if (*tag != (char) MYLOWER(*str)) { + return -1; + } + tag++; + str++; + } + + /* + ** One of the strings has ended, if they are both ended, then they + ** are equal, otherwise not. + */ + if ((*tag == '\0')&&(*str == '\0')) { + return wordlist[hval].id; + } + } + } + } + } + return -1; +} + +const nsCSSKeywords::NameTableEntry nsCSSKeywords::kNameTable[] = { + { "absolute", 0 }, + { "auto", 1 }, + { "baseline", 2 }, + { "blink", 3 }, + { "block", 4 }, + { "bold", 5 }, + { "bolder", 6 }, + { "both", 7 }, + { "bottom", 8 }, + { "capitalize", 9 }, + { "center", 10 }, + { "circle", 11 }, + { "cm", 12 }, + { "dashed", 13 }, + { "decimal", 14 }, + { "disc", 15 }, + { "dotted", 16 }, + { "double", 17 }, + { "em", 18 }, + { "ex", 19 }, + { "fixed", 20 }, + { "groove", 21 }, + { "hidden", 22 }, + { "in", 23 }, + { "inherit", 24 }, + { "inline", 25 }, + { "inset", 26 }, + { "inside", 27 }, + { "italic", 28 }, + { "justify", 29 }, + { "large", 30 }, + { "larger", 31 }, + { "left", 32 }, + { "lighter", 33 }, + { "line-through", 34 }, + { "list-item", 35 }, + { "lower-alpha", 36 }, + { "lower-roman", 37 }, + { "lowercase", 38 }, + { "medium", 39 }, + { "middle", 40 }, + { "mm", 41 }, + { "no-repeat", 42 }, + { "none", 43 }, + { "normal", 44 }, + { "noshade", 45 }, + { "nowrap", 46 }, + { "oblique", 47 }, + { "outset", 48 }, + { "outside", 49 }, + { "overline", 50 }, + { "paragraph", 51 }, + { "pc", 52 }, + { "pre", 53 }, + { "pt", 54 }, + { "px", 55 }, + { "relative", 56 }, + { "repeat", 57 }, + { "repeat-x", 58 }, + { "repeat-y", 59 }, + { "ridge", 60 }, + { "right", 61 }, + { "scroll", 62 }, + { "small", 63 }, + { "small-caps", 64 }, + { "smaller", 65 }, + { "solid", 66 }, + { "square", 67 }, + { "static", 68 }, + { "sub", 69 }, + { "super", 70 }, + { "text-bottom", 71 }, + { "text-top", 72 }, + { "thick", 73 }, + { "thin", 74 }, + { "top", 75 }, + { "transparent", 76 }, + { "underline", 77 }, + { "upper-alpha", 78 }, + { "upper-roman", 79 }, + { "uppercase", 80 }, + { "visible", 81 }, + { "x-large", 82 }, + { "x-small", 83 }, + { "xx-large", 84 }, + { "xx-small", 85 }, +}; diff --git a/mozilla/content/shared/src/nsCSSProps.cpp b/mozilla/content/shared/src/nsCSSProps.cpp new file mode 100644 index 00000000000..d6de955d6a3 --- /dev/null +++ b/mozilla/content/shared/src/nsCSSProps.cpp @@ -0,0 +1,347 @@ + +/* +** This is a generated file, do not edit it. This file is created by +** genhash.pl +*/ + +#include "plstr.h" +#include "nsCSSProps.h" +#define TOTAL_KEYWORDS 76 +#define MIN_WORD_LENGTH 3 +#define MAX_WORD_LENGTH 21 +#define MIN_HASH_VALUE 6 +#define MAX_HASH_VALUE 212 +/* maximum key range = 207, duplicates = 0 */ + + +struct StaticNameTable { + char* tag; + PRInt32 id; +}; + +static const unsigned char kLowerLookup[256] = { + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, + 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, + 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, + 64, + 97,98,99,100,101,102,103,104,105,106,107,108,109, + 110,111,112,113,114,115,116,117,118,119,120,121,122, + + 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, + + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 +}; + +#define MYLOWER(x) kLowerLookup[((x) & 0x7f)] + +/** + * Map a name to an ID or -1 + */ +PRInt32 nsCSSProps::LookupName(const char* str) +{ + static unsigned char asso_values[] = + { + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 30, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 45, 0, 85, + 45, 25, 5, 20, 80, 0, 213, 213, 25, 75, + 0, 0, 5, 213, 0, 65, 40, 213, 0, 65, + 10, 15, 10, 213, 213, 213, 213, 213, + }; + static unsigned char lengthtable[] = + { + 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 6, 12, 8, + 0, 10, 0, 0, 0, 19, 0, 0, 0, 0, 0, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, + 0, 0, 19, 0, 0, 17, 3, 4, 0, 11, 0, 0, 0, 0, + 0, 0, 18, 0, 0, 0, 12, 0, 0, 0, 11, 17, 0, 19, + 0, 0, 17, 0, 0, 5, 21, 7, 0, 0, 0, 21, 7, 18, + 14, 0, 16, 0, 13, 0, 5, 0, 12, 0, 4, 0, 0, 12, + 8, 19, 10, 16, 17, 0, 9, 10, 16, 0, 0, 0, 0, 0, + 7, 0, 19, 5, 11, 0, 0, 4, 10, 11, 0, 0, 14, 10, + 6, 17, 0, 0, 0, 16, 0, 0, 0, 10, 0, 0, 18, 0, + 0, 0, 12, 0, 0, 0, 16, 0, 0, 0, 5, 21, 0, 0, + 0, 0, 11, 0, 0, 0, 10, 16, 0, 8, 0, 15, 0, 0, + 0, 0, 15, 11, 12, 0, 0, 0, 0, 0, 0, 14, 0, 0, + 12, 13, 9, 0, 0, 0, 0, 0, 0, 6, 0, 0, 14, 0, + 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, + 0, 11, 12, + }; + static struct StaticNameTable wordlist[] = + { + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"border", 9}, + {"",}, {"",}, {"",}, {"",}, + {"filter", 37}, + {"border-color", 14}, + {"position", 64}, + {"",}, + {"border-top", 24}, + {"",}, {"",}, {"",}, + {"border-bottom-color", 11}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"visibility", 71}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, + {"font-family", 40}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"border-bottom-style", 12}, + {"",}, {"",}, + {"border-left-color", 16}, + {"top", 69}, + {"font", 39}, + {"",}, + {"border-left", 15}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"border-right-color", 20}, + {"",}, {"",}, {"",}, + {"border-style", 23}, + {"",}, {"",}, {"",}, + {"padding-top", 63}, + {"background-filter", 3}, + {"",}, + {"background-position", 5}, + {"",}, {"",}, + {"border-left-style", 17}, + {"",}, {"",}, + {"float", 38}, + {"background-x-position", 6}, + {"padding", 59}, + {"",}, {"",}, {"",}, + {"background-y-position", 7}, + {"z-index", 75}, + {"border-right-style", 21}, + {"letter-spacing", 47}, + {"",}, + {"background-image", 4}, + {"",}, + {"border-bottom", 10}, + {"",}, + {"color", 35}, + {"",}, + {"border-right", 19}, + {"",}, + {"left", 46}, + {"",}, {"",}, + {"font-variant", 43}, + {"overflow", 58}, + {"border-bottom-width", 13}, + {"background", 0}, + {"border-top-color", 25}, + {"background-repeat", 8}, + {"",}, + {"font-size", 41}, + {"font-style", 42}, + {"border-top-style", 26}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"display", 36}, + {"",}, + {"list-style-position", 51}, + {"clear", 29}, + {"text-indent", 67}, + {"",}, {"",}, + {"clip", 30}, + {"text-align", 65}, + {"font-weight", 44}, + {"",}, {"",}, + {"vertical-align", 70}, + {"list-style", 49}, + {"margin", 53}, + {"border-left-width", 18}, + {"",}, {"",}, {"",}, + {"list-style-image", 50}, + {"",}, {"",}, {"",}, + {"margin-top", 57}, + {"",}, {"",}, + {"border-right-width", 22}, + {"",}, {"",}, {"",}, + {"padding-left", 61}, + {"",}, {"",}, {"",}, + {"background-color", 2}, + {"",}, {"",}, {"",}, + {"width", 73}, + {"background-attachment", 1}, + {"",}, {"",}, {"",}, {"",}, + {"line-height", 48}, + {"",}, {"",}, {"",}, + {"clip-right", 33}, + {"border-top-width", 27}, + {"",}, + {"clip-top", 34}, + {"",}, + {"text-decoration", 66}, + {"",}, {"",}, {"",}, {"",}, + {"list-style-type", 52}, + {"margin-left", 55}, + {"border-width", 28}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"padding-bottom", 60}, + {"",}, {"",}, + {"word-spacing", 74}, + {"padding-right", 62}, + {"clip-left", 32}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"height", 45}, + {"",}, {"",}, + {"text-transform", 68}, + {"",}, + {"clip-bottom", 31}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, + {"margin-bottom", 54}, + {"",}, {"",}, + {"white-space", 72}, + {"margin-right", 56}, + }; + + if (str != NULL) { + int len = PL_strlen(str); + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) { + register int hval = len; + + switch (hval) + { + default: + case 12: + hval += asso_values[MYLOWER(str[11])]; + case 11: + case 10: + case 9: + case 8: + case 7: + case 6: + hval += asso_values[MYLOWER(str[5])]; + case 5: + case 4: + case 3: + case 2: + hval += asso_values[MYLOWER(str[1])]; + case 1: + hval += asso_values[MYLOWER(str[0])]; + break; + } + hval += asso_values[MYLOWER(str[len - 1])]; + if (hval <= MAX_HASH_VALUE && hval >= MIN_HASH_VALUE) { + if (len == lengthtable[hval]) { + register const char *tag = wordlist[hval].tag; + + /* + ** While not at the end of the string, if they ever differ + ** they are not equal. We know "tag" is already lower case. + */ + while ((*tag != '\0')&&(*str != '\0')) { + if (*tag != (char) MYLOWER(*str)) { + return -1; + } + tag++; + str++; + } + + /* + ** One of the strings has ended, if they are both ended, then they + ** are equal, otherwise not. + */ + if ((*tag == '\0')&&(*str == '\0')) { + return wordlist[hval].id; + } + } + } + } + } + return -1; +} + +const nsCSSProps::NameTableEntry nsCSSProps::kNameTable[] = { + { "background", 0 }, + { "background-attachment", 1 }, + { "background-color", 2 }, + { "background-filter", 3 }, + { "background-image", 4 }, + { "background-position", 5 }, + { "background-x-position", 6 }, + { "background-y-position", 7 }, + { "background-repeat", 8 }, + { "border", 9 }, + { "border-bottom", 10 }, + { "border-bottom-color", 11 }, + { "border-bottom-style", 12 }, + { "border-bottom-width", 13 }, + { "border-color", 14 }, + { "border-left", 15 }, + { "border-left-color", 16 }, + { "border-left-style", 17 }, + { "border-left-width", 18 }, + { "border-right", 19 }, + { "border-right-color", 20 }, + { "border-right-style", 21 }, + { "border-right-width", 22 }, + { "border-style", 23 }, + { "border-top", 24 }, + { "border-top-color", 25 }, + { "border-top-style", 26 }, + { "border-top-width", 27 }, + { "border-width", 28 }, + { "clear", 29 }, + { "clip", 30 }, + { "clip-bottom", 31 }, + { "clip-left", 32 }, + { "clip-right", 33 }, + { "clip-top", 34 }, + { "color", 35 }, + { "display", 36 }, + { "filter", 37 }, + { "float", 38 }, + { "font", 39 }, + { "font-family", 40 }, + { "font-size", 41 }, + { "font-style", 42 }, + { "font-variant", 43 }, + { "font-weight", 44 }, + { "height", 45 }, + { "left", 46 }, + { "letter-spacing", 47 }, + { "line-height", 48 }, + { "list-style", 49 }, + { "list-style-image", 50 }, + { "list-style-position", 51 }, + { "list-style-type", 52 }, + { "margin", 53 }, + { "margin-bottom", 54 }, + { "margin-left", 55 }, + { "margin-right", 56 }, + { "margin-top", 57 }, + { "overflow", 58 }, + { "padding", 59 }, + { "padding-bottom", 60 }, + { "padding-left", 61 }, + { "padding-right", 62 }, + { "padding-top", 63 }, + { "position", 64 }, + { "text-align", 65 }, + { "text-decoration", 66 }, + { "text-indent", 67 }, + { "text-transform", 68 }, + { "top", 69 }, + { "vertical-align", 70 }, + { "visibility", 71 }, + { "white-space", 72 }, + { "width", 73 }, + { "word-spacing", 74 }, + { "z-index", 75 }, +}; diff --git a/mozilla/content/shared/src/nsHTMLAtoms.cpp b/mozilla/content/shared/src/nsHTMLAtoms.cpp new file mode 100644 index 00000000000..377ed58e605 --- /dev/null +++ b/mozilla/content/shared/src/nsHTMLAtoms.cpp @@ -0,0 +1,367 @@ +/* -*- 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 "nsHTMLAtoms.h" + +nsIAtom* nsHTMLAtoms::a; +nsIAtom* nsHTMLAtoms::above; +nsIAtom* nsHTMLAtoms::action; +nsIAtom* nsHTMLAtoms::align; +nsIAtom* nsHTMLAtoms::alink; +nsIAtom* nsHTMLAtoms::alt; +nsIAtom* nsHTMLAtoms::archive; +nsIAtom* nsHTMLAtoms::background; +nsIAtom* nsHTMLAtoms::below; +nsIAtom* nsHTMLAtoms::bgcolor; +nsIAtom* nsHTMLAtoms::body; +nsIAtom* nsHTMLAtoms::border; +nsIAtom* nsHTMLAtoms::bordercolor; +nsIAtom* nsHTMLAtoms::bottompadding; +nsIAtom* nsHTMLAtoms::br; +nsIAtom* nsHTMLAtoms::cellpadding; +nsIAtom* nsHTMLAtoms::cellspacing; +nsIAtom* nsHTMLAtoms::checked; +nsIAtom* nsHTMLAtoms::kClass; +nsIAtom* nsHTMLAtoms::classid; +nsIAtom* nsHTMLAtoms::clear; +nsIAtom* nsHTMLAtoms::clip; +nsIAtom* nsHTMLAtoms::code; +nsIAtom* nsHTMLAtoms::codebase; +nsIAtom* nsHTMLAtoms::color; +nsIAtom* nsHTMLAtoms::cols; +nsIAtom* nsHTMLAtoms::colspan; +nsIAtom* nsHTMLAtoms::compact; +nsIAtom* nsHTMLAtoms::coords; +nsIAtom* nsHTMLAtoms::data; +nsIAtom* nsHTMLAtoms::dir; +nsIAtom* nsHTMLAtoms::div; +nsIAtom* nsHTMLAtoms::dl; +nsIAtom* nsHTMLAtoms::encoding; +nsIAtom* nsHTMLAtoms::face; +nsIAtom* nsHTMLAtoms::font; +nsIAtom* nsHTMLAtoms::fontWeight; +nsIAtom* nsHTMLAtoms::frameborder; +nsIAtom* nsHTMLAtoms::gutter; +nsIAtom* nsHTMLAtoms::h1; +nsIAtom* nsHTMLAtoms::h2; +nsIAtom* nsHTMLAtoms::h3; +nsIAtom* nsHTMLAtoms::h4; +nsIAtom* nsHTMLAtoms::h5; +nsIAtom* nsHTMLAtoms::h6; +nsIAtom* nsHTMLAtoms::height; +nsIAtom* nsHTMLAtoms::hidden; +nsIAtom* nsHTMLAtoms::href; +nsIAtom* nsHTMLAtoms::hspace; +nsIAtom* nsHTMLAtoms::httpEquiv; +nsIAtom* nsHTMLAtoms::id; +nsIAtom* nsHTMLAtoms::ismap; +nsIAtom* nsHTMLAtoms::language; +nsIAtom* nsHTMLAtoms::li; +nsIAtom* nsHTMLAtoms::link; +nsIAtom* nsHTMLAtoms::left; +nsIAtom* nsHTMLAtoms::leftpadding; +nsIAtom* nsHTMLAtoms::lowsrc; +nsIAtom* nsHTMLAtoms::marginheight; +nsIAtom* nsHTMLAtoms::marginwidth; +nsIAtom* nsHTMLAtoms::maxlength; +nsIAtom* nsHTMLAtoms::mayscript; +nsIAtom* nsHTMLAtoms::menu; +nsIAtom* nsHTMLAtoms::method; +nsIAtom* nsHTMLAtoms::multicol; +nsIAtom* nsHTMLAtoms::multiple; +nsIAtom* nsHTMLAtoms::name; +nsIAtom* nsHTMLAtoms::noresize; +nsIAtom* nsHTMLAtoms::noshade; +nsIAtom* nsHTMLAtoms::nowrap; +nsIAtom* nsHTMLAtoms::ol; +nsIAtom* nsHTMLAtoms::onblur; +nsIAtom* nsHTMLAtoms::onfocus; +nsIAtom* nsHTMLAtoms::onload; +nsIAtom* nsHTMLAtoms::onunload; +nsIAtom* nsHTMLAtoms::overflow; +nsIAtom* nsHTMLAtoms::p; +nsIAtom* nsHTMLAtoms::pagex; +nsIAtom* nsHTMLAtoms::pagey; +nsIAtom* nsHTMLAtoms::pointSize; +nsIAtom* nsHTMLAtoms::pre; +nsIAtom* nsHTMLAtoms::prompt; +nsIAtom* nsHTMLAtoms::rel; +nsIAtom* nsHTMLAtoms::rightpadding; +nsIAtom* nsHTMLAtoms::rows; +nsIAtom* nsHTMLAtoms::rowspan; +nsIAtom* nsHTMLAtoms::scrolling; +nsIAtom* nsHTMLAtoms::selected; +nsIAtom* nsHTMLAtoms::shape; +nsIAtom* nsHTMLAtoms::size; +nsIAtom* nsHTMLAtoms::src; +nsIAtom* nsHTMLAtoms::start; +nsIAtom* nsHTMLAtoms::suppress; +nsIAtom* nsHTMLAtoms::tabstop; +nsIAtom* nsHTMLAtoms::target; +nsIAtom* nsHTMLAtoms::text; +nsIAtom* nsHTMLAtoms::top; +nsIAtom* nsHTMLAtoms::toppadding; +nsIAtom* nsHTMLAtoms::type; +nsIAtom* nsHTMLAtoms::ul; +nsIAtom* nsHTMLAtoms::usemap; +nsIAtom* nsHTMLAtoms::valign; +nsIAtom* nsHTMLAtoms::value; +nsIAtom* nsHTMLAtoms::variable; +nsIAtom* nsHTMLAtoms::visibility; +nsIAtom* nsHTMLAtoms::vlink; +nsIAtom* nsHTMLAtoms::vspace; +nsIAtom* nsHTMLAtoms::width; +nsIAtom* nsHTMLAtoms::wrap; +nsIAtom* nsHTMLAtoms::zindex; + + +static nsrefcnt gRefCnt; + +void nsHTMLAtoms::AddrefAtoms() +{ + if (0 == gRefCnt) { + a = NS_NewAtom("A"); + above = NS_NewAtom("ABOVE"); + action = NS_NewAtom("ACTION"); + align = NS_NewAtom("ALIGN"); + alink = NS_NewAtom("ALINK"); + alt = NS_NewAtom("ALT"); + archive = NS_NewAtom("ARCHIVE"); + background = NS_NewAtom("BACKGROUND"); + below = NS_NewAtom("BELOW"); + bgcolor = NS_NewAtom("BGCOLOR"); + body = NS_NewAtom("BODY"); + border = NS_NewAtom("BORDER"); + bordercolor = NS_NewAtom("BORDERCOLOR"); + bottompadding = NS_NewAtom("BOTTOMPADDING"); + br = NS_NewAtom("BR"); + cellpadding = NS_NewAtom("CELLPADDING"); + cellspacing = NS_NewAtom("CELLSPACING"); + checked = NS_NewAtom("CHECKED"); + kClass = NS_NewAtom("CLASS"); + classid = NS_NewAtom("CLASSID"); + clear = NS_NewAtom("CLEAR"); + clip = NS_NewAtom("CLIP"); + code = NS_NewAtom("CODE"); + codebase = NS_NewAtom("CODEBASE"); + color = NS_NewAtom("COLOR"); + cols = NS_NewAtom("COLS"); + colspan = NS_NewAtom("COLSPAN"); + compact = NS_NewAtom("COMPACT"); + coords = NS_NewAtom("COORDS"); + dir = NS_NewAtom("DIR"); + div = NS_NewAtom("DIV"); + dl = NS_NewAtom("DL"); + data = NS_NewAtom("DATA"); + encoding = NS_NewAtom("ENCODING"); + face = NS_NewAtom("FACE"); + font = NS_NewAtom("FONT"); + fontWeight = NS_NewAtom("FONT-WEIGHT"); + frameborder = NS_NewAtom("FRAMEBORDER"); + gutter = NS_NewAtom("GUTTER"); + h1 = NS_NewAtom("H1"); + h2 = NS_NewAtom("H2"); + h3 = NS_NewAtom("H3"); + h4 = NS_NewAtom("H4"); + h5 = NS_NewAtom("H5"); + h6 = NS_NewAtom("H6"); + height = NS_NewAtom("HEIGHT"); + hidden = NS_NewAtom("HIDDEN"); + href = NS_NewAtom("HREF"); + hspace = NS_NewAtom("HSPACE"); + httpEquiv = NS_NewAtom("HTTP-EQUIV"); + id = NS_NewAtom("ID"); + ismap = NS_NewAtom("ISMAP"); + language = NS_NewAtom("LANGUAGE"); + li = NS_NewAtom("LI"); + link = NS_NewAtom("LINK"); + left = NS_NewAtom("LEFT"); + leftpadding = NS_NewAtom("LEFTPADDING"); + lowsrc = NS_NewAtom("LOWSRC"); + marginheight = NS_NewAtom("MARGINHEIGHT"); + marginwidth = NS_NewAtom("MARGINWIDTH"); + maxlength = NS_NewAtom("MAXLENGTH"); + mayscript = NS_NewAtom("MAYSCRIPT"); + menu = NS_NewAtom("MENU"); + method = NS_NewAtom("METHOD"); + multicol = NS_NewAtom("MULTICOL"); + multiple = NS_NewAtom("MULTIPLE"); + name = NS_NewAtom("NAME"); + noresize = NS_NewAtom("NORESIZE"); + noshade = NS_NewAtom("NOSHADE"); + nowrap = NS_NewAtom("NOWRAP"); + ol = NS_NewAtom("OL"); + onblur = NS_NewAtom("ONBLUR"); + onfocus = NS_NewAtom("ONFOCUS"); + onload = NS_NewAtom("ONLOAD"); + onunload = NS_NewAtom("ONUNLOAD"); + overflow = NS_NewAtom("OVERFLOW"); + p = NS_NewAtom("P"); + pagex = NS_NewAtom("PAGEX"); + pagey = NS_NewAtom("PAGEY"); + pointSize = NS_NewAtom("POINT-SIZE"); + pre = NS_NewAtom("PRE"); + prompt = NS_NewAtom("PROMPT"); + rel = NS_NewAtom("REL"); + rightpadding = NS_NewAtom("RIGHTPADDING"); + rows = NS_NewAtom("ROWS"); + rowspan = NS_NewAtom("ROWSPAN"); + scrolling = NS_NewAtom("SCROLLING"); + selected = NS_NewAtom("SELECTED"); + shape = NS_NewAtom("SHAPE"); + size = NS_NewAtom("SIZE"); + src = NS_NewAtom("SRC"); + start = NS_NewAtom("START"); + suppress = NS_NewAtom("SUPPRESS"); + tabstop = NS_NewAtom("TABSTOP"); + target = NS_NewAtom("TARGET"); + text = NS_NewAtom("TEXT"); + top = NS_NewAtom("TOP"); + toppadding = NS_NewAtom("TOPPADDING"); + type = NS_NewAtom("TYPE"); + ul = NS_NewAtom("UL"); + usemap = NS_NewAtom("USEMAP"); + valign = NS_NewAtom("VALIGN"); + value = NS_NewAtom("VALUE"); + variable = NS_NewAtom("VARIABLE"); + visibility = NS_NewAtom("VISIBILITY"); + vlink = NS_NewAtom("VLINK"); + vspace = NS_NewAtom("VSPACE"); + width = NS_NewAtom("WIDTH"); + wrap = NS_NewAtom("WRAP"); + zindex = NS_NewAtom("ZINDEX"); + } + ++gRefCnt; +} + +void nsHTMLAtoms::ReleaseAtoms() +{ + NS_PRECONDITION(gRefCnt != 0, "bad release atoms"); + if (--gRefCnt == 0) { + NS_RELEASE(a); + NS_RELEASE(above); + NS_RELEASE(action); + NS_RELEASE(align); + NS_RELEASE(alink); + NS_RELEASE(alt); + NS_RELEASE(archive); + NS_RELEASE(background); + NS_RELEASE(below); + NS_RELEASE(bgcolor); + NS_RELEASE(body); + NS_RELEASE(border); + NS_RELEASE(bordercolor); + NS_RELEASE(bottompadding); + NS_RELEASE(br); + NS_RELEASE(cellpadding); + NS_RELEASE(cellspacing); + NS_RELEASE(checked); + NS_RELEASE(kClass); + NS_RELEASE(classid); + NS_RELEASE(clear); + NS_RELEASE(clip); + NS_RELEASE(code); + NS_RELEASE(codebase); + NS_RELEASE(color); + NS_RELEASE(cols); + NS_RELEASE(colspan); + NS_RELEASE(compact); + NS_RELEASE(coords); + NS_RELEASE(dir); + NS_RELEASE(div); + NS_RELEASE(dl); + NS_RELEASE(data); + NS_RELEASE(encoding); + NS_RELEASE(face); + NS_RELEASE(font); + NS_RELEASE(fontWeight); + NS_RELEASE(frameborder); + NS_RELEASE(gutter); + NS_RELEASE(h1); + NS_RELEASE(h2); + NS_RELEASE(h3); + NS_RELEASE(h4); + NS_RELEASE(h5); + NS_RELEASE(h6); + NS_RELEASE(height); + NS_RELEASE(hidden); + NS_RELEASE(href); + NS_RELEASE(hspace); + NS_RELEASE(httpEquiv); + NS_RELEASE(id); + NS_RELEASE(ismap); + NS_RELEASE(language); + NS_RELEASE(li); + NS_RELEASE(link); + NS_RELEASE(left); + NS_RELEASE(leftpadding); + NS_RELEASE(lowsrc); + NS_RELEASE(marginheight); + NS_RELEASE(marginwidth); + NS_RELEASE(maxlength); + NS_RELEASE(mayscript); + NS_RELEASE(menu); + NS_RELEASE(method); + NS_RELEASE(multicol); + NS_RELEASE(multiple); + NS_RELEASE(name); + NS_RELEASE(noresize); + NS_RELEASE(noshade); + NS_RELEASE(nowrap); + NS_RELEASE(ol); + NS_RELEASE(onblur); + NS_RELEASE(onfocus); + NS_RELEASE(onload); + NS_RELEASE(onunload); + NS_RELEASE(overflow); + NS_RELEASE(p); + NS_RELEASE(pagex); + NS_RELEASE(pagey); + NS_RELEASE(pointSize); + NS_RELEASE(pre); + NS_RELEASE(prompt); + NS_RELEASE(rel); + NS_RELEASE(rightpadding); + NS_RELEASE(rows); + NS_RELEASE(rowspan); + NS_RELEASE(scrolling); + NS_RELEASE(selected); + NS_RELEASE(shape); + NS_RELEASE(size); + NS_RELEASE(src); + NS_RELEASE(start); + NS_RELEASE(suppress); + NS_RELEASE(tabstop); + NS_RELEASE(target); + NS_RELEASE(text); + NS_RELEASE(top); + NS_RELEASE(toppadding); + NS_RELEASE(type); + NS_RELEASE(ul); + NS_RELEASE(usemap); + NS_RELEASE(valign); + NS_RELEASE(value); + NS_RELEASE(variable); + NS_RELEASE(visibility); + NS_RELEASE(vlink); + NS_RELEASE(vspace); + NS_RELEASE(width); + NS_RELEASE(wrap); + NS_RELEASE(zindex); + } +} + diff --git a/mozilla/content/shared/src/nsHTMLValue.cpp b/mozilla/content/shared/src/nsHTMLValue.cpp new file mode 100644 index 00000000000..ed2df9aaab5 --- /dev/null +++ b/mozilla/content/shared/src/nsHTMLValue.cpp @@ -0,0 +1,257 @@ +/* -*- 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 "nsHTMLValue.h" +#include "nsString.h" +#include "nsCRT.h" + +const nsHTMLValue nsHTMLValue::kNull; + +nsHTMLValue::nsHTMLValue(void) + : mUnit(eHTMLUnit_Null) +{ + mValue.mString = nsnull; +} + +nsHTMLValue::nsHTMLValue(PRInt32 aValue, nsHTMLUnit aUnit) + : mUnit(aUnit) +{ + mValue.mInt = aValue; +} + +nsHTMLValue::nsHTMLValue(float aValue, nsHTMLUnit aUnit) + : mUnit(aUnit) +{ + mValue.mFloat = aValue; +} + +nsHTMLValue::nsHTMLValue(const nsString& aValue) + : mUnit(eHTMLUnit_String) +{ + mValue.mString = aValue.ToNewString(); +} + +nsHTMLValue::nsHTMLValue(nsISupports* aValue) + : mUnit(eHTMLUnit_ISupports) +{ + mValue.mISupports = aValue; + NS_IF_ADDREF(mValue.mISupports); +} + +nsHTMLValue::nsHTMLValue(nscolor aValue) + : mUnit(eHTMLUnit_Color) +{ + mValue.mColor = aValue; +} + +nsHTMLValue::nsHTMLValue(const nsHTMLValue& aCopy) + : mUnit(aCopy.mUnit) +{ + if (eHTMLUnit_String == mUnit) { + if (nsnull != aCopy.mValue.mString) { + mValue.mString = aCopy.mValue.mString->ToNewString(); + } + else { + mValue.mString = nsnull; + } + } + else if (eHTMLUnit_ISupports == mUnit) { + mValue.mISupports = aCopy.mValue.mISupports; + NS_IF_ADDREF(mValue.mISupports); + } + else if (eHTMLUnit_Color == mUnit){ + mValue.mColor = aCopy.mValue.mColor; + } + else if (eHTMLUnit_Percent == mUnit) { + mValue.mFloat = aCopy.mValue.mFloat; + } + else { + mValue.mInt = aCopy.mValue.mInt; + } +} + +nsHTMLValue::~nsHTMLValue(void) +{ + Reset(); +} + +nsHTMLValue& nsHTMLValue::operator=(const nsHTMLValue& aCopy) +{ + Reset(); + mUnit = aCopy.mUnit; + if (eHTMLUnit_String == mUnit) { + if (nsnull != aCopy.mValue.mString) { + mValue.mString = aCopy.mValue.mString->ToNewString(); + } + } + else if (eHTMLUnit_ISupports == mUnit) { + mValue.mISupports = aCopy.mValue.mISupports; + NS_IF_ADDREF(mValue.mISupports); + } + else if (eHTMLUnit_Color == mUnit){ + mValue.mColor = aCopy.mValue.mColor; + } + else if (eHTMLUnit_Percent == mUnit) { + mValue.mFloat = aCopy.mValue.mFloat; + } + else { + mValue.mInt = aCopy.mValue.mInt; + } + return *this; +} + +PRBool nsHTMLValue::operator==(const nsHTMLValue& aOther) const +{ + if (mUnit == aOther.mUnit) { + if (eHTMLUnit_String == mUnit) { + if (nsnull == mValue.mString) { + if (nsnull == aOther.mValue.mString) { + return PR_TRUE; + } + } + else if (nsnull != aOther.mValue.mString) { + return mValue.mString->Equals(*(aOther.mValue.mString)); + } + } + else if (eHTMLUnit_ISupports == mUnit) { + return PRBool(mValue.mISupports == aOther.mValue.mISupports); + } + else if (eHTMLUnit_Color == mUnit){ + return PRBool(mValue.mColor == aOther.mValue.mColor); + } + else if (eHTMLUnit_Percent == mUnit) { + return PRBool(mValue.mFloat == aOther.mValue.mFloat); + } + else { + return PRBool(mValue.mInt == aOther.mValue.mInt); + } + } + return PR_FALSE; +} + +void nsHTMLValue::Reset(void) +{ + if (eHTMLUnit_String == mUnit) { + if (nsnull != mValue.mString) { + delete mValue.mString; + } + } + else if (eHTMLUnit_ISupports == mUnit) { + NS_IF_RELEASE(mValue.mISupports); + } + mUnit = eHTMLUnit_Null; + mValue.mString = nsnull; +} + + +void nsHTMLValue::Set(PRInt32 aValue, nsHTMLUnit aUnit) +{ + Reset(); + mUnit = aUnit; + mValue.mInt = aValue; +} + +void nsHTMLValue::Set(float aValue, nsHTMLUnit aUnit) +{ + Reset(); + mUnit = aUnit; + mValue.mFloat = aValue; +} + +void nsHTMLValue::Set(const nsString& aValue) +{ + Reset(); + mUnit = eHTMLUnit_String; + mValue.mString = aValue.ToNewString(); +} + +void nsHTMLValue::Set(nsISupports* aValue) +{ + Reset(); + mUnit = eHTMLUnit_ISupports; + mValue.mISupports = aValue; + NS_IF_ADDREF(mValue.mISupports); +} + +void nsHTMLValue::Set(nscolor aValue) +{ + Reset(); + mUnit = eHTMLUnit_Color; + mValue.mColor = aValue; +} + +void nsHTMLValue::AppendToString(nsString& aBuffer) const +{ + if (eHTMLUnit_Null == mUnit) { + return; + } + + if (eHTMLUnit_String == mUnit) { + if (nsnull != mValue.mString) { + aBuffer.Append('"'); + aBuffer.Append(*(mValue.mString)); + aBuffer.Append('"'); + } + else { + aBuffer.Append("null str"); + } + } + else if (eHTMLUnit_ISupports == mUnit) { + aBuffer.Append("0x"); + aBuffer.Append((PRInt32)mValue.mISupports, 16); + } + else if (eHTMLUnit_Color == mUnit){ + aBuffer.Append("(0x"); + aBuffer.Append(NS_GET_R(mValue.mColor), 16); + aBuffer.Append(" 0x"); + aBuffer.Append(NS_GET_G(mValue.mColor), 16); + aBuffer.Append(" 0x"); + aBuffer.Append(NS_GET_B(mValue.mColor), 16); + aBuffer.Append(" 0x"); + aBuffer.Append(NS_GET_A(mValue.mColor), 16); + aBuffer.Append(')'); + } + else if (eHTMLUnit_Percent == mUnit) { + aBuffer.Append(mValue.mFloat); + } + else { + aBuffer.Append(mValue.mInt, 10); + aBuffer.Append("[0x"); + aBuffer.Append(mValue.mInt, 16); + aBuffer.Append(']'); + } + + switch (mUnit) { + case eHTMLUnit_Null: break; + case eHTMLUnit_String: break; + case eHTMLUnit_ISupports: aBuffer.Append("ptr"); break; + case eHTMLUnit_Absolute: break; + case eHTMLUnit_Enumerated: aBuffer.Append("enum"); break; + case eHTMLUnit_Color: aBuffer.Append("rbga"); break; + case eHTMLUnit_Percent: aBuffer.Append("%"); break; + case eHTMLUnit_Pixel: aBuffer.Append("px"); break; + } + aBuffer.Append(' '); +} + +void nsHTMLValue::ToString(nsString& aBuffer) const +{ + aBuffer.SetLength(0); + AppendToString(aBuffer); +} + diff --git a/mozilla/dom/Makefile b/mozilla/dom/Makefile new file mode 100644 index 00000000000..afe6eeaaadd --- /dev/null +++ b/mozilla/dom/Makefile @@ -0,0 +1,24 @@ +#!gmake +# +# 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. + +DEPTH = .. + +DIRS = public src + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/dom/makefile.win b/mozilla/dom/makefile.win new file mode 100644 index 00000000000..1166b03f914 --- /dev/null +++ b/mozilla/dom/makefile.win @@ -0,0 +1,22 @@ +#!nmake +# +# 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. + +DEPTH=.. + +DIRS= public src + +include <$(DEPTH)\config\rules.mak> diff --git a/mozilla/dom/public/Makefile b/mozilla/dom/public/Makefile new file mode 100644 index 00000000000..c3895219e1f --- /dev/null +++ b/mozilla/dom/public/Makefile @@ -0,0 +1,34 @@ +#!gmake +# +# 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. + +DEPTH=../.. + +DIRS = coreDom + +DEFINES = -D_IMPL_NS_DOM + +EXPORTS = \ + nsIScriptContext.h \ + nsIScriptObject.h \ + nsIScriptObjectOwner.h \ + $(NULL) + +MODULE = dom + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/dom/public/coreDom/Makefile b/mozilla/dom/public/coreDom/Makefile new file mode 100644 index 00000000000..60576682b39 --- /dev/null +++ b/mozilla/dom/public/coreDom/Makefile @@ -0,0 +1,38 @@ +#!gmake +# +# 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. + +DEPTH=../../.. + +DEFINES = -D_IMPL_NS_DOM + +EXPORTS = \ + nsDOM.h \ + nsIDOMAttribute.h \ + nsIDOMComment.h \ + nsIDOMDocument.h \ + nsIDOMElement.h \ + nsIDOMIterators.h \ + nsIDOMNode.h \ + nsIDOMPI.h \ + nsIDOMText.h \ + $(NULL) + +MODULE = dom + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/dom/public/coreDom/makefile.win b/mozilla/dom/public/coreDom/makefile.win new file mode 100644 index 00000000000..3c57bcd179a --- /dev/null +++ b/mozilla/dom/public/coreDom/makefile.win @@ -0,0 +1,28 @@ +#!nmake +# +# 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. + +DEPTH=..\..\.. +IGNORE_MANIFEST=1 + +DEFINES=-D_IMPL_NS_DOM +EXPORTS=nsDOM.h nsIDOMAttribute.h nsIDOMComment.h nsIDOMDocument.h \ + nsIDOMElement.h nsIDOMIterators.h nsIDOMNode.h nsIDOMPI.h \ + nsIDOMText.h +MODULE=dom + +include <$(DEPTH)\config\rules.mak> + diff --git a/mozilla/dom/public/coreDom/nsDOM.h b/mozilla/dom/public/coreDom/nsDOM.h new file mode 100644 index 00000000000..725b2c90079 --- /dev/null +++ b/mozilla/dom/public/coreDom/nsDOM.h @@ -0,0 +1,39 @@ +/* -*- 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. + */ + +#ifndef nsDOM_h__ +#define nsDOM_h__ + +#include "nsISupports.h" + +class nsIDOMDocument; +class nsString; + +#define NS_IDOM_IID \ +{ /* 8f6bca70-ce42-11d1-b724-00600891d8c9 */ \ +0x8f6bca70, 0xce42, 0x11d1, \ + {0xb7, 0x24, 0x00, 0x60, 0x08, 0x91, 0xd8, 0xc9} } + +class nsIDOM : public nsISupports { +public: + virtual nsresult CreateDocument(nsString &type, nsIDOMDocument** aDocument) = 0; + virtual nsresult HasFeature(nsString &aFeature) = 0; +}; + + +#endif // nsDOM_h__ diff --git a/mozilla/dom/public/coreDom/nsIDOMAttribute.h b/mozilla/dom/public/coreDom/nsIDOMAttribute.h new file mode 100644 index 00000000000..11c6a9038a9 --- /dev/null +++ b/mozilla/dom/public/coreDom/nsIDOMAttribute.h @@ -0,0 +1,61 @@ +/* -*- 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. + */ + +#ifndef nsIDOMAttribute_h__ +#define nsIDOMAttribute_h__ + +#include "nsDOM.h" +#include "nsISupports.h" + +// forward declaration +class nsIDOMNode; + +#define NS_IDOMATTRIBUTE_IID \ +{ /* 8f6bca77-ce42-11d1-b724-00600891d8c9 */ \ +0x8f6bca77, 0xce42, 0x11d1, \ + {0xb7, 0x24, 0x00, 0x60, 0x08, 0x91, 0xd8, 0xc9} } + +class nsIDOMAttribute : public nsISupports { +public: + virtual nsresult GetName(nsString &aName) = 0; + //attribute Node value; + virtual nsresult GetValue(nsString &aName /*nsIDOMNode **aValue*/) = 0; + virtual nsresult SetValue(nsString &aName /*nsIDOMNode *aValue*/) = 0; + //attribute boolean specified; + virtual nsresult GetSpecified() = 0; + virtual nsresult SetSpecified(PRBool specified) = 0; + virtual nsresult ToString(nsString &aString) = 0; +}; + +#define NS_IDOMATTRIBUTELIST_IID \ +{ /* 8f6bca78-ce42-11d1-b724-00600891d8c9 */ \ +0x8f6bca78, 0xce42, 0x11d1, \ + {0xb7, 0x24, 0x00, 0x60, 0x08, 0x91, 0xd8, 0xc9} } + +class nsIDOMAttributeList : public nsISupports { +public: + virtual nsresult GetAttribute(nsString &aAttrName, nsIDOMAttribute** aAttribute) = 0; + virtual nsresult SetAttribute(nsIDOMAttribute *attr) = 0; + virtual nsresult Remove(nsString &attrName, nsIDOMAttribute** aAttribute) = 0; + virtual nsresult Item(PRUint32 aIndex, nsIDOMAttribute** aAttribute) = 0; + virtual nsresult GetLength(PRUint32 *aLength) = 0; +}; + + +#endif // nsIDOMAttribute_h__ + diff --git a/mozilla/dom/public/coreDom/nsIDOMComment.h b/mozilla/dom/public/coreDom/nsIDOMComment.h new file mode 100644 index 00000000000..30131679860 --- /dev/null +++ b/mozilla/dom/public/coreDom/nsIDOMComment.h @@ -0,0 +1,38 @@ +/* -*- 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. + */ + +#ifndef nsIDOMComment_h__ +#define nsIDOMComment_h__ + +#include "nsDOM.h" +#include "nsIDOMNode.h" + +#define NS_IDOMCOMMENT_IID \ +{ /* 8f6bca7a-ce42-11d1-b724-00600891d8c9 */ \ +0x8f6bca7a, 0xce42, 0x11d1, \ + {0xb7, 0x24, 0x00, 0x60, 0x08, 0x91, 0xd8, 0xc9} } + +class nsIDOMComment : public nsIDOMNode { +public: + //attribute UniString data; + virtual nsresult GetData(nsString &aData) = 0; + virtual nsresult SetData(nsString &aData) = 0; +}; + +#endif // nsIDOMComment_h__ + diff --git a/mozilla/dom/public/coreDom/nsIDOMDocument.h b/mozilla/dom/public/coreDom/nsIDOMDocument.h new file mode 100644 index 00000000000..dbe467dafa9 --- /dev/null +++ b/mozilla/dom/public/coreDom/nsIDOMDocument.h @@ -0,0 +1,96 @@ +/* -*- 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. + */ + +#ifndef nsIDOMDocument_h__ +#define nsIDOMDocument_h__ + +#include "nsDOM.h" +#include "nsISupports.h" +#include "nsIDOMNode.h" + +// forward declaration +class nsIDOMDocument; +class nsIDOMElement; +class nsIDOMText; +class nsIDOMComment; +class nsIDOMPI; +class nsIDOMAttribute; +class nsIDOMAttributeList; +class nsIDOMNodeIterator; +class nsIDOMTreeIterator; + +#define NS_IDOMDOCUMENTCONTEXT_IID \ +{ /* 8f6bca71-ce42-11d1-b724-00600891d8c9 */ \ +0x8f6bca71, 0xce42, 0x11d1, \ + {0xb7, 0x24, 0x00, 0x60, 0x08, 0x91, 0xd8, 0xc9} } + +class nsIDOMDocumentContext : public nsISupports { +public: + //attribute Document document; + virtual nsresult GetDocument(nsIDOMDocument **aDocument) = 0; + virtual nsresult SetDocument(nsIDOMDocument *aDocument) = 0; +}; + +#define NS_IDOMDOCUMENTFRAGMENT_IID \ +{ /* 8f6bca72-ce42-11d1-b724-00600891d8c9 */ \ +0x8f6bca72, 0xce42, 0x11d1, \ + {0xb7, 0x24, 0x00, 0x60, 0x08, 0x91, 0xd8, 0xc9} } + +class nsIDOMDocumentFragment : public nsIDOMNode { +public: + //attribute Document masterDoc; + virtual nsresult GetMasterDoc(nsIDOMDocument **aDocument) = 0; + virtual nsresult SetMasterDoc(nsIDOMDocument *aDocument) = 0; +}; + +#define NS_IDOMDOCUMENT_IID \ +{ /* 8f6bca73-ce42-11d1-b724-00600891d8c9 */ \ +0x8f6bca73, 0xce42, 0x11d1, \ + {0xb7, 0x24, 0x00, 0x60, 0x08, 0x91, 0xd8, 0xc9} } + +class nsIDOMDocument : public nsIDOMDocumentFragment { +public: + //attribute Node documentType; + virtual nsresult GetDocumentType(nsIDOMNode **aDocType) = 0; + virtual nsresult SetDocumentType(nsIDOMNode *aNode) = 0; + + //attribute Element documentElement; + virtual nsresult GetDocumentElement(nsIDOMElement **aElement) = 0; + virtual nsresult SetDocumentElement(nsIDOMElement *aElement) = 0; + + //attribute DocumentContext contextInfo; + virtual nsresult GetDocumentContext(nsIDOMDocumentContext **aDocContext) = 0; + virtual nsresult SetDocumentContext(nsIDOMDocumentContext *aContext) = 0; + + virtual nsresult CreateDocumentContext(nsIDOMDocumentContext **aDocContext) = 0; + virtual nsresult CreateElement(nsString &aTagName, + nsIDOMAttributeList *aAttributes, + nsIDOMElement **aElement) = 0; + virtual nsresult CreateTextNode(nsString &aData, nsIDOMText** aTextNode) = 0; + virtual nsresult CreateComment(nsString &aData, nsIDOMComment **aComment) = 0; + virtual nsresult CreatePI(nsString &aName, nsString &aData, nsIDOMPI **aPI) = 0; + virtual nsresult CreateAttribute(nsString &aName, + nsIDOMNode *value, + nsIDOMAttribute **aAttribute) = 0; + virtual nsresult CreateAttributeList(nsIDOMAttributeList **aAttributesList) = 0; + virtual nsresult CreateTreeIterator(nsIDOMNode **aNode, nsIDOMTreeIterator **aTreeIterator) = 0; + virtual nsresult GetElementsByTagName(nsIDOMNodeIterator **aIterator) = 0; +}; + +#endif // nsIDOMDocument_h__ + diff --git a/mozilla/dom/public/coreDom/nsIDOMElement.h b/mozilla/dom/public/coreDom/nsIDOMElement.h new file mode 100644 index 00000000000..e18e13f1940 --- /dev/null +++ b/mozilla/dom/public/coreDom/nsIDOMElement.h @@ -0,0 +1,50 @@ +/* -*- 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. + */ + +#ifndef nsIDOMElement_h__ +#define nsIDOMElement_h__ + +#include "nsDOM.h" +#include "nsIDOMNode.h" + +// forward declaration +class nsIDOMAttribute; +class nsIDOMAttributeList; +class nsIDOMNodeIterator; + +#define NS_IDOMELEMENT_IID \ +{ /* 8f6bca79-ce42-11d1-b724-00600891d8c9 */ \ +0x8f6bca79, 0xce42, 0x11d1, \ + {0xb7, 0x24, 0x00, 0x60, 0x08, 0x91, 0xd8, 0xc9} } + +class nsIDOMElement : public nsIDOMNode { +public: + virtual nsresult GetTagName(nsString &aName) = 0; + virtual nsresult GetAttributes(nsIDOMAttributeList **aAttributeList) = 0; + virtual nsresult GetDOMAttribute(nsString &aName, nsString &aValue) = 0; + virtual nsresult SetDOMAttribute(nsString &aName, nsString &aValue) = 0; + virtual nsresult RemoveAttribute(nsString &aName) = 0; + virtual nsresult GetAttributeNode(nsString &aName, nsIDOMAttribute **aAttribute) = 0; + virtual nsresult SetAttributeNode(nsIDOMAttribute *aAttribute) = 0; + virtual nsresult RemoveAttributeNode(nsIDOMAttribute *aAttribute) = 0; + virtual nsresult GetElementsByTagName(nsString &aName,nsIDOMNodeIterator **aIterator) = 0; + virtual nsresult Normalize() = 0; +}; + +#endif // nsIDOMElement_h__ + diff --git a/mozilla/dom/public/coreDom/nsIDOMIterators.h b/mozilla/dom/public/coreDom/nsIDOMIterators.h new file mode 100644 index 00000000000..5132a5360ba --- /dev/null +++ b/mozilla/dom/public/coreDom/nsIDOMIterators.h @@ -0,0 +1,64 @@ +/* -*- 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. + */ + +#ifndef nsIDOMIterators_h__ +#define nsIDOMIterators_h__ + +#include "nsDOM.h" +#include "nsISupports.h" + +// forward declaration +class nsIDOMNode; + +#define NS_IDOMNODEITERATOR_IID \ +{ /* 8f6bca75-ce42-11d1-b724-00600891d8c9 */ \ +0x8f6bca75, 0xce42, 0x11d1, \ + {0xb7, 0x24, 0x00, 0x60, 0x08, 0x91, 0xd8, 0xc9} } + +class nsIDOMNodeIterator : public nsISupports { +public: + virtual nsresult SetFilter(PRInt32 aFilter, PRBool aFilterOn) = 0; + virtual nsresult GetLength(PRUint32 *aLength) = 0; + virtual nsresult GetCurrentNode(nsIDOMNode **aNode) = 0; + virtual nsresult GetNextNode(nsIDOMNode **aNode) = 0; + virtual nsresult GetPreviousNode(nsIDOMNode **aNode) = 0; + virtual nsresult ToFirst(nsIDOMNode **aNode) = 0; + virtual nsresult ToLast(nsIDOMNode **aNode) = 0; + virtual nsresult MoveTo(int aNth, nsIDOMNode **aNode) = 0; +}; + +#define NS_IDOMTREEITERATOR_IID \ +{ /* 8f6bca76-ce42-11d1-b724-00600891d8c9 */ \ +0x8f6bca76, 0xce42, 0x11d1, \ + {0xb7, 0x24, 0x00, 0x60, 0x08, 0x91, 0xd8, 0xc9} } + +class nsIDOMTreeIterator : public nsIDOMNodeIterator { +public: + virtual nsresult NumChildren(PRUint32 *aLength) = 0; + virtual nsresult NumPreviousSiblings(PRUint32 *aLength) = 0; + virtual nsresult NumNextSiblings(PRUint32 *aLength) = 0; + virtual nsresult ToParent(nsIDOMNode **aNode) = 0; + virtual nsresult ToPreviousSibling(nsIDOMNode **aNode) = 0; + virtual nsresult ToNextSibling(nsIDOMNode **aNode) = 0; + virtual nsresult ToFirstChild(nsIDOMNode **aNode) = 0; + virtual nsresult ToLastChild(nsIDOMNode **aNode) = 0; + virtual nsresult ToNthChild(nsIDOMNode **aNode) = 0; +}; + +#endif // nsIDOMIterators_h__ + diff --git a/mozilla/dom/public/coreDom/nsIDOMNode.h b/mozilla/dom/public/coreDom/nsIDOMNode.h new file mode 100644 index 00000000000..41690734225 --- /dev/null +++ b/mozilla/dom/public/coreDom/nsIDOMNode.h @@ -0,0 +1,58 @@ +/* -*- 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. + */ + +#ifndef nsIDOMNode_h__ +#define nsIDOMNode_h__ + +#include "nsDOM.h" +#include "nsISupports.h" + +// forward declaration +class nsIDOMNodeIterator; + +#define NS_IDOMNODE_IID \ +{ /* 8f6bca74-ce42-11d1-b724-00600891d8c9 */ \ +0x8f6bca74, 0xce42, 0x11d1, \ +{0xb7, 0x24, 0x00, 0x60, 0x08, 0x91, 0xd8, 0xc9} } + +class nsIDOMNode : public nsISupports { +public: + // NodeType + enum NodeType { + DOCUMENT = 1, + ELEMENT = 2, + ATTRIBUTE = 3, + PI = 4, + COMMENT = 5, + TEXT = 6 + }; + + virtual nsresult GetNodeType(PRInt32 *aType) = 0; + virtual nsresult GetParentNode(nsIDOMNode **aNode) = 0; + virtual nsresult GetChildNodes(nsIDOMNodeIterator **aIterator) = 0; + virtual nsresult HasChildNodes() = 0; + virtual nsresult GetFirstChild(nsIDOMNode **aNode) = 0; + virtual nsresult GetPreviousSibling(nsIDOMNode **aNode) = 0; + virtual nsresult GetNextSibling(nsIDOMNode **aNode) = 0; + virtual nsresult InsertBefore(nsIDOMNode *newChild, nsIDOMNode *refChild) = 0; + virtual nsresult ReplaceChild(nsIDOMNode *newChild, nsIDOMNode *oldChild) = 0; + virtual nsresult RemoveChild(nsIDOMNode *oldChild) = 0; +}; + +#endif // nsIDOMNode_h__ + diff --git a/mozilla/dom/public/coreDom/nsIDOMPI.h b/mozilla/dom/public/coreDom/nsIDOMPI.h new file mode 100644 index 00000000000..8cb21423ed8 --- /dev/null +++ b/mozilla/dom/public/coreDom/nsIDOMPI.h @@ -0,0 +1,37 @@ +/* -*- 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. + */ + +#ifndef nsIDOMPI_h__ +#define nsIDOMPI_h__ + +#include "nsDOM.h" +#include "nsIDOMNode.h" + + +class nsIDOMPI : public nsIDOMNode { +public: + //attribute UniString name; + virtual UniString GetName() = 0; + virtual void SetName(UniString name) = 0; + //attribute UniString data; + virtual UniString GetData() = 0; + virtual void SetData(UniString data) = 0; +}; + +#endif // nsIDOMPI_h__ + diff --git a/mozilla/dom/public/coreDom/nsIDOMText.h b/mozilla/dom/public/coreDom/nsIDOMText.h new file mode 100644 index 00000000000..5030ab2760f --- /dev/null +++ b/mozilla/dom/public/coreDom/nsIDOMText.h @@ -0,0 +1,46 @@ +/* -*- 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. + */ + +#ifndef nsIDOMText_h__ +#define nsIDOMText_h__ + +#include "nsDOM.h" +#include "nsIDOMNode.h" + +// forward declaration +class nsIDOMElement; + +#define NS_IDOMTEXT_IID \ +{ /* 8f6bca7b-ce42-11d1-b724-00600891d8c9 */ \ +0x8f6bca7b, 0xce42, 0x11d1, \ + {0xb7, 0x24, 0x00, 0x60, 0x08, 0x91, 0xd8, 0xc9} } + +class nsIDOMText : public nsIDOMNode { +public: + //attribute UniString data; + virtual nsresult GetData(nsString &aString) = 0; + virtual nsresult SetData(nsString &aString) = 0; + virtual nsresult Append(nsString &aData) = 0; + virtual nsresult Insert(int offset, nsString &aData) = 0; + virtual nsresult Delete(int offset, int count) = 0; + virtual nsresult Replace(int offset, int count, nsString &aData) = 0; + virtual nsresult Splice(nsIDOMElement *element, int offset, int count) = 0; +}; + +#endif // nsIDOMText_h__ + diff --git a/mozilla/dom/public/makefile.win b/mozilla/dom/public/makefile.win new file mode 100644 index 00000000000..524f9e2914e --- /dev/null +++ b/mozilla/dom/public/makefile.win @@ -0,0 +1,28 @@ +#!nmake +# +# 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. + +DEPTH=..\.. +IGNORE_MANIFEST=1 + +DIRS=coreDom +DEFINES=-D_IMPL_NS_DOM +EXPORTS=nsIScriptContext.h nsIScriptObject.h nsIScriptObjectOwner.h + +MODULE=dom + +include <$(DEPTH)\config\rules.mak> + diff --git a/mozilla/dom/public/nsIScriptContext.h b/mozilla/dom/public/nsIScriptContext.h new file mode 100644 index 00000000000..6a5e00d16b0 --- /dev/null +++ b/mozilla/dom/public/nsIScriptContext.h @@ -0,0 +1,53 @@ +/* -*- 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. + */ + +#ifndef nsIScriptContext_h__ +#define nsIScriptContext_h__ + +#include "nscore.h" +#include "nsISupports.h" +#include "jsapi.h" + +// +// This dependency will disappear soon. A more general "global object" +// interface will be defined. nsIWebWidget is too specific +// +class nsIWebWidget; + +#define NS_ISCRIPTCONTEXT_IID \ +{ /* 8f6bca7d-ce42-11d1-b724-00600891d8c9 */ \ +0x8f6bca7d, 0xce42, 0x11d1, \ + {0xb7, 0x24, 0x00, 0x60, 0x08, 0x91, 0xd8, 0xc9} } + +class nsIScriptContext : public nsISupports { +public: + virtual PRBool EvaluateString(const char *aScript, + PRUint32 aScriptSize, + jsval *aRetValue) = 0; + virtual JSObject* GetGlobalObject() = 0; + virtual JSContext* GetContext() = 0; + virtual nsresult InitAllClasses() = 0; + // This dependency (nsIWebWidget) will disappear soon. A more general "global object" + // interface will be defined. nsIWebWidget is too specific + virtual nsresult InitContext(nsIWebWidget *aGlobalObject) = 0; +}; + +extern "C" NS_DOM NS_CreateContext(nsIWebWidget *aGlobal, nsIScriptContext **aContext); + +#endif // nsIScriptContext_h__ + diff --git a/mozilla/dom/public/nsIScriptObject.h b/mozilla/dom/public/nsIScriptObject.h new file mode 100644 index 00000000000..f7724bc76a0 --- /dev/null +++ b/mozilla/dom/public/nsIScriptObject.h @@ -0,0 +1,45 @@ +/* -*- 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. + */ + +#ifndef nsIScriptObject_h__ +#define nsIScriptObject_h__ + +#include "nsISupports.h" +#include "jsapi.h" + +#define NS_ISCRIPTOBJECT_IID \ +{ /* 8f6bca7c-ce42-11d1-b724-00600891d8c9 */ \ +0x8f6bca7c, 0xce42, 0x11d1, \ + {0xb7, 0x24, 0x00, 0x60, 0x08, 0x91, 0xd8, 0xc9} } + +// +// The interface a js object can implement +// +class nsIScriptObject : public nsISupports { +public: + virtual PRBool AddProperty(JSContext *aContext, jsval aID, jsval *aVp) = 0; + virtual PRBool DeleteProperty(JSContext *aContext, jsval aID, jsval *aVp) = 0; + virtual PRBool GetProperty(JSContext *aContext, jsval aID, jsval *aVp) = 0; + virtual PRBool SetProperty(JSContext *aContext, jsval aID, jsval *aVp) = 0; + virtual PRBool EnumerateProperty(JSContext *aContext) = 0; + virtual PRBool Resolve(JSContext *aContext, jsval aID) = 0; + virtual PRBool Convert(JSContext *aContext, jsval aID) = 0; + virtual void Finalize(JSContext *aContext) = 0; +}; + +#endif // nsIScriptObject_h__ diff --git a/mozilla/dom/public/nsIScriptObjectOwner.h b/mozilla/dom/public/nsIScriptObjectOwner.h new file mode 100644 index 00000000000..dd4b7d48b0d --- /dev/null +++ b/mozilla/dom/public/nsIScriptObjectOwner.h @@ -0,0 +1,74 @@ +/* -*- 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. + */ + +#ifndef nsIScriptObjectOwner_h__ +#define nsIScriptObjectOwner_h__ + +#include "nscore.h" +#include "nsISupports.h" + +typedef struct JSContext JSContext; +typedef struct JSObject JSObject; + +class nsIScriptContext; + +#define NS_ISCRIPTOBJECTOWNER_IID \ +{ /* 8f6bca7e-ce42-11d1-b724-00600891d8c9 */ \ +0x8f6bca7e, 0xce42, 0x11d1, \ + {0xb7, 0x24, 0x00, 0x60, 0x08, 0x91, 0xd8, 0xc9} } \ + +// +// The interface a content object has to implement +// +class nsIScriptObjectOwner : public nsISupports { +public: + virtual nsresult GetScriptObject(JSContext *aContext, void** aScriptObject) = 0; + virtual nsresult ResetScriptObject() = 0; +}; + +class nsIDOMDocument; +extern "C" NS_DOM nsresult NS_NewScriptDocument(JSContext *aContext, + nsIDOMDocument *aDocument, + JSObject *aParent, + JSObject **aJSObject); +class nsIDOMElement; +extern "C" NS_DOM nsresult NS_NewScriptElement(JSContext *aContext, + nsIDOMElement *aElement, + JSObject *aParent, + JSObject **aJSObject); +class nsIDOMText; +extern "C" NS_DOM nsresult NS_NewScriptText(JSContext *aContext, + nsIDOMText *aText, + JSObject *aParent, + JSObject **aJSObject); +class nsIDOMNodeIterator; +extern "C" NS_DOM nsresult NS_NewScriptNodeIterator(JSContext *aContext, + nsIDOMNodeIterator *aNodeIterator, + JSObject *aParent, + JSObject **aJSObject); +class nsIDOMAttribute; +extern "C" NS_DOM nsresult NS_NewScriptAttribute(JSContext *aContext, + nsIDOMAttribute *aAttribute, + JSObject *aParent, + JSObject **aJSObject); +class nsIDOMAttributeList; +extern "C" NS_DOM nsresult NS_NewScriptAttributeList(JSContext *aContext, + nsIDOMAttributeList *aAttributeList, + JSObject *aParent, + JSObject **aJSObject); +#endif // nsIScriptObjectOwner_h__ diff --git a/mozilla/dom/src/Makefile b/mozilla/dom/src/Makefile new file mode 100644 index 00000000000..a7f09013cc9 --- /dev/null +++ b/mozilla/dom/src/Makefile @@ -0,0 +1,44 @@ +#!gmake +# +# 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. + +DEPTH=../.. + +LIBRARY_NAME = jsdom + +DEFINES = -D_IMPL_NS_DOM + +CPPSRCS = \ + nsJSEnvironment.cpp \ + nsJSNode.cpp \ + nsJSDocument.cpp \ + nsJSElement.cpp \ + nsJSText.cpp \ + nsJSNodeIterator.cpp\ + nsJSAttribute.cpp \ + nsJSAttributeList.cpp\ + nsJSWindow.cpp\ + $(NULL) + +MODULE = raptor + +REQUIRES = xpcom raptor dom js + +include $(DEPTH)/config/config.mk + +TARGETS = $(LIBRARY) + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/dom/src/makefile.win b/mozilla/dom/src/makefile.win new file mode 100644 index 00000000000..1aac83f1da5 --- /dev/null +++ b/mozilla/dom/src/makefile.win @@ -0,0 +1,67 @@ +#!nmake +# +# 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. + +DEPTH=..\.. +IGNORE_MANIFEST=1 + +MAKE_OBJ_TYPE = DLL +DLLNAME = jsdom +DLL=.\$(OBJDIR)\$(DLLNAME).dll + +DEFINES=-D_IMPL_NS_DOM +CPPSRCS = \ + nsJSEnvironment.cpp \ + nsJSNode.cpp \ + nsJSDocument.cpp \ + nsJSElement.cpp \ + nsJSText.cpp \ + nsJSNodeIterator.cpp\ + nsJSAttribute.cpp \ + nsJSAttributeList.cpp\ + nsJSWindow.cpp\ + $(NULL) + +MODULE=raptor + +REQUIRES=xpcom raptor js + +CPP_OBJS= .\$(OBJDIR)\nsJSEnvironment.obj .\$(OBJDIR)\nsJSNode.obj .\$(OBJDIR)\nsJSDocument.obj \ + .\$(OBJDIR)\nsJSElement.obj .\$(OBJDIR)\nsJSText.obj \ + .\$(OBJDIR)\nsJSNodeIterator.obj .\$(OBJDIR)\nsJSAttribute.obj \ + .\$(OBJDIR)\nsJSAttributeList.obj .\$(OBJDIR)\nsJSWindow.obj + +LINCS=-I$(XPDIST)\public\xpcom -I$(XPDIST)\public\raptor -I$(XPDIST)\public\dom -I$(XPDIST)\public\js + +LCFLAGS = \ + $(LCFLAGS) \ + $(DEFINES) \ + $(NULL) + +LLIBS= \ + $(DIST)\lib\xpcom32.lib \ + $(DIST)\lib\raptorbase.lib \ + $(DIST)\lib\js3240.lib \ + $(LIBNSPR) + +include <$(DEPTH)\config\rules.mak> + +install:: $(DLL) + $(MAKE_INSTALL) $(DLL) $(DIST)\bin + $(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).lib $(DIST)\lib + +clobber:: + rm -f $(DIST)\lib\$(LIBRARY_NAME).lib diff --git a/mozilla/dom/src/nsJSAttribute.cpp b/mozilla/dom/src/nsJSAttribute.cpp new file mode 100644 index 00000000000..913d1596370 --- /dev/null +++ b/mozilla/dom/src/nsJSAttribute.cpp @@ -0,0 +1,290 @@ +/* -*- 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 "jsapi.h" +#include "nscore.h" +#include "nsIScriptObject.h" +#include "nsIScriptObjectOwner.h" +#include "nsIDOMAttribute.h" +#include "nsString.h" + +static NS_DEFINE_IID(kIScriptObjectIID, NS_ISCRIPTOBJECT_IID); +static NS_DEFINE_IID(kIScriptObjectOwnerIID, NS_ISCRIPTOBJECTOWNER_IID); + +// +// Attribute property ids +// +enum attribute_slot { + ATTRIBUTE_VALUE = -1, + ATTRIBUTE_SPECIFIED = -2, +}; + +/***********************************************************************/ + +// +// Attribute properties getter +// +PR_STATIC_CALLBACK(JSBool) +GetAttributeProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + nsIDOMAttribute *attribute = (nsIDOMAttribute*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != attribute, "null pointer"); + + if (JSVAL_IS_INT(id)) { + switch(JSVAL_TO_INT(id)) { + case ATTRIBUTE_VALUE: + { + nsAutoString string; + if (NS_OK == attribute->GetValue(string)) { + JSString *jsstring = JS_NewUCStringCopyN(cx, string.GetUnicode(), string.Length()); + *vp = STRING_TO_JSVAL(jsstring); + } + + break; + } + case ATTRIBUTE_SPECIFIED: + { + if (NS_OK == attribute->GetSpecified()) { + *vp = JSVAL_TRUE; + } + else { + *vp = JSVAL_FALSE; + } + + break; + } + default: + nsIScriptObject *object; + if (NS_OK == attribute->QueryInterface(kIScriptObjectIID, (void**)&object)) { + return object->GetProperty(cx, id, vp); + } + } + } + + return JS_TRUE; +} + +// +// Attribute properties setter +// +PR_STATIC_CALLBACK(JSBool) +SetAttributeProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + nsIDOMAttribute *attribute = (nsIDOMAttribute*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != attribute, "null pointer"); + + if (JSVAL_IS_INT(id)) { + switch(JSVAL_TO_INT(id)) { + case ATTRIBUTE_VALUE: + { + if (JSVAL_IS_STRING(*vp)) { + JSString *jsstring = JSVAL_TO_STRING(*vp); + nsAutoString string = JS_GetStringChars(jsstring); + attribute->SetValue(string); + } + break; + } + case ATTRIBUTE_SPECIFIED: + { + if (JSVAL_IS_BOOLEAN(*vp)) { + attribute->SetSpecified(JSVAL_TO_BOOLEAN(*vp)); + } + break; + } + default: + nsIScriptObject *object; + if (NS_OK == attribute->QueryInterface(kIScriptObjectIID, (void**)&object)) { + return object->GetProperty(cx, id, vp); + } + } + } + + return JS_TRUE; +} + +// +// Attribute finalizer +// +PR_STATIC_CALLBACK(void) +FinalizeAttribute(JSContext *cx, JSObject *obj) +{ + nsIDOMAttribute *attribute = (nsIDOMAttribute*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != attribute, "null pointer"); + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == attribute->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + owner->ResetScriptObject(); + NS_RELEASE(owner); + } + + attribute->Release(); +} + +/***********************************************************************/ +// +// JS->Native functions +// +PR_STATIC_CALLBACK(JSBool) +GetName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMAttribute *attribute = (nsIDOMAttribute*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != attribute, "null pointer"); + nsAutoString string; + if (NS_OK == attribute->GetName(string)) { + JSString *jsstring = JS_NewUCStringCopyN(cx, string.GetUnicode(), string.Length()); + *rval = STRING_TO_JSVAL(jsstring); + } + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +ToString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMAttribute *attribute = (nsIDOMAttribute*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != attribute, "null pointer"); + nsAutoString string; + if (NS_OK == attribute->ToString(string)) { + JSString *jsstring = JS_NewUCStringCopyN(cx, string.GetUnicode(), string.Length()); + *rval = STRING_TO_JSVAL(jsstring); + } + return JS_TRUE; +} + +/***********************************************************************/ +// +// the jscript class for a DOM Attribute +// +JSClass attribute = { + "Attribute", + JSCLASS_HAS_PRIVATE, + JS_PropertyStub, + JS_PropertyStub, + GetAttributeProperty, + SetAttributeProperty, + JS_EnumerateStub, + JS_ResolveStub, + JS_ConvertStub, + FinalizeAttribute +}; + +// +// Attribute class properties +// +static JSPropertySpec attributeProperties[] = +{ + {"value", ATTRIBUTE_VALUE, JSPROP_ENUMERATE}, + {"specified", ATTRIBUTE_SPECIFIED, JSPROP_ENUMERATE}, + {0} +}; + +// +// Attribute class methods +// +static JSFunctionSpec attributeMethods[] = { + {"GetName", GetName, 0}, + {"ToString", ToString, 0}, + {0} +}; + +// +// Attribute constructor +// +PR_STATIC_CALLBACK(JSBool) +Attribute(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + return JS_TRUE; +} + +// +// Attribute static property ids +// + +// +// Attribute static properties +// + +// +// Attribute static methods +// + +/***********************************************************************/ + +// +// Init this object class +// +nsresult NS_InitAttributeClass(JSContext *aContext, JSObject **aPrototype) +{ + // look in the global object for this class prototype + jsval vp; + static JSObject *proto = nsnull; + + if (nsnull == proto) { + proto = JS_InitClass(aContext, // context + JS_GetGlobalObject(aContext), // global object + NULL, // parent proto + &attribute, // JSClass + Attribute, // JSNative ctor + 0, // ctor args + attributeProperties, // proto props + attributeMethods, // proto funcs + NULL, // ctor props (static) + NULL); // ctor funcs (static) + if (nsnull == proto) { + return NS_ERROR_FAILURE; + } + } + + if (nsnull != aPrototype) { + *aPrototype = proto; + } + + return NS_OK; +} + +// +// Attribute instance property ids +// + +// +// Attribute instance properties +// + +// +// New a attribute object in js, connect the native and js worlds +// +extern "C" NS_DOM nsresult NS_NewScriptAttribute(JSContext *aContext, nsIDOMAttribute *aAttribute, JSObject *aParent, JSObject **aJSObject) +{ + NS_PRECONDITION(nsnull != aContext && nsnull != aAttribute && nsnull != aJSObject, "null arg"); + JSObject *proto; + NS_InitAttributeClass(aContext, &proto); + + // create a js object for this class + *aJSObject = JS_NewObject(aContext, &attribute, proto, aParent); + if (nsnull != *aJSObject) { + // define the instance specific properties + + // connect the native object to the js object + JS_SetPrivate(aContext, *aJSObject, aAttribute); + aAttribute->AddRef(); + } + else return NS_ERROR_FAILURE; + + return NS_OK; +} + diff --git a/mozilla/dom/src/nsJSAttributeList.cpp b/mozilla/dom/src/nsJSAttributeList.cpp new file mode 100644 index 00000000000..7d13b94e095 --- /dev/null +++ b/mozilla/dom/src/nsJSAttributeList.cpp @@ -0,0 +1,370 @@ +/* -*- 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 "jsapi.h" +#include "nscore.h" +#include "nsIScriptObject.h" +#include "nsIScriptObjectOwner.h" +#include "nsIDOMAttribute.h" +#include "nsString.h" + +static NS_DEFINE_IID(kIScriptObjectIID, NS_ISCRIPTOBJECT_IID); +static NS_DEFINE_IID(kIScriptObjectOwnerIID, NS_ISCRIPTOBJECTOWNER_IID); +static NS_DEFINE_IID(kIDOMAttributeIID, NS_IDOMATTRIBUTE_IID); + +/***********************************************************************/ + +// +// AttributeList properties getter +// +PR_STATIC_CALLBACK(JSBool) +GetAttributeListProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + nsIDOMAttributeList *attributeList = (nsIDOMAttributeList*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != attributeList, "null pointer"); + + if (JSVAL_IS_INT(id)) { + switch(JSVAL_TO_INT(id)) { + default: + nsIScriptObject *object; + if (NS_OK == attributeList->QueryInterface(kIScriptObjectIID, (void**)&object)) { + return object->GetProperty(cx, id, vp); + } + } + } + + return JS_TRUE; +} + +// +// AttributeList properties setter +// +PR_STATIC_CALLBACK(JSBool) +SetAttributeListProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + nsIDOMAttributeList *attributeList = (nsIDOMAttributeList*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != attributeList, "null pointer"); + + if (JSVAL_IS_INT(id)) { + switch(JSVAL_TO_INT(id)) { + default: + nsIScriptObject *object; + if (NS_OK == attributeList->QueryInterface(kIScriptObjectIID, (void**)&object)) { + return object->SetProperty(cx, id, vp); + } + } + } + + return JS_TRUE; +} + +// +// Document finalizer +// +PR_STATIC_CALLBACK(void) +FinalizeAttributeList(JSContext *cx, JSObject *obj) +{ + nsIDOMAttributeList *attributeList = (nsIDOMAttributeList*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != attributeList, "null pointer"); + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == attributeList->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + owner->ResetScriptObject(); + NS_RELEASE(owner); + } + + attributeList->Release(); +} + +/***********************************************************************/ +// +// JS->Native functions +// +PR_STATIC_CALLBACK(JSBool) +GetAttribute(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMAttributeList *attributeList = (nsIDOMAttributeList*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != attributeList, "null pointer"); + NS_ASSERTION(1 == argc, "wrong number of arguments"); + *rval = JSVAL_NULL; + if (1 == argc) { + // get the arguments + if (JSVAL_IS_STRING(argv[0])) { + JSString *jsstring1 = JSVAL_TO_STRING(argv[0]); + nsAutoString string1 = JS_GetStringChars(jsstring1); + + // call the function + nsIDOMAttribute *attribute; + if (NS_OK == attributeList->GetAttribute(string1, &attribute)) { + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == attribute->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + JSObject *object = nsnull; + if (NS_OK == owner->GetScriptObject(cx, (void**)&object)) { + // set the return value + *rval = OBJECT_TO_JSVAL(object); + } + NS_RELEASE(owner); + } + NS_RELEASE(attribute); + } + } + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +SetAttribute(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMAttributeList *attributeList = (nsIDOMAttributeList*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != attributeList, "null pointer"); + NS_ASSERTION(1 == argc, "wrong number of arguments"); + *rval = JSVAL_NULL; + if (1 == argc) { + // get the arguments + if (JSVAL_IS_OBJECT(argv[0])) { + JSObject *obj1 = JSVAL_TO_OBJECT(argv[0]); + //XXX should check if that's a good class (do not just GetPrivate) + nsISupports *support1 = (nsISupports*)JS_GetPrivate(cx, obj1); + NS_ASSERTION(nsnull != support1, "null pointer"); + + nsIDOMAttribute *attribute1 = nsnull; + if (NS_OK == support1->QueryInterface(kIDOMAttributeIID, (void**)&attribute1)) { + if (NS_OK == attributeList->SetAttribute(attribute1)) { + // set the return value + *rval = argv[0]; + } + NS_RELEASE(attribute1); + } + } + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +Remove(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMAttributeList *attributeList = (nsIDOMAttributeList*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != attributeList, "null pointer"); + NS_ASSERTION(1 == argc, "wrong number of arguments"); + *rval = JSVAL_NULL; + if (1 == argc) { + // get the arguments + if (JSVAL_IS_STRING(argv[0])) { + JSString *jsstring1 = JSVAL_TO_STRING(argv[0]); + nsAutoString string1 = JS_GetStringChars(jsstring1); + + // call the function + nsIDOMAttribute *attribute1 = nsnull; + if (NS_OK == attributeList->Remove(string1, &attribute1)) { + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == attribute1->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + JSObject *object = nsnull; + if (NS_OK == owner->GetScriptObject(cx, (void**)&object)) { + // set the return value + *rval = OBJECT_TO_JSVAL(object); + } + NS_RELEASE(owner); + } + NS_RELEASE(attribute1); + } + } + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +Item(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMAttributeList *attributeList = (nsIDOMAttributeList*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != attributeList, "null pointer"); + NS_ASSERTION(1 == argc, "wrong number of arguments"); + *rval = JSVAL_NULL; + if (1 == argc) { + // get the arguments + if (JSVAL_IS_INT(argv[0])) { + PRInt32 pos = JSVAL_TO_INT(argv[0]); + + // call the function + nsIDOMAttribute *attribute1 = nsnull; + if (NS_OK == attributeList->Item(pos, &attribute1)) { + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == attribute1->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + JSObject *object = nsnull; + if (NS_OK == owner->GetScriptObject(cx, (void**)&object)) { + // set the return value + *rval = OBJECT_TO_JSVAL(object); + } + NS_RELEASE(owner); + } + NS_RELEASE(attribute1); + } + } + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +GetLength(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMAttributeList *attributeList = (nsIDOMAttributeList*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != attributeList, "null pointer"); + + PRUint32 length; + + // call the function + if (NS_OK == attributeList->GetLength(&length)) { + + // set the return value + *rval = INT_TO_JSVAL((PRInt32)length); + } + return JS_TRUE; +} + +/***********************************************************************/ +// +// the jscript class for a DOM AttributeList +// +JSClass attributeList = { + "AttributeList", + JSCLASS_HAS_PRIVATE, + JS_PropertyStub, + JS_PropertyStub, + GetAttributeListProperty, + SetAttributeListProperty, + JS_EnumerateStub, + JS_ResolveStub, + JS_ConvertStub, + FinalizeAttributeList +}; + +// +// AttributeList property ids +// + +// +// AttributeList class properties +// + +// +// AttributeList class methods +// +static JSFunctionSpec attributeListMethods[] = { + {"GetAttribute", GetAttribute, 1}, + {"SetAttribute", SetAttribute, 1}, + {"Remove", Remove, 1}, + {"Item", Item, 1}, + {"GetLength", GetLength, 0}, + {0} +}; + +// +// AttributeList constructor +// +PR_STATIC_CALLBACK(JSBool) +AttributeList(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + return JS_TRUE; +} + +// +// AttributeList static property ids +// + +// +// AttributeList static properties +// + +// +// AttributeList static methods +// + +/***********************************************************************/ + +// +// Init this object class +// +nsresult NS_InitAttributeListClass(JSContext *aContext, JSObject **aPrototype) +{ + // look in the global object for this class prototype + static JSObject *proto = nsnull; + + if (nsnull == proto) { + proto = JS_InitClass(aContext, // context + JS_GetGlobalObject(aContext), // global object + NULL, // parent proto + &attributeList, // JSClass + AttributeList, // JSNative ctor + 0, // ctor args + NULL, // proto props + attributeListMethods, // proto funcs + NULL, // ctor props (static) + NULL); // ctor funcs (static) + if (nsnull == proto) { + return NS_ERROR_FAILURE; + } + } + + if (nsnull != aPrototype) { + *aPrototype = proto; + } + + return NS_OK; +} + +// +// AttributeList instance property ids +// + +// +// AttributeList instance properties +// + +// +// New a AttributeList object in js, connect the native and js worlds +// +extern "C" NS_DOM nsresult NS_NewScriptAttributeList(JSContext *aContext, nsIDOMAttributeList *aAttributeList, JSObject *aParent, JSObject **aJSObject) +{ + NS_PRECONDITION(nsnull != aContext && nsnull != aAttributeList && nsnull != aJSObject, "null arg"); + JSObject *proto; + NS_InitAttributeListClass(aContext, &proto); + + // create a js object for this class + *aJSObject = JS_NewObject(aContext, &attributeList, proto, aParent); + if (nsnull != *aJSObject) { + // define the instance specific properties + + // connect the native object to the js object + JS_SetPrivate(aContext, *aJSObject, aAttributeList); + aAttributeList->AddRef(); + } + else return NS_ERROR_FAILURE; + + return NS_OK; +} + diff --git a/mozilla/dom/src/nsJSDocument.cpp b/mozilla/dom/src/nsJSDocument.cpp new file mode 100644 index 00000000000..62c36682dad --- /dev/null +++ b/mozilla/dom/src/nsJSDocument.cpp @@ -0,0 +1,352 @@ +/* -*- 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 "jsapi.h" +#include "nscore.h" +#include "nsIScriptObject.h" +#include "nsIScriptObjectOwner.h" +#include "nsIDOMDocument.h" +#include "nsIDOMNode.h" +#include "nsIDOMElement.h" + +static NS_DEFINE_IID(kIScriptObjectIID, NS_ISCRIPTOBJECT_IID); +static NS_DEFINE_IID(kIScriptObjectOwnerIID, NS_ISCRIPTOBJECTOWNER_IID); + +// +// Document property ids +// +enum document_slot { + DOCUMENT_DOCUMENTTYPE = -21, + DOCUMENT_DOCUMENTELEMENT = -22, + DOCUMENT_CONTEXTINFO = -23 +}; + +/***********************************************************************/ + +// +// Document properties getter +// +PR_STATIC_CALLBACK(JSBool) +GetDocumentProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + nsIDOMDocument *document = (nsIDOMDocument*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != document, "null pointer"); + + if (JSVAL_IS_INT(id)) { + switch(JSVAL_TO_INT(id)) { + case DOCUMENT_DOCUMENTTYPE: + { + //XXX TBI + break; + } + case DOCUMENT_DOCUMENTELEMENT: + { + nsIDOMElement *element = nsnull; + // call the function + if (NS_OK == document->GetDocumentElement(&element)) { + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == element->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + JSObject *object = nsnull; + if (NS_OK == owner->GetScriptObject(cx, (void**)&object)) { + // set the return value + *vp = OBJECT_TO_JSVAL(object); + } + NS_RELEASE(owner); + } + NS_RELEASE(element); + } + break; + } + case DOCUMENT_CONTEXTINFO: + { + //XXX TBI + break; + } + default: + { + nsIScriptObject *object; + if (NS_OK == document->QueryInterface(kIScriptObjectIID, (void**)&object)) { + return object->GetProperty(cx, id, vp); + } + } + } + } + + return PR_TRUE; +} + +// +// Document properties setter +// +PR_STATIC_CALLBACK(JSBool) +SetDocumentProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + nsIDOMDocument *document = (nsIDOMDocument*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != document, "null pointer"); + + if (JSVAL_IS_INT(id)) { + switch(JSVAL_TO_INT(id)) { + case DOCUMENT_DOCUMENTTYPE: + { + //XXX TBI + break; + } + case DOCUMENT_DOCUMENTELEMENT: + { + //XXX TBI + break; + } + case DOCUMENT_CONTEXTINFO: + { + //XXX TBI + break; + } + default: + { + nsIScriptObject *object; + if (NS_OK == document->QueryInterface(kIScriptObjectIID, (void**)&object)) { + return object->SetProperty(cx, id, vp); + } + } + } + } + + return PR_TRUE; +} + +// +// Document finalizer +// +PR_STATIC_CALLBACK(void) +FinalizeDocument(JSContext *cx, JSObject *obj) +{ + nsIDOMDocument *document = (nsIDOMDocument*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != document, "null pointer"); + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == document->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + owner->ResetScriptObject(); + NS_RELEASE(owner); + } + + document->Release(); +} + +/***********************************************************************/ +// +// JS->Native functions +// +PR_STATIC_CALLBACK(JSBool) +CreateDocumentContext(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + //XXX TBI + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +CreateElement(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + //XXX TBI + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +CreateTextNode(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + //XXX TBI + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +CreateComment(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + //XXX TBI + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +CreatePI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + //XXX TBI + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +CreateAttribute(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + //XXX TBI + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +CreateAttributeList(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + //XXX TBI + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +CreateTreeIterator(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + //XXX TBI + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +GetElementsByTagName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + //XXX TBI + return JS_TRUE; +} + +/***********************************************************************/ +// +// the jscript class for a DOM Document +// +JSClass document = { + "Document", + JSCLASS_HAS_PRIVATE, + JS_PropertyStub, + JS_PropertyStub, + GetDocumentProperty, + SetDocumentProperty, + JS_EnumerateStub, + JS_ResolveStub, + JS_ConvertStub, + FinalizeDocument +}; + +// +// Document class properties +// +static JSPropertySpec documentProperties[] = +{ + {"documentType", DOCUMENT_DOCUMENTTYPE, JSPROP_ENUMERATE}, + {"documentElement", DOCUMENT_DOCUMENTELEMENT, JSPROP_ENUMERATE}, + {"contextInfo", DOCUMENT_CONTEXTINFO, JSPROP_ENUMERATE}, + {0} +}; + +// +// Document class methods +// +static JSFunctionSpec documentMethods[] = { + {"CreateDocumentContext", CreateDocumentContext, 0}, + {"CreateElement", CreateElement, 2}, + {"CreateTextNode", CreateTextNode, 1}, + {"CreateComment", CreateComment, 1}, + {"CreatePI", CreatePI, 2}, + {"CreateAttribute", CreateAttribute, 2}, + {"CreateAttributeList", CreateAttributeList, 0}, + {"CreateTreeIterator", CreateTreeIterator, 1}, + {"GetElementsByTagName", GetElementsByTagName, 0}, + {0} +}; + +// +// Document constructor +// +PR_STATIC_CALLBACK(JSBool) +Document(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + return JS_TRUE; +} + +// +// Document static property ids +// + +// +// Document static properties +// + +// +// Document static methods +// + +/***********************************************************************/ + +// +// Init this object class +// +nsresult NS_InitNodeClass(JSContext *aContext, JSObject **aPrototype); +nsresult NS_InitDocumentClass(JSContext *aContext, JSObject **aPrototype) +{ + // look in the global object for this class prototype + jsval vp; + static JSObject *proto = nsnull; + + if (nsnull == proto) { + JSObject *parentProto = nsnull; + NS_InitNodeClass(aContext, &parentProto); + proto = JS_InitClass(aContext, // context + JS_GetGlobalObject(aContext), // global object + parentProto, // parent proto + &document, // JSClass + Document, // JSNative ctor + 0, // ctor args + documentProperties, // proto props + documentMethods, // proto funcs + NULL, // ctor props (static) + NULL); // ctor funcs (static) + if (nsnull == proto) { + return NS_ERROR_FAILURE; + } + } + + if (nsnull != aPrototype) { + *aPrototype = proto; + } + + return NS_OK; +} + +// +// Document instance property ids +// + +// +// Document instance properties +// + +// +// New a document object in js, connect the native and js worlds +// +extern "C" NS_DOM nsresult NS_NewScriptDocument(JSContext *aContext, nsIDOMDocument *aDocument, JSObject *aParent, JSObject **aJSObject) +{ + NS_PRECONDITION(nsnull != aContext && nsnull != aDocument && nsnull != aJSObject, "null arg"); + JSObject *proto; + NS_InitDocumentClass(aContext, &proto); + + // create a js object for this class + *aJSObject = JS_NewObject(aContext, &document, proto, aParent); + if (nsnull != *aJSObject) { + // define the instance specific properties + + // connect the native object to the js object + JS_SetPrivate(aContext, *aJSObject, aDocument); + aDocument->AddRef(); + } + else return NS_ERROR_FAILURE; + + return NS_OK; +} + diff --git a/mozilla/dom/src/nsJSElement.cpp b/mozilla/dom/src/nsJSElement.cpp new file mode 100644 index 00000000000..8ac3f89575f --- /dev/null +++ b/mozilla/dom/src/nsJSElement.cpp @@ -0,0 +1,477 @@ +/* -*- 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 "jsapi.h" +#include "nscore.h" +#include "nsIScriptObject.h" +#include "nsIScriptObjectOwner.h" +#include "nsIDOMElement.h" +#include "nsIDOMAttribute.h" +#include "nsIDOMIterators.h" +#include "nsString.h" + +static NS_DEFINE_IID(kIScriptObjectIID, NS_ISCRIPTOBJECT_IID); +static NS_DEFINE_IID(kIScriptObjectOwnerIID, NS_ISCRIPTOBJECTOWNER_IID); +static NS_DEFINE_IID(kIDOMAttributeIID, NS_IDOMATTRIBUTE_IID); + +/***********************************************************************/ + +// +// Element properties getter +// +PR_STATIC_CALLBACK(JSBool) +GetElementProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + nsIDOMElement *element = (nsIDOMElement*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != element, "null pointer"); + + if (JSVAL_IS_INT(id)) { + switch(JSVAL_TO_INT(id)) { + default: + nsIScriptObject *object; + if (NS_OK == element->QueryInterface(kIScriptObjectIID, (void**)&object)) { + return object->GetProperty(cx, id, vp); + } + } + } + + return JS_TRUE; +} + +// +// Element properties setter +// +PR_STATIC_CALLBACK(JSBool) +SetElementProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + nsIDOMElement *element = (nsIDOMElement*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != element, "null pointer"); + + if (JSVAL_IS_INT(id)) { + switch(JSVAL_TO_INT(id)) { + default: + nsIScriptObject *object = nsnull; + if (NS_OK == element->QueryInterface(kIScriptObjectIID, (void**)&object)) { + return object->SetProperty(cx, id, vp); + } + } + } + + return JS_TRUE; +} + +// +// Element finalizer +// +PR_STATIC_CALLBACK(void) +FinalizeElement(JSContext *cx, JSObject *obj) +{ + nsIDOMElement *element = (nsIDOMElement*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != element, "null pointer"); + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == element->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + owner->ResetScriptObject(); + NS_RELEASE(owner); + } + + element->Release(); +} + +/***********************************************************************/ +// +// JS->Native functions +// +PR_STATIC_CALLBACK(JSBool) +GetTagName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMElement *element = (nsIDOMElement*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != element, "null pointer"); + *rval = JSVAL_NULL; + + // call the function + nsAutoString string; + if (NS_OK == element->GetTagName(string)) { + JSString *jsstring = JS_NewUCStringCopyN(cx, string, string.Length()); + // set the return value + *rval = STRING_TO_JSVAL(jsstring); + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +GetAttributes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMElement *element = (nsIDOMElement*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != element, "null pointer"); + *rval = JSVAL_NULL; + + // call the function + nsIDOMAttributeList *attributeList = nsnull; + if (NS_OK == element->GetAttributes(&attributeList)) { + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == attributeList->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + JSObject *object = nsnull; + if (NS_OK == owner->GetScriptObject(cx, (void**)&object)) { + // set the return value + *rval = OBJECT_TO_JSVAL(object); + } + NS_RELEASE(owner); + } + NS_RELEASE(attributeList); + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +GetAttribute(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMElement *element = (nsIDOMElement*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != element, "null pointer"); + NS_ASSERTION(1 == argc, "wrong number of arguments"); + *rval = JSVAL_NULL; + if (1 == argc) { + // get the arguments + if (JSVAL_IS_STRING(argv[0])) { + JSString *jsstring1 = JSVAL_TO_STRING(argv[0]); + nsAutoString string1 = JS_GetStringChars(jsstring1); + + // call the function + nsAutoString string; + if (NS_OK == element->GetDOMAttribute(string1, string)) { + JSString *jsstring = JS_NewUCStringCopyN(cx, string, string.Length()); + // set the return value + *rval = STRING_TO_JSVAL(jsstring); + } + } + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +SetAttribute(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMElement *element = (nsIDOMElement*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != element, "null pointer"); + NS_ASSERTION(2 == argc, "wrong number of arguments"); + if (2 == argc) { + // get the arguments + if (JSVAL_IS_STRING(argv[0]) && + JSVAL_IS_STRING(argv[1])) { + JSString *jsstring1 = JSVAL_TO_STRING(argv[0]); + nsAutoString string1 = JS_GetStringChars(jsstring1); + JSString *jsstring2 = JSVAL_TO_STRING(argv[1]); + nsAutoString string2 = JS_GetStringChars(jsstring2); + + // call the function + element->SetDOMAttribute(string1, string2); + } + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +RemoveAttribute(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMElement *element = (nsIDOMElement*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != element, "null pointer"); + NS_ASSERTION(1 == argc, "wrong number of arguments"); + if (1 == argc) { + // get the arguments + if (JSVAL_IS_STRING(argv[0])) { + JSString *jsstring1 = JSVAL_TO_STRING(argv[0]); + nsAutoString string1 = JS_GetStringChars(jsstring1); + + // call the function + element->RemoveAttribute(string1); + } + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +GetAttributeNode(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMElement *element = (nsIDOMElement*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != element, "null pointer"); + NS_ASSERTION(1 == argc, "wrong number of arguments"); + *rval = JSVAL_NULL; + if (1 == argc) { + // get the arguments + if (JSVAL_IS_STRING(argv[0])) { + JSString *jsstring1 = JSVAL_TO_STRING(argv[0]); + nsAutoString string1 = JS_GetStringChars(jsstring1); + + // call the function + nsIDOMAttribute *attribute = nsnull; + if (NS_OK == element->GetAttributeNode(string1, &attribute)) { + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == attribute->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + JSObject *object = nsnull; + if (NS_OK == owner->GetScriptObject(cx, (void**)&object)) { + // set the return value + *rval = OBJECT_TO_JSVAL(object); + } + NS_RELEASE(owner); + } + NS_RELEASE(attribute); + } + } + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +SetAttributeNode(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMElement *element = (nsIDOMElement*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != element, "null pointer"); + NS_ASSERTION(1 == argc, "wrong number of arguments"); + if (1 == argc) { + // get the arguments + if (JSVAL_IS_OBJECT(argv[0])) { + JSObject *obj1 = JSVAL_TO_OBJECT(argv[0]); + //XXX should check if that's a good class (do not just GetPrivate) + nsISupports *support1 = (nsISupports*)JS_GetPrivate(cx, obj1); + NS_ASSERTION(nsnull != support1, "null pointer"); + + nsIDOMAttribute *attribute1 = nsnull; + if (NS_OK == support1->QueryInterface(kIDOMAttributeIID, (void**)&attribute1)) { + element->SetAttributeNode(attribute1); + NS_RELEASE(attribute1); + } + } + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +RemoveAttributeNode(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMElement *element = (nsIDOMElement*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != element, "null pointer"); + NS_ASSERTION(1 == argc, "wrong number of arguments"); + if (1 == argc) { + // get the arguments + if (JSVAL_IS_OBJECT(argv[0])) { + JSObject *obj1 = JSVAL_TO_OBJECT(argv[0]); + //XXX should check if that's a good class (do not just GetPrivate) + nsISupports *support1 = (nsISupports*)JS_GetPrivate(cx, obj1); + NS_ASSERTION(nsnull != support1, "null pointer"); + + nsIDOMAttribute *attribute1 = nsnull; + if (NS_OK == support1->QueryInterface(kIDOMAttributeIID, (void**)&attribute1)) { + element->RemoveAttributeNode(attribute1); + NS_RELEASE(attribute1); + } + } + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +GetElementsByTagName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMElement *element = (nsIDOMElement*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != element, "null pointer"); + NS_ASSERTION(1 == argc, "wrong number of arguments"); + *rval = JSVAL_NULL; + if (1 == argc) { + // get the arguments + if (JSVAL_IS_STRING(argv[0])) { + JSString *jsstring1 = JSVAL_TO_STRING(argv[0]); + nsAutoString string1 = JS_GetStringChars(jsstring1); + + // call the function + nsIDOMNodeIterator *nodeIterator = nsnull; + if (NS_OK == element->GetElementsByTagName(string1, &nodeIterator)) { + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == nodeIterator->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + JSObject *object = nsnull; + if (NS_OK == owner->GetScriptObject(cx, (void**)&object)) { + // set the return value + *rval = OBJECT_TO_JSVAL(object); + } + NS_RELEASE(owner); + } + NS_RELEASE(nodeIterator); + } + } + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +Normalize(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMElement *element = (nsIDOMElement*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != element, "null pointer"); + + // call the function + element->Normalize(); + + return JS_TRUE; +} + +/***********************************************************************/ +// +// the jscript class for a DOM Element +// +JSClass element = { + "Element", + JSCLASS_HAS_PRIVATE, + JS_PropertyStub, + JS_PropertyStub, + GetElementProperty, + SetElementProperty, + JS_EnumerateStub, + JS_ResolveStub, + JS_ConvertStub, + FinalizeElement +}; + +// +// Element property ids +// + +// +// Element class properties +// + +// +// Element class methods +// +static JSFunctionSpec elementMethods[] = { + {"GetTagName", GetTagName, 0}, + {"GetAttributes", GetAttributes, 0}, + {"GetAttribute", GetAttribute, 1}, + {"SetAttribute", SetAttribute, 2}, + {"RemoveAttribute", RemoveAttribute, 1}, + {"GetAttributeNode", GetAttributeNode, 1}, + {"SetAttributeNode", SetAttributeNode, 1}, + {"RemoveAttributeNode", RemoveAttributeNode, 1}, + {"GetElementsByTagName", GetElementsByTagName, 1}, + {"Normalize", Normalize, 0}, + {0} +}; + +// +// Element constructor +// +PR_STATIC_CALLBACK(JSBool) +Element(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + return JS_TRUE; +} + +// +// Element static property ids +// + +// +// Element static properties +// + +// +// Element static methods +// + +/***********************************************************************/ + +// +// Init this object class +// +nsresult NS_InitNodeClass(JSContext *aContext, JSObject **aPrototype); +nsresult NS_InitElementClass(JSContext *aContext, JSObject **aPrototype) +{ + // look in the global object for this class prototype + jsval vp; + static JSObject *proto = nsnull; + + if (nsnull == proto) { + JSObject *parentProto; + NS_InitNodeClass(aContext, &parentProto); + proto = JS_InitClass(aContext, // context + JS_GetGlobalObject(aContext), // global object + parentProto, // parent proto + &element, // JSClass + Element, // JSNative ctor + 0, // ctor args + NULL, // proto props + elementMethods, // proto funcs + NULL, // ctor props (static) + NULL); // ctor funcs (static) + if (nsnull == proto) { + return NS_ERROR_FAILURE; + } + } + + if (nsnull != aPrototype) { + *aPrototype = proto; + } + + return NS_OK; +} + +// +// Element instance property ids +// + +// +// Element instance properties +// + +// +// New a element object in js, connect the native and js worlds +// +extern "C" NS_DOM nsresult NS_NewScriptElement(JSContext *aContext, nsIDOMElement *aElement, JSObject *aParent, JSObject **aJSObject) +{ + NS_PRECONDITION(nsnull != aContext && nsnull != aElement && nsnull != aJSObject, "null arg"); + JSObject *proto; + NS_InitElementClass(aContext, &proto); + + // create a js object for this class + *aJSObject = JS_NewObject(aContext, &element, proto, aParent); + if (nsnull != *aJSObject) { + // define the instance specific properties + + // connect the native object to the js object + JS_SetPrivate(aContext, *aJSObject, aElement); + aElement->AddRef(); + } + else return NS_ERROR_FAILURE; + + return NS_OK; +} + diff --git a/mozilla/dom/src/nsJSEnvironment.cpp b/mozilla/dom/src/nsJSEnvironment.cpp new file mode 100644 index 00000000000..397b4baef64 --- /dev/null +++ b/mozilla/dom/src/nsJSEnvironment.cpp @@ -0,0 +1,130 @@ +/* -*- 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 "nsJSEnvironment.h" +#include "nsIScriptObjectOwner.h" + +const uint32 gGCSize = 4L * 1024L * 1024L; +const size_t gStackSize = 8192; + +static NS_DEFINE_IID(kIScriptContextIID, NS_ISCRIPTCONTEXT_IID); + +nsJSContext::nsJSContext(JSRuntime *aRuntime) +{ + mRefCnt = 1; + mContext = JS_NewContext(aRuntime, gStackSize); +} + +nsJSContext::~nsJSContext() +{ + JS_DestroyContext(mContext); +} + +NS_IMPL_ISUPPORTS(nsJSContext, kIScriptContextIID); + +PRBool nsJSContext::EvaluateString(const char *aScript, + PRUint32 aScriptSize, + jsval *aRetValue) +{ + return ::JS_EvaluateScript(mContext, + JS_GetGlobalObject(mContext), + aScript, + aScriptSize, + NULL, + 0, + aRetValue); +} + +JSObject* nsJSContext::GetGlobalObject() +{ + return JS_GetGlobalObject(mContext); +} + +JSContext* nsJSContext::GetContext() +{ + return mContext; +} + +#define GLOBAL_OBJECT_NAME "window_object" +nsresult NS_NewGlobalWindow(JSContext *aContext, nsIWebWidget *aWindow, void **aJSObject); + +nsresult nsJSContext::InitContext(nsIWebWidget *aGlobalObject) +{ + nsresult result = NS_ERROR_FAILURE; + + JSObject *global; + nsresult res = NS_NewGlobalWindow(mContext, aGlobalObject, (void**)&global); + if (NS_OK == res) { + // init standard classes + if (::JS_InitStandardClasses(mContext, global)) { + res = InitAllClasses(); // this will complete the global object initialization + } + } + + return res; +} + +nsresult NS_InitWindowClass(JSContext *aContext, JSObject *aGlobal); +nsresult NS_InitNodeClass(JSContext *aContext, JSObject **aPrototype); +nsresult NS_InitElementClass(JSContext *aContext, JSObject **aPrototype); +nsresult NS_InitDocumentClass(JSContext *aContext, JSObject **aPrototype); +nsresult NS_InitTextClass(JSContext *aContext, JSObject **aPrototype); +nsresult NS_InitAttributeClass(JSContext *aContext, JSObject **aPrototype); +nsresult NS_InitAttributeListClass(JSContext *aContext, JSObject **aPrototype); +nsresult NS_InitNodeIteratorClass(JSContext *aContext, JSObject **aPrototype); + +nsresult nsJSContext::InitAllClasses() +{ + if (NS_OK == NS_InitWindowClass(mContext, GetGlobalObject()) && + NS_OK == NS_InitNodeClass(mContext, nsnull) && + NS_OK == NS_InitElementClass(mContext, nsnull) && + NS_OK == NS_InitDocumentClass(mContext, nsnull) && + NS_OK == NS_InitTextClass(mContext, nsnull) && + NS_OK == NS_InitAttributeClass(mContext, nsnull) && + NS_OK == NS_InitAttributeListClass(mContext, nsnull) && + NS_OK == NS_InitNodeIteratorClass(mContext, nsnull)) + return NS_OK; + + return NS_ERROR_FAILURE; +} + +nsJSEnvironment::nsJSEnvironment() +{ + mRuntime = JS_Init(gGCSize); + mScriptContext = new nsJSContext(mRuntime); +} + +nsJSEnvironment::~nsJSEnvironment() +{ + NS_RELEASE(mScriptContext); + JS_Finish(mRuntime); +} + +nsIScriptContext* nsJSEnvironment::GetContext() +{ + return mScriptContext; +} + +extern "C" NS_DOM NS_CreateContext(nsIWebWidget *aGlobal, nsIScriptContext **aContext) +{ + nsJSEnvironment *environment = new nsJSEnvironment(); + *aContext = environment->GetContext(); + (*aContext)->InitContext(aGlobal); + return NS_OK; +} + diff --git a/mozilla/dom/src/nsJSEnvironment.h b/mozilla/dom/src/nsJSEnvironment.h new file mode 100644 index 00000000000..7753164a66c --- /dev/null +++ b/mozilla/dom/src/nsJSEnvironment.h @@ -0,0 +1,54 @@ +/* -*- 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. + */ +#ifndef nsJSEnvironment_h___ +#define nsJSEnvironment_h___ + +#include "nsIScriptContext.h" + +class nsJSContext : public nsIScriptContext { +private: + JSContext *mContext; + +public: + nsJSContext(JSRuntime *aRuntime); + ~nsJSContext(); + + NS_DECL_ISUPPORTS + + virtual PRBool EvaluateString(const char *aScript, + PRUint32 aScriptSize, + jsval *aRetValue); + virtual JSObject* GetGlobalObject(); + virtual JSContext* GetContext(); + virtual nsresult InitAllClasses(); + virtual nsresult InitContext(nsIWebWidget *aGlobalObject); +}; + +class nsJSEnvironment { +private: + nsIScriptContext *mScriptContext; + JSRuntime *mRuntime; + +public: + nsJSEnvironment(); + ~nsJSEnvironment(); + + nsIScriptContext* GetContext(); +}; + +#endif /* nsJSEnvironment_h___ */ diff --git a/mozilla/dom/src/nsJSNode.cpp b/mozilla/dom/src/nsJSNode.cpp new file mode 100644 index 00000000000..26a1507da0c --- /dev/null +++ b/mozilla/dom/src/nsJSNode.cpp @@ -0,0 +1,519 @@ +/* -*- 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 "nscore.h" +#include "nsIScriptObject.h" +#include "nsIScriptObjectOwner.h" +#include "nsIDOMNode.h" +#include "nsIDOMIterators.h" +#include "jsapi.h" + +static NS_DEFINE_IID(kIScriptObjectOwnerIID, NS_ISCRIPTOBJECTOWNER_IID); +static NS_DEFINE_IID(kIScriptObjectIID, NS_ISCRIPTOBJECT_IID); +static NS_DEFINE_IID(kIDOMNodeIID, NS_IDOMNODE_IID); + +/***********************************************************************/ + +// +// Node properties getter +// +PR_STATIC_CALLBACK(JSBool) +GetNodeProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + nsIDOMNode *node = (nsIDOMNode*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != node, "null pointer"); + + if (JSVAL_IS_INT(id)) { + switch(JSVAL_TO_INT(id)) { + default: + nsIScriptObject *object; + if (NS_OK == node->QueryInterface(kIScriptObjectIID, (void**)&object)) { + return object->GetProperty(cx, id, vp); + } + } + } + + return JS_TRUE; +} + +// +// Node properties setter +// +PR_STATIC_CALLBACK(JSBool) +SetNodeProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + nsIDOMNode *node = (nsIDOMNode*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != node, "null pointer"); + + if (JSVAL_IS_INT(id)) { + switch(JSVAL_TO_INT(id)) { + default: + nsIScriptObject *object; + if (NS_OK == node->QueryInterface(kIScriptObjectIID, (void**)&object)) { + return object->SetProperty(cx, id, vp); + } + } + } + + return JS_TRUE; +} + +// +// Node finalizer +// +PR_STATIC_CALLBACK(void) +FinalizeNode(JSContext *cx, JSObject *obj) +{ + nsIDOMNode *node = (nsIDOMNode*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != node, "null pointer"); + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == node->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + owner->ResetScriptObject(); + NS_RELEASE(owner); + } + + node->Release(); +} + +/***********************************************************************/ +// +// JS->Native functions +// +PR_STATIC_CALLBACK(JSBool) +GetNodeType(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMNode *node = (nsIDOMNode*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != node, "null pointer"); + + PRInt32 type = 0; + // call the function + if (NS_OK == node->GetNodeType(&type)) { + *rval = INT_TO_JSVAL(type); + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +GetParentNode(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMNode *node = (nsIDOMNode*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != node, "null pointer"); + *rval = JSVAL_NULL; + + nsIDOMNode *parent = nsnull; + // call the function + if (NS_OK == node->GetParentNode(&parent)) { + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == parent->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + JSObject *object = nsnull; + if (NS_OK == owner->GetScriptObject(cx, (void**)&object)) { + *rval = OBJECT_TO_JSVAL(object); + } + NS_RELEASE(owner); + } + NS_RELEASE(parent); + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +GetChildNodes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMNode *node = (nsIDOMNode*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != node, "null pointer"); + *rval = JSVAL_NULL; + + nsIDOMNodeIterator *nodeIterator = nsnull; + // call the function + if (NS_OK == node->GetChildNodes(&nodeIterator)) { + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == nodeIterator->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + JSObject *object = nsnull; + if (NS_OK == owner->GetScriptObject(cx, (void**)&object)) { + *rval = OBJECT_TO_JSVAL(object); + } + NS_RELEASE(owner); + } + NS_RELEASE(nodeIterator); + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +HasChildNodes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMNode *node = (nsIDOMNode*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != node, "null pointer"); + + // call the function + if (NS_OK == node->HasChildNodes()) { + *rval = JSVAL_TRUE; + } + else { + *rval = JSVAL_FALSE; + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +GetFirstChild(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMNode *node = (nsIDOMNode*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != node, "null pointer"); + *rval = JSVAL_NULL; + + nsIDOMNode *child = nsnull; + // call the function + if (NS_OK == node->GetFirstChild(&child)) { + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == child->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + JSObject *object = nsnull; + if (NS_OK == owner->GetScriptObject(cx, (void**)&object)) { + *rval = OBJECT_TO_JSVAL(object); + } + NS_RELEASE(owner); + } + NS_RELEASE(child); + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +GetPreviousSibling(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMNode *node = (nsIDOMNode*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != node, "null pointer"); + *rval = JSVAL_NULL; + + nsIDOMNode *previous = nsnull; + // call the function + if (NS_OK == node->GetPreviousSibling(&previous)) { + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == previous->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + JSObject *object = nsnull; + if (NS_OK == owner->GetScriptObject(cx, (void**)&object)) { + *rval = OBJECT_TO_JSVAL(object); + } + NS_RELEASE(owner); + } + NS_RELEASE(previous); + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +GetNextSibling(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMNode *node = (nsIDOMNode*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != node, "null pointer"); + *rval = JSVAL_NULL; + + nsIDOMNode *next = nsnull; + // call the function + if (NS_OK == node->GetNextSibling(&next)) { + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == next->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + JSObject *object = nsnull; + if (NS_OK == owner->GetScriptObject(cx, (void**)&object)) { + *rval = OBJECT_TO_JSVAL(object); + } + NS_RELEASE(owner); + } + NS_RELEASE(next); + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +InsertBefore(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMNode *node = (nsIDOMNode*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != node, "null pointer"); + NS_ASSERTION(2 == argc, "wrong number of arguments"); + *rval = JSVAL_NULL; + if (2 == argc) { + // get the arguments + if (JSVAL_IS_OBJECT(argv[0]) && JSVAL_IS_OBJECT(argv[1])) { + JSObject *obj1 = JSVAL_TO_OBJECT(argv[0]); + JSObject *obj2 = JSVAL_TO_OBJECT(argv[1]); + //XXX should check if that's a good class (do not just GetPrivate) + nsISupports *support1 = (nsISupports*)JS_GetPrivate(cx, obj1); + NS_ASSERTION(nsnull != support1, "null pointer"); + nsISupports *support2 = (nsISupports*)JS_GetPrivate(cx, obj2); + NS_ASSERTION(nsnull != support2, "null pointer"); + + nsIDOMNode *node1 = nsnull; + nsIDOMNode *node2 = nsnull; + if (NS_OK == support1->QueryInterface(kIDOMNodeIID, (void**)&node1)) { + if (NS_OK == support2->QueryInterface(kIDOMNodeIID, (void**)&node2)) { + + // call the function + if (NS_OK == node->InsertBefore(node1, node2)) { + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == node1->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + JSObject *object = nsnull; + if (NS_OK == owner->GetScriptObject(cx, (void**)&object)) { + *rval = OBJECT_TO_JSVAL(object); + } + NS_RELEASE(owner); + } + } + NS_RELEASE(node2); + } + NS_RELEASE(node1); + } + } + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +ReplaceChild(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMNode *node = (nsIDOMNode*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != node, "null pointer"); + NS_ASSERTION(2 == argc, "wrong number of arguments"); + *rval = JSVAL_NULL; + if (2 == argc) { + // get the arguments + if (JSVAL_IS_OBJECT(argv[0]) && JSVAL_IS_OBJECT(argv[1])) { + JSObject *obj1 = JSVAL_TO_OBJECT(argv[0]); + JSObject *obj2 = JSVAL_TO_OBJECT(argv[1]); + //XXX should check if that's a good class (do not just GetPrivate) + nsISupports *support1 = (nsISupports*)JS_GetPrivate(cx, obj1); + NS_ASSERTION(nsnull != support1, "null pointer"); + nsISupports *support2 = (nsISupports*)JS_GetPrivate(cx, obj2); + NS_ASSERTION(nsnull != support2, "null pointer"); + + nsIDOMNode *node1 = nsnull; + nsIDOMNode *node2 = nsnull; + if (NS_OK == support1->QueryInterface(kIDOMNodeIID, (void**)&node1)) { + if (NS_OK == support2->QueryInterface(kIDOMNodeIID, (void**)&node2)) { + + // call the function + if (NS_OK == node->ReplaceChild(node1, node2)) { + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == node2->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + JSObject *object = nsnull; + if (NS_OK == owner->GetScriptObject(cx, (void**)&object)) { + *rval = OBJECT_TO_JSVAL(object); + } + NS_RELEASE(owner); + } + } + NS_RELEASE(node2); + } + NS_RELEASE(node1); + } + } + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +RemoveChild(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMNode *node = (nsIDOMNode*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != node, "null pointer"); + NS_ASSERTION(1 == argc, "wrong number of arguments"); + *rval = JSVAL_NULL; + if (1 == argc) { + // get the arguments + if (JSVAL_IS_OBJECT(argv[0])) { + JSObject *obj1 = JSVAL_TO_OBJECT(argv[0]); + //XXX should check if that's a good class (do not just GetPrivate) + nsISupports *support1 = (nsISupports*)JS_GetPrivate(cx, obj1); + NS_ASSERTION(nsnull != support1, "null pointer"); + + nsIDOMNode *node1 = nsnull; + if (NS_OK == support1->QueryInterface(kIDOMNodeIID, (void**)&node1)) { + + // call the function + if (NS_OK == node->RemoveChild(node1)) { + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == node1->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + JSObject *object = nsnull; + if (NS_OK == owner->GetScriptObject(cx, (void**)&object)) { + *rval = OBJECT_TO_JSVAL(object); + } + NS_RELEASE(owner); + } + } + NS_RELEASE(node1); + } + } + } + + return JS_TRUE; +} + +/***********************************************************************/ +// +// the jscript class for a DOM Node +// +JSClass node = { + "Node", + JSCLASS_HAS_PRIVATE, + JS_PropertyStub, + JS_PropertyStub, + GetNodeProperty, + SetNodeProperty, + JS_EnumerateStub, + JS_ResolveStub, + JS_ConvertStub, + FinalizeNode +}; + +// +// Node property ids +// + +// +// Node class properties +// + +// +// Node class methods +// +static JSFunctionSpec nodeMethods[] = { + {"GetNodeType", GetNodeType, 0}, + {"GetParentNode", GetParentNode, 0}, + {"GetChildNodes", GetChildNodes, 0}, + {"HasChildNodes", HasChildNodes, 0}, + {"GetFirstChild", GetFirstChild, 0}, + {"GetPreviousSibling", GetPreviousSibling, 0}, + {"GetNextSibling", GetNextSibling, 0}, + {"InsertBefore", InsertBefore, 2}, + {"ReplaceChild", ReplaceChild, 2}, + {"RemoveChild", RemoveChild, 1}, + {0} +}; + +// +// Node constructor +// +PR_STATIC_CALLBACK(JSBool) +Node(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + return JS_TRUE; +} + +// +// Node static property ids +// + +// +// Node static properties +// + +// +// Node static methods +// + +/***********************************************************************/ + +// +// Init this object class +// +nsresult NS_InitNodeClass(JSContext *aContext, JSObject **aPrototype) +{ + // look in the global object for this class prototype + jsval vp; + static JSObject *proto = nsnull; + + if (nsnull == proto) { + proto = JS_InitClass(aContext, // context + JS_GetGlobalObject(aContext), // global object + NULL, // parent proto + &node, // JSClass + Node, // JSNative ctor + 0, // ctor args + NULL, // proto props + nodeMethods, // proto funcs + NULL, // ctor props (static) + NULL); // ctor funcs (static) + if (nsnull == proto) { + return NS_ERROR_FAILURE; + } + } + + if (nsnull != aPrototype) { + *aPrototype = proto; + } + + return NS_OK; +} + +// +// Node instance property ids +// + +// +// Node instance properties +// + +// +// New a node object in js, connect the native and js worlds +// +nsresult NS_NewScriptNode(JSContext *aContext, nsIDOMNode *aNode, JSObject *aParent, JSObject **aJSObject) +{ + NS_PRECONDITION(nsnull != aContext && nsnull != aNode && nsnull != aJSObject, "null arg"); + JSObject *proto; + NS_InitNodeClass(aContext, &proto); + + // create a js object for this class + *aJSObject = JS_NewObject(aContext, &node, proto, aParent); + if (nsnull != *aJSObject) { + // define the instance specific properties + + // connect the native object to the js object + JS_SetPrivate(aContext, *aJSObject, aNode); + aNode->AddRef(); + } + else return NS_ERROR_FAILURE; + + return NS_OK; +} + diff --git a/mozilla/dom/src/nsJSNodeIterator.cpp b/mozilla/dom/src/nsJSNodeIterator.cpp new file mode 100644 index 00000000000..4c57db843d4 --- /dev/null +++ b/mozilla/dom/src/nsJSNodeIterator.cpp @@ -0,0 +1,414 @@ +/* -*- 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 "jsapi.h" +#include "nscore.h" +#include "nsIScriptObject.h" +#include "nsIScriptObjectOwner.h" +#include "nsIDOMIterators.h" +#include "nsIDOMNode.h" + +static NS_DEFINE_IID(kIScriptObjectIID, NS_ISCRIPTOBJECT_IID); +static NS_DEFINE_IID(kIScriptObjectOwnerIID, NS_ISCRIPTOBJECTOWNER_IID); +static NS_DEFINE_IID(kIDOMNodeIID, NS_IDOMNODE_IID); + +/***********************************************************************/ + +// +// NodeIterator properties getter +// +PR_STATIC_CALLBACK(JSBool) +GetNodeIteratorProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + nsIDOMNodeIterator *nodeIterator = (nsIDOMNodeIterator*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != nodeIterator, "null pointer"); + + if (JSVAL_IS_INT(id)) { + switch(JSVAL_TO_INT(id)) { + default: + nsIScriptObject *object; + if (NS_OK == nodeIterator->QueryInterface(kIScriptObjectIID, (void**)&object)) { + return object->GetProperty(cx, id, vp); + } + } + } + + return JS_TRUE; +} + +// +// NodeIterator properties setter +// +PR_STATIC_CALLBACK(JSBool) +SetNodeIteratorProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + nsIDOMNodeIterator *nodeIterator = (nsIDOMNodeIterator*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != nodeIterator, "null pointer"); + + if (JSVAL_IS_INT(id)) { + switch(JSVAL_TO_INT(id)) { + default: + nsIScriptObject *object; + if (NS_OK == nodeIterator->QueryInterface(kIScriptObjectIID, (void**)&object)) { + return object->SetProperty(cx, id, vp); + } + } + } + + return JS_TRUE; +} + +// +// NodeIterator finalizer +// +PR_STATIC_CALLBACK(void) +FinalizeNodeIterator(JSContext *cx, JSObject *obj) +{ + nsIDOMNodeIterator *nodeIterator = (nsIDOMNodeIterator*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != nodeIterator, "null pointer"); + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == nodeIterator->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + owner->ResetScriptObject(); + NS_RELEASE(owner); + } + + nodeIterator->Release(); +} + +/***********************************************************************/ +// +// JS->Native functions +// +PR_STATIC_CALLBACK(JSBool) +SetFilter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +GetLength(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMNodeIterator *nodeIterator = (nsIDOMNodeIterator*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != nodeIterator, "null pointer"); + + PRUint32 length = 0; + // call the function + if (NS_OK == nodeIterator->GetLength(&length)) { + // set the return value + *rval = INT_TO_JSVAL(length); + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +GetCurrentNode(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMNodeIterator *nodeIterator = (nsIDOMNodeIterator*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != nodeIterator, "null pointer"); + *rval = JSVAL_NULL; + + nsIDOMNode *aNode1 = nsnull; + // call the function + if (NS_OK == nodeIterator->GetCurrentNode(&aNode1)) { + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == aNode1->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + JSObject *object = nsnull; + if (NS_OK == owner->GetScriptObject(cx, (void**)&object)) { + // set the return value + *rval = OBJECT_TO_JSVAL(object); + } + NS_RELEASE(owner); + } + NS_RELEASE(aNode1); + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +GetNextNode(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMNodeIterator *nodeIterator = (nsIDOMNodeIterator*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != nodeIterator, "null pointer"); + *rval = JSVAL_NULL; + + nsIDOMNode *aNode1 = nsnull; + // call the function + if (NS_OK == nodeIterator->GetNextNode(&aNode1)) { + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == aNode1->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + JSObject *object = nsnull; + if (NS_OK == owner->GetScriptObject(cx, (void**)&object)) { + // set the return value + *rval = OBJECT_TO_JSVAL(object); + } + NS_RELEASE(owner); + } + NS_RELEASE(aNode1); + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +GetPreviousNode(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMNodeIterator *nodeIterator = (nsIDOMNodeIterator*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != nodeIterator, "null pointer"); + *rval = JSVAL_NULL; + + nsIDOMNode *aNode1 = nsnull; + // call the function + if (NS_OK == nodeIterator->GetPreviousNode(&aNode1)) { + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == aNode1->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + JSObject *object = nsnull; + if (NS_OK == owner->GetScriptObject(cx, (void**)&object)) { + // set the return value + *rval = OBJECT_TO_JSVAL(object); + } + NS_RELEASE(owner); + } + NS_RELEASE(aNode1); + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +ToFirst(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMNodeIterator *nodeIterator = (nsIDOMNodeIterator*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != nodeIterator, "null pointer"); + *rval = JSVAL_NULL; + + nsIDOMNode *aNode1 = nsnull; + // call the function + if (NS_OK == nodeIterator->ToFirst(&aNode1)) { + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == aNode1->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + JSObject *object = nsnull; + if (NS_OK == owner->GetScriptObject(cx, (void**)&object)) { + // set the return value + *rval = OBJECT_TO_JSVAL(object); + } + NS_RELEASE(owner); + } + NS_RELEASE(aNode1); + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +ToLast(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMNodeIterator *nodeIterator = (nsIDOMNodeIterator*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != nodeIterator, "null pointer"); + *rval = JSVAL_NULL; + + nsIDOMNode *aNode1 = nsnull; + // call the function + if (NS_OK == nodeIterator->ToLast(&aNode1)) { + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == aNode1->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + JSObject *object = nsnull; + if (NS_OK == owner->GetScriptObject(cx, (void**)&object)) { + // set the return value + *rval = OBJECT_TO_JSVAL(object); + } + NS_RELEASE(owner); + } + NS_RELEASE(aNode1); + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +MoveTo(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMNodeIterator *nodeIterator = (nsIDOMNodeIterator*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != nodeIterator, "null pointer"); + NS_ASSERTION(1 == argc, "wrong number of arguments"); + *rval = JSVAL_NULL; + if (1 == argc) { + // get the arguments + if (JSVAL_IS_INT(argv[0])) { + + nsIDOMNode *aNode1 = nsnull; + // call the function + if (NS_OK == nodeIterator->MoveTo(JSVAL_TO_INT(argv[0]), &aNode1)) { + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == aNode1->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + JSObject *object = nsnull; + if (NS_OK == owner->GetScriptObject(cx, (void**)&object)) { + // set the return value + *rval = OBJECT_TO_JSVAL(object); + } + NS_RELEASE(owner); + } + NS_RELEASE(aNode1); + } + } + } + + return JS_TRUE; +} + +/***********************************************************************/ +// +// the jscript class for a DOM NodeIterator +// +JSClass nodeIterator = { + "NodeIterator", + JSCLASS_HAS_PRIVATE, + JS_PropertyStub, + JS_PropertyStub, + GetNodeIteratorProperty, + SetNodeIteratorProperty, + JS_EnumerateStub, + JS_ResolveStub, + JS_ConvertStub, + FinalizeNodeIterator +}; + +// +// NodeIterator property ids +// + +// +// NodeIterator class properties +// + +// +// NodeIterator class methods +// +static JSFunctionSpec nodeIteratorMethods[] = { + {"SetFilter", SetFilter, 2}, + {"GetLength", GetLength, 0}, + {"GetCurrentNode", GetCurrentNode, 0}, + {"GetNextNode", GetNextNode, 0}, + {"GetPreviousNode", GetPreviousNode, 0}, + {"ToFirst", ToFirst, 0}, + {"ToLast", ToLast, 0}, + {"MoveTo", MoveTo, 1}, + {0} +}; + +// +// NodeIterator constructor +// +PR_STATIC_CALLBACK(JSBool) +NodeIterator(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + return JS_TRUE; +} + +// +// NodeIterator static property ids +// + +// +// NodeIterator static properties +// + +// +// NodeIterator static methods +// + +/***********************************************************************/ + +// +// Init this object class +// +nsresult NS_InitNodeIteratorClass(JSContext *aContext, JSObject **aPrototype) +{ + // look in the global object for this class prototype + jsval vp; + static JSObject *proto = nsnull; + + if (nsnull == proto) { + proto = JS_InitClass(aContext, // context + JS_GetGlobalObject(aContext), // global object + NULL, // parent proto + &nodeIterator, // JSClass + NodeIterator, // JSNative ctor + 0, // ctor args + NULL, // proto props + nodeIteratorMethods, // proto funcs + NULL, // ctor props (static) + NULL); // ctor funcs (static) + if (nsnull == proto) { + return NS_ERROR_FAILURE; + } + } + + if (nsnull != aPrototype) { + *aPrototype = proto; + } + + return NS_OK; +} + +// +// NodeIterator instance property ids +// + +// +// NodeIterator instance properties +// + +// +// New a nodeIterator object in js, connect the native and js worlds +// +extern "C" NS_DOM nsresult NS_NewScriptNodeIterator(JSContext *aContext, nsIDOMNodeIterator *aNodeIterator, JSObject *aParent, JSObject **aJSObject) +{ + NS_PRECONDITION(nsnull != aContext && nsnull != aNodeIterator && nsnull != aJSObject, "null arg"); + JSObject *proto; + NS_InitNodeIteratorClass(aContext, &proto); + + // create a js object for this class + *aJSObject = JS_NewObject(aContext, &nodeIterator, proto, aParent); + if (nsnull != *aJSObject) { + // define the instance specific properties + + // connect the native object to the js object + JS_SetPrivate(aContext, *aJSObject, aNodeIterator); + aNodeIterator->AddRef(); + } + else return NS_ERROR_FAILURE; + + return NS_OK; +} + diff --git a/mozilla/dom/src/nsJSText.cpp b/mozilla/dom/src/nsJSText.cpp new file mode 100644 index 00000000000..e2f6f0ed025 --- /dev/null +++ b/mozilla/dom/src/nsJSText.cpp @@ -0,0 +1,315 @@ +/* -*- 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 "jsapi.h" +#include "nscore.h" +#include "nsIScriptObject.h" +#include "nsIScriptObjectOwner.h" +#include "nsIDOMText.h" +#include "nsString.h" + +static NS_DEFINE_IID(kIScriptObjectIID, NS_ISCRIPTOBJECT_IID); +static NS_DEFINE_IID(kIScriptObjectOwnerIID, NS_ISCRIPTOBJECTOWNER_IID); + +// +// Text property ids +// +enum text_slot { + TEXT_DATA = -1 +}; + +/***********************************************************************/ + +// +// Text properties getter +// +PR_STATIC_CALLBACK(JSBool) +GetTextProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + nsIDOMText *text = (nsIDOMText*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != text, "null pointer"); + + if (JSVAL_IS_INT(id)) { + switch(JSVAL_TO_INT(id)) { + case TEXT_DATA: + { + nsAutoString string; + if (NS_OK == text->GetData(string)) { + JSString *jsstring = JS_NewUCStringCopyN(cx, string, string.Length()); + // set the return value + *vp = STRING_TO_JSVAL(jsstring); + } + } + default: + { + nsIScriptObject *object; + if (NS_OK == text->QueryInterface(kIScriptObjectIID, (void**)&object)) { + return object->GetProperty(cx, id, vp); + } + } + } + } + + return JS_TRUE; +} + +// +// Text properties setter +// +PR_STATIC_CALLBACK(JSBool) +SetTextProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + nsIDOMText *text = (nsIDOMText*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != text, "null pointer"); + + if (JSVAL_IS_INT(id)) { + switch(JSVAL_TO_INT(id)) { + case TEXT_DATA: + { + if (JSVAL_IS_STRING(*vp)) { + JSString *jsstring = JSVAL_TO_STRING(*vp); + nsAutoString string = JS_GetStringChars(jsstring); + text->SetData(string); + } + break; + } + default: + { + nsIScriptObject *object; + if (NS_OK == text->QueryInterface(kIScriptObjectIID, (void**)&object)) { + return object->SetProperty(cx, id, vp); + } + } + } + } + + return JS_TRUE; +} + +// +// Finalize Text +// +PR_STATIC_CALLBACK(void) +FinalizeText(JSContext *cx, JSObject *obj) +{ + nsIDOMText *text = (nsIDOMText*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != text, "null pointer"); + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == text->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + owner->ResetScriptObject(); + NS_RELEASE(owner); + } + + text->Release(); +} + +/***********************************************************************/ +// +// JS->Native functions +// +PR_STATIC_CALLBACK(JSBool) +Append(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMText *text = (nsIDOMText*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != text, "null pointer"); + NS_ASSERTION(1 == argc, "wrong number of arguments"); + if (1 == argc) { + // get the arguments + if (JSVAL_IS_STRING(argv[0])) { + JSString *jsstring1 = JSVAL_TO_STRING(argv[0]); + nsAutoString string1 = JS_GetStringChars(jsstring1); + + // call the function + text->Append(string1); + } + } + + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +Insert(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + nsIDOMText *text = (nsIDOMText*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != text, "null pointer"); + NS_ASSERTION(2 == argc, "wrong number of arguments"); + if (2 == argc) { + // get the arguments + if (JSVAL_IS_INT(argv[0]) && + JSVAL_IS_STRING(argv[1])) { + JSString *jsstring2 = JSVAL_TO_STRING(argv[1]); + nsAutoString string2 = JS_GetStringChars(jsstring2); + + // call the function + text->Insert(JSVAL_TO_INT(argv[0]), string2); + } + } + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +Delete(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + //XXX TBI + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +Replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + //XXX TBI + return JS_TRUE; +} + +PR_STATIC_CALLBACK(JSBool) +Splice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + //XXX TBI + return JS_TRUE; +} + +/***********************************************************************/ +// +// the jscript class for a DOM Text +// +JSClass text = { + "Text", + JSCLASS_HAS_PRIVATE, + JS_PropertyStub, + JS_PropertyStub, + GetTextProperty, + SetTextProperty, + JS_EnumerateStub, + JS_ResolveStub, + JS_ConvertStub, + FinalizeText +}; + +// +// Text class properties +// +static JSPropertySpec textProperties[] = +{ + {"data", TEXT_DATA, JSPROP_ENUMERATE}, + {0} +}; + +// +// Text class methods +// +static JSFunctionSpec textMethods[] = { + {"Append", Append, 1}, + {"Insert", Insert, 2}, + {"Delete", Delete, 2}, + {"Replace", Replace, 3}, + {"Splice", Splice, 3}, + {0} +}; + +// +// Text constructor +// +PR_STATIC_CALLBACK(JSBool) +Text(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + return JS_TRUE; +} + +// +// Text static property ids +// + +// +// Text static properties +// + +// +// Text static methods +// + +/***********************************************************************/ + +// +// Init this object class +// +nsresult NS_InitNodeClass(JSContext *aContext, JSObject **aPrototype); +nsresult NS_InitTextClass(JSContext *aContext, JSObject **aPrototype) +{ + // look in the global object for this class prototype + jsval vp; + static JSObject *proto = nsnull; + + if (nsnull == proto) { + JSObject *parentProto; + NS_InitNodeClass(aContext, &parentProto); + JSObject *proto; + proto = JS_InitClass(aContext, // context + JS_GetGlobalObject(aContext), // global object + parentProto, // parent proto + &text, // JSClass + Text, // JSNative ctor + 0, // ctor args + textProperties, // proto props + textMethods, // proto funcs + NULL, // ctor props (static) + NULL); // ctor funcs (static) + if (nsnull == proto) { + return NS_ERROR_FAILURE; + } + } + + if (nsnull != aPrototype) { + *aPrototype = proto; + } + + return NS_OK; +} + +// +// Text instance property ids +// + +// +// Text instance properties +// + +// +// New a text object in js, connect the native and js worlds +// +extern "C" NS_DOM nsresult NS_NewScriptText(JSContext *aContext, nsIDOMText *aText, JSObject *aParent, JSObject **aJSObject) +{ + NS_PRECONDITION(nsnull != aContext && nsnull != aText && nsnull != aJSObject, "null arg"); + JSObject *proto; + NS_InitTextClass(aContext, &proto); + + // create a js object for this class + *aJSObject = JS_NewObject(aContext, &text, proto, aParent); + if (nsnull != *aJSObject) { + // define the instance specific properties + + // connect the native object to the js object + JS_SetPrivate(aContext, *aJSObject, aText); + aText->AddRef(); + } + else return NS_ERROR_FAILURE; + + return NS_OK; +} + diff --git a/mozilla/dom/src/nsJSWindow.cpp b/mozilla/dom/src/nsJSWindow.cpp new file mode 100644 index 00000000000..e429f4b47f3 --- /dev/null +++ b/mozilla/dom/src/nsJSWindow.cpp @@ -0,0 +1,259 @@ +/* -*- 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 "jsapi.h" +#include "nscore.h" +#include "nsIScriptContext.h" +#include "nsIScriptObject.h" +#include "nsIScriptObjectOwner.h" +#include "nsIWebWidget.h" +#include "nsIDocument.h" +#include "nsString.h" + +static NS_DEFINE_IID(kIScriptObjectIID, NS_ISCRIPTOBJECT_IID); +static NS_DEFINE_IID(kIScriptObjectOwnerIID, NS_ISCRIPTOBJECTOWNER_IID); + +// +// Window property ids +// +enum window_slot { + WINDOW_DOCUMENT = -1, +}; + +/***********************************************************************/ + +// +// Window properties getter +// +PR_STATIC_CALLBACK(JSBool) +GetWindowProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + nsIWebWidget *window = (nsIWebWidget*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != window, "null pointer"); + + if (JSVAL_IS_INT(id)) { + switch(JSVAL_TO_INT(id)) { + case WINDOW_DOCUMENT: + { + nsIDocument *document = window->GetDocument(); + // call the function + if (nsnull != document) { + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == document->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + JSObject *object = nsnull; + if (NS_OK == owner->GetScriptObject(cx, (void**)&object)) { + // set the return value + *vp = OBJECT_TO_JSVAL(object); + } + NS_RELEASE(owner); + } + NS_RELEASE(document); + } + break; + } + default: + { + nsIScriptObject *object; + if (NS_OK == window->QueryInterface(kIScriptObjectIID, (void**)&object)) { + PRBool ret = object->GetProperty(cx, id, vp); + NS_RELEASE(object); + return ret; + } + } + } + } + + return PR_TRUE; +} + +// +// Window properties setter +// +PR_STATIC_CALLBACK(JSBool) +SetWindowProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + nsIWebWidget *window = (nsIWebWidget*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != window, "null pointer"); + + if (JSVAL_IS_INT(id)) { + switch(JSVAL_TO_INT(id)) { + case WINDOW_DOCUMENT: + { + break; + } + default: + { + nsIScriptObject *object; + if (NS_OK == window->QueryInterface(kIScriptObjectIID, (void**)&object)) { + PRBool ret = object->SetProperty(cx, id, vp); + NS_RELEASE(object); + return ret; + } + } + } + } + + return PR_TRUE; +} + +// +// Window finalizer +// +PR_STATIC_CALLBACK(void) +FinalizeWindow(JSContext *cx, JSObject *obj) +{ + nsIWebWidget *window = (nsIWebWidget*)JS_GetPrivate(cx, obj); + NS_ASSERTION(nsnull != window, "null pointer"); + + // get the js object + nsIScriptObjectOwner *owner = nsnull; + if (NS_OK == window->QueryInterface(kIScriptObjectOwnerIID, (void**)&owner)) { + owner->ResetScriptObject(); + NS_RELEASE(owner); + } +} + +/***********************************************************************/ +// +// JS->Native functions +// +PR_STATIC_CALLBACK(JSBool) +Dump(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + NS_ASSERTION(1 == argc, "wrong number of arguments"); + if (1 == argc) { + // get the arguments + if (JSVAL_IS_STRING(argv[0])) { + JSString *jsstring1 = JSVAL_TO_STRING(argv[0]); + char *print = JS_GetStringBytes(jsstring1); + printf("%s", print); + //delete print; + } + } + + return JS_TRUE; +} + +/***********************************************************************/ +// +// the jscript class for a DOM Window +// +JSClass window = { + "Window", + JSCLASS_HAS_PRIVATE, + JS_PropertyStub, + JS_PropertyStub, + GetWindowProperty, + SetWindowProperty, + JS_EnumerateStub, + JS_ResolveStub, + JS_ConvertStub, + FinalizeWindow +}; + +// +// Window class properties +// +static JSPropertySpec windowProperties[] = +{ + {"document", WINDOW_DOCUMENT, JSPROP_ENUMERATE}, + {0} +}; + +// +// Window class methods +// +static JSFunctionSpec windowMethods[] = { + {"Dump", Dump, 1}, + {0} +}; + +// +// Window constructor +// +PR_STATIC_CALLBACK(JSBool) +Window(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + return JS_TRUE; +} + +// +// Window static property ids +// + +// +// Window static properties +// + +// +// Window static methods +// + +/***********************************************************************/ + +// +// Init this object class +// +nsresult NS_InitWindowClass(JSContext *aContext, JSObject *aGlobalObject) +{ + // look in the global object for this class prototype + JS_DefineProperties(aContext, aGlobalObject, windowProperties); + JS_DefineFunctions(aContext, aGlobalObject, windowMethods); + return NS_OK; +} + +// +// Window instance property ids +// + +// +// Window instance properties +// + +// +// New a Window object in js, connect the native and js worlds +// +nsresult NS_NewGlobalWindow(JSContext *aContext, nsIWebWidget *aWindow, void **aJSObject) +{ + NS_PRECONDITION(nsnull != aContext && nsnull != aWindow && nsnull != aJSObject, "null arg"); + + JSObject *global = ::JS_NewObject(aContext, &window, NULL, NULL); + if (global) { + // The global object has a to be defined in two step: + // 1- create a generic object, with no prototype and no parent which + // will be passed to JS_InitStandardClasses. JS_InitStandardClasses + // will make it the global object + // 2- define the global object to be what you really want it to be. + // + // The js runtime is not fully initialized before JS_InitStandardClasses + // is called, so part of the global object initialization has to be moved + // after JS_InitStandardClasses + + // assign "this" to the js object, don't AddRef + ::JS_SetPrivate(aContext, global, aWindow); + + *aJSObject = (void*)global; + + return NS_OK; + } + + return NS_ERROR_FAILURE; +} + diff --git a/mozilla/dom/tests/js/DumpHTML.js b/mozilla/dom/tests/js/DumpHTML.js new file mode 100644 index 00000000000..d765ce6b062 Binary files /dev/null and b/mozilla/dom/tests/js/DumpHTML.js differ diff --git a/mozilla/dom/tests/js/DumpTree.js b/mozilla/dom/tests/js/DumpTree.js new file mode 100644 index 00000000000..4033f9457c1 Binary files /dev/null and b/mozilla/dom/tests/js/DumpTree.js differ diff --git a/mozilla/dom/tests/js/simple.js b/mozilla/dom/tests/js/simple.js new file mode 100644 index 00000000000..f3ac126a819 Binary files /dev/null and b/mozilla/dom/tests/js/simple.js differ diff --git a/mozilla/gfx/Makefile b/mozilla/gfx/Makefile new file mode 100644 index 00000000000..b8eb68125f7 --- /dev/null +++ b/mozilla/gfx/Makefile @@ -0,0 +1,24 @@ +#!gmake +# +# 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. + +DEPTH = .. + +DIRS = src tests + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/gfx/makefile.win b/mozilla/gfx/makefile.win new file mode 100644 index 00000000000..b7909d0e8ea --- /dev/null +++ b/mozilla/gfx/makefile.win @@ -0,0 +1,22 @@ +#!nmake +# +# 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. + +DEPTH=.. + +DIRS= src tests + +include <$(DEPTH)\config\rules.mak> diff --git a/mozilla/gfx/src/Makefile b/mozilla/gfx/src/Makefile new file mode 100644 index 00000000000..9c853a4806a --- /dev/null +++ b/mozilla/gfx/src/Makefile @@ -0,0 +1,41 @@ +#!gmake +# +# 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. + +DEPTH = ../.. + +include $(DEPTH)/config/config.mk + +LIBRARY_NAME = raptorgfx + +MODULE=raptor + +REQUIRES=util img xpcom raptor + +LCFLAGS=-D_IMPL_NS_GFX + +CPPSRCS=nsColor.cpp nsColorNames.cpp nsColorNamesRGB.cpp nsFont.cpp \ + nsImageGroup.cpp nsImageManager.cpp nsImageNetContext.cpp \ + nsImageRenderer.cpp nsImageRequest.cpp nsImageSystemServices.cpp \ + nsImageURL.cpp nsRect.cpp nsTransform2D.cpp nsFontCache.cpp + +EXPORTS=nsColor.h nsColorNames.h nsCoord.h nsFont.h nsRect.h nsPoint.h \ + nsSize.h nsMargin.h nsTransform2D.h nsIRenderingContext.h \ + nsIFontMetrics.h nsIImageManager.h nsIImageGroup.h nsIImageRequest.h \ + nsIImageObserver.h nsIDeviceContext.h nsIFontCache.h nsIImage.h \ + nsGfxCIID.h + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/gfx/src/makefile.win b/mozilla/gfx/src/makefile.win new file mode 100644 index 00000000000..d0f8ba0032d --- /dev/null +++ b/mozilla/gfx/src/makefile.win @@ -0,0 +1,77 @@ +#!nmake +# +# 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. + +DEPTH=..\.. +IGNORE_MANIFEST=1 + +DIRS = windows + +LIBRARY_NAME=gmgfx +MODULE=raptor +REQUIRES=util img xpcom raptor + +DEFINES=-D_IMPL_NS_GFX + +CPPSRCS=nsColor.cpp nsColorNames.cpp nsColorNamesRGB.cpp nsFont.cpp \ + nsImageGroup.cpp nsImageManager.cpp nsImageNetContext.cpp \ + nsImageRenderer.cpp nsImageRequest.cpp nsImageSystemServices.cpp \ + nsImageURL.cpp nsRect.cpp nsTransform2D.cpp nsFontCache.cpp + +EXPORTS=nsColor.h nsColorNames.h nsCoord.h nsFont.h nsRect.h nsPoint.h \ + nsSize.h nsMargin.h nsTransform2D.h nsIRenderingContext.h \ + nsIFontMetrics.h nsIImageManager.h nsIImageGroup.h nsIImageRequest.h \ + nsIImageObserver.h nsIDeviceContext.h nsIFontCache.h nsIImage.h \ + nsGfxCIID.h + +CPP_OBJS=.\$(OBJDIR)\nsColor.obj .\$(OBJDIR)\nsColorNames.obj \ + .\$(OBJDIR)\nsColorNamesRGB.obj .\$(OBJDIR)\nsFont.obj \ + .\$(OBJDIR)\nsImageGroup.obj .\$(OBJDIR)\nsImageManager.obj \ + .\$(OBJDIR)\nsImageNetContext.obj .\$(OBJDIR)\nsImageRenderer.obj \ + .\$(OBJDIR)\nsImageRequest.obj .\$(OBJDIR)\nsImageSystemServices.obj \ + .\$(OBJDIR)\nsImageURL.obj .\$(OBJDIR)\nsRect.obj \ + .\$(OBJDIR)\nsTransform2D.obj .\$(OBJDIR)\nsFontCache.obj + +LINCS=-I$(XPDIST)\public\util -I$(XPDIST)\public\img \ + -I$(XPDIST)\public\xpcom -I$(XPDIST)\public\raptor + +MAKE_OBJ_TYPE = DLL +DLLNAME = raptorgfx +DLL=.\$(OBJDIR)\$(DLLNAME).dll + +LCFLAGS = \ + $(LCFLAGS) \ + $(DEFINES) \ + $(NULL) + +# These are the libraries we need to link with to create the dll +LLIBS= \ + $(DIST)\lib\xpcom32.lib \ + $(DIST)\lib\raptorbase.lib \ + $(DIST)\lib\img3240.lib \ + $(DIST)\lib\util.lib \ + $(DIST)\lib\libplc21.lib \ + $(LIBNSPR) + +include <$(DEPTH)\config\rules.mak> + +libs:: $(DLL) + $(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).dll $(DIST)\bin + $(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).lib $(DIST)\lib + +clobber:: + rm -f $(DIST)\bin\$(DLLNAME).dll + rm -f $(DIST)\lib\$(DLLNAME).lib diff --git a/mozilla/gfx/src/nsColor.cpp b/mozilla/gfx/src/nsColor.cpp new file mode 100644 index 00000000000..eb33f59b17f --- /dev/null +++ b/mozilla/gfx/src/nsColor.cpp @@ -0,0 +1,111 @@ +/* -*- 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 "plstr.h" +#include "nsColor.h" +#include "nsColorNames.h" + +static int ComponentValue(const char* aColorSpec, int dpc) +{ + int component = 0; + while (--dpc >= 0) { + char ch = *aColorSpec++; + if ((ch >= '0') && (ch <= '9')) { + component = component*16 + (ch - '0'); + } else { + // "ch&7" handles lower and uppercase hex alphabetics + component = component*16 + (ch & 7) + 9; + } + } + return component; +} + +// Note: This handles 9 digits of hex to be compatible with eric +// bina's original code. However, it is pickyer with respect to what a +// legal color is and will only return true for perfectly legal color +// values. +NS_GFX PRBool NS_HexToRGB(const char* aColorSpec, nscolor* aResult) +{ + NS_PRECONDITION(nsnull != aColorSpec, "null ptr"); + if (nsnull == aColorSpec) { + return PR_FALSE; + } + + if (aColorSpec[0] == '#') { + aColorSpec++; + } + + int nameLen = PL_strlen(aColorSpec); + if ((nameLen == 3) || (nameLen == 6) || (nameLen == 9)) { + // Make sure the digits are legal + for (int i = 0; i < nameLen; i++) { + char ch = aColorSpec[i]; + if (((ch >= '0') && (ch <= '9')) || + ((ch >= 'a') && (ch <= 'f')) || + ((ch >= 'A') && (ch <= 'F'))) { + // Legal character + continue; + } + // Whoops. Illegal character. + return PR_FALSE; + } + + // Convert the ascii to binary + int dpc = nameLen / 3; + + // Translate components from hex to binary + int r = ComponentValue(aColorSpec, dpc); + int g = ComponentValue(aColorSpec + dpc, dpc); + int b = ComponentValue(aColorSpec + dpc*2, dpc); + if (dpc == 1) { + // Scale single digit component to an 8 bit value. Replicate the + // single digit to compute the new value. + r = (r << 4) | r; + g = (g << 4) | g; + b = (b << 4) | b; + } else if (dpc == 3) { + // Drop off the low digit from 12 bit values. + r = r >> 4; + g = g >> 4; + b = b >> 4; + } + NS_ASSERTION((r >= 0) && (r <= 255), "bad r"); + NS_ASSERTION((g >= 0) && (g <= 255), "bad g"); + NS_ASSERTION((b >= 0) && (b <= 255), "bad b"); + if (nsnull != aResult) { + *aResult = NS_RGB(r, g, b); + } + return PR_TRUE; + } + + // Improperly formatted color value + return PR_FALSE; +} + +PRBool NS_ColorNameToRGB(const char* aColorName, nscolor* aResult) +{ + PRInt32 id = nsColorNames::LookupName(aColorName); + if (id >= 0) { + NS_ASSERTION(id < COLOR_MAX, "LookupName mess up"); + if (nsnull != aResult) { + *aResult = nsColorNames::kColors[id]; + } + return PR_TRUE; + } + return PR_FALSE; +} diff --git a/mozilla/gfx/src/nsColor.h b/mozilla/gfx/src/nsColor.h new file mode 100644 index 00000000000..95bbbbfa34a --- /dev/null +++ b/mozilla/gfx/src/nsColor.h @@ -0,0 +1,52 @@ +/* -*- 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. + */ + +#ifndef nsColor_h___ +#define nsColor_h___ + +#include "nscore.h" + +// A color is a 32 bit unsigned integer with four components: R, G, B +// and A. +typedef PRUint32 nscolor; + +// Make a color out of r,g,b values. This assumes that the r,g,b values are +// properly constrained to 0-255. This also assumes that a is 255. +#define NS_RGB(_r,_g,_b) \ + ((nscolor) ((255 << 24) | ((_b)<<16) | ((_g)<<8) | (_r))) + +// Make a color out of r,g,b,a values. This assumes that the r,g,b,a +// values are properly constrained to 0-255. +#define NS_RGBA(_r,_g,_b,_a) \ + ((nscolor) (((_a) << 24) | ((_b)<<16) | ((_g)<<8) | (_r))) + +// Extract color components from nscolor +#define NS_GET_R(_rgba) ((PRUint8) ((_rgba) & 0xff)) +#define NS_GET_G(_rgba) ((PRUint8) (((_rgba) >> 8) & 0xff)) +#define NS_GET_B(_rgba) ((PRUint8) (((_rgba) >> 16) & 0xff)) +#define NS_GET_A(_rgba) ((PRUint8) (((_rgba) >> 24) & 0xff)) + +// Translate a hex string to a color. Return true if it parses ok, +// otherwise return false. +extern NS_GFX PRBool NS_HexToRGB(const char* aBuf, nscolor* aResult); + +// Translate a color name to a color. Return true if it parses ok, +// otherwise return false. +extern NS_GFX PRBool NS_ColorNameToRGB(const char* aBuf, nscolor* aResult); + +#endif /* nsColor_h___ */ diff --git a/mozilla/gfx/src/nsColorNameIDs.h b/mozilla/gfx/src/nsColorNameIDs.h new file mode 100644 index 00000000000..b8e7a35a2be --- /dev/null +++ b/mozilla/gfx/src/nsColorNameIDs.h @@ -0,0 +1,142 @@ +/* Do not edit - generated by genhash.pl */ +#define COLOR_ALICEBLUE 0 +#define COLOR_ANTIQUEWHITE 1 +#define COLOR_AQUA 2 +#define COLOR_AQUAMARINE 3 +#define COLOR_AZURE 4 +#define COLOR_BEIGE 5 +#define COLOR_BISQUE 6 +#define COLOR_BLACK 7 +#define COLOR_BLANCHEDALMOND 8 +#define COLOR_BLUE 9 +#define COLOR_BLUEVIOLET 10 +#define COLOR_BROWN 11 +#define COLOR_BURLYWOOD 12 +#define COLOR_CADETBLUE 13 +#define COLOR_CHARTREUSE 14 +#define COLOR_CHOCOLATE 15 +#define COLOR_CORAL 16 +#define COLOR_CORNFLOWERBLUE 17 +#define COLOR_CORNSILK 18 +#define COLOR_CRIMSON 19 +#define COLOR_CYAN 20 +#define COLOR_DARKBLUE 21 +#define COLOR_DARKCYAN 22 +#define COLOR_DARKGOLDENROD 23 +#define COLOR_DARKGRAY 24 +#define COLOR_DARKGREEN 25 +#define COLOR_DARKKHAKI 26 +#define COLOR_DARKMAGENTA 27 +#define COLOR_DARKOLIVEGREEN 28 +#define COLOR_DARKORANGE 29 +#define COLOR_DARKORCHID 30 +#define COLOR_DARKRED 31 +#define COLOR_DARKSALMON 32 +#define COLOR_DARKSEAGREEN 33 +#define COLOR_DARKSLATEBLUE 34 +#define COLOR_DARKSLATEGRAY 35 +#define COLOR_DARKTURQUOISE 36 +#define COLOR_DARKVIOLET 37 +#define COLOR_DEEPPINK 38 +#define COLOR_DEEPSKYBLUE 39 +#define COLOR_DIMGRAY 40 +#define COLOR_DODGERBLUE 41 +#define COLOR_FIREBRICK 42 +#define COLOR_FLORALWHITE 43 +#define COLOR_FORESTGREEN 44 +#define COLOR_FUCHSIA 45 +#define COLOR_GAINSBORO 46 +#define COLOR_GHOSTWHITE 47 +#define COLOR_GOLD 48 +#define COLOR_GOLDENROD 49 +#define COLOR_GRAY 50 +#define COLOR_GREEN 51 +#define COLOR_GREENYELLOW 52 +#define COLOR_HONEYDEW 53 +#define COLOR_HOTPINK 54 +#define COLOR_INDIANRED 55 +#define COLOR_INDIGO 56 +#define COLOR_IVORY 57 +#define COLOR_KHAKI 58 +#define COLOR_LAVENDER 59 +#define COLOR_LAVENDERBLUSH 60 +#define COLOR_LAWNGREEN 61 +#define COLOR_LEMONCHIFFON 62 +#define COLOR_LIGHTBLUE 63 +#define COLOR_LIGHTCORAL 64 +#define COLOR_LIGHTCYAN 65 +#define COLOR_LIGHTGOLDENRODYELLOW 66 +#define COLOR_LIGHTGREEN 67 +#define COLOR_LIGHTGREY 68 +#define COLOR_LIGHTPINK 69 +#define COLOR_LIGHTSALMON 70 +#define COLOR_LIGHTSEAGREEN 71 +#define COLOR_LIGHTSKYBLUE 72 +#define COLOR_LIGHTSLATEGRAY 73 +#define COLOR_LIGHTSTEELBLUE 74 +#define COLOR_LIGHTYELLOW 75 +#define COLOR_LIME 76 +#define COLOR_LIMEGREEN 77 +#define COLOR_LINEN 78 +#define COLOR_MAGENTA 79 +#define COLOR_MAROON 80 +#define COLOR_MEDIUMAQUAMARINE 81 +#define COLOR_MEDIUMBLUE 82 +#define COLOR_MEDIUMORCHID 83 +#define COLOR_MEDIUMPURPLE 84 +#define COLOR_MEDIUMSEAGREEN 85 +#define COLOR_MEDIUMSLATEBLUE 86 +#define COLOR_MEDIUMSPRINGGREEN 87 +#define COLOR_MEDIUMTURQUOISE 88 +#define COLOR_MEDIUMVIOLETRED 89 +#define COLOR_MIDNIGHTBLUE 90 +#define COLOR_MINTCREAM 91 +#define COLOR_MISTYROSE 92 +#define COLOR_MOCCASIN 93 +#define COLOR_NAVAJOWHITE 94 +#define COLOR_NAVY 95 +#define COLOR_OLDLACE 96 +#define COLOR_OLIVE 97 +#define COLOR_OLIVEDRAB 98 +#define COLOR_ORANGE 99 +#define COLOR_ORANGERED 100 +#define COLOR_ORCHID 101 +#define COLOR_PALEGOLDENROD 102 +#define COLOR_PALEGREEN 103 +#define COLOR_PALETURQUOISE 104 +#define COLOR_PALEVIOLETRED 105 +#define COLOR_PAPAYAWHIP 106 +#define COLOR_PEACHPUFF 107 +#define COLOR_PERU 108 +#define COLOR_PINK 109 +#define COLOR_PLUM 110 +#define COLOR_POWDERBLUE 111 +#define COLOR_PURPLE 112 +#define COLOR_RED 113 +#define COLOR_ROSYBROWN 114 +#define COLOR_ROYALBLUE 115 +#define COLOR_SADDLEBROWN 116 +#define COLOR_SALMON 117 +#define COLOR_SANDYBROWN 118 +#define COLOR_SEAGREEN 119 +#define COLOR_SEASHELL 120 +#define COLOR_SIENNA 121 +#define COLOR_SILVER 122 +#define COLOR_SKYBLUE 123 +#define COLOR_SLATEBLUE 124 +#define COLOR_SLATEGRAY 125 +#define COLOR_SNOW 126 +#define COLOR_SPRINGGREEN 127 +#define COLOR_STEELBLUE 128 +#define COLOR_TAN 129 +#define COLOR_TEAL 130 +#define COLOR_THISTLE 131 +#define COLOR_TOMATO 132 +#define COLOR_TURQUOISE 133 +#define COLOR_VIOLET 134 +#define COLOR_WHEAT 135 +#define COLOR_WHITE 136 +#define COLOR_WHITESMOKE 137 +#define COLOR_YELLOW 138 +#define COLOR_YELLOWGREEN 139 +#define COLOR_MAX 140 diff --git a/mozilla/gfx/src/nsColorNames.cpp b/mozilla/gfx/src/nsColorNames.cpp new file mode 100644 index 00000000000..c683ff95780 --- /dev/null +++ b/mozilla/gfx/src/nsColorNames.cpp @@ -0,0 +1,566 @@ + +/* +** This is a generated file, do not edit it. This file is created by +** genhash.pl +*/ + +#include "plstr.h" +#include "nsColorNames.h" +#define TOTAL_KEYWORDS 140 +#define MIN_WORD_LENGTH 3 +#define MAX_WORD_LENGTH 20 +#define MIN_HASH_VALUE 5 +#define MAX_HASH_VALUE 573 +/* maximum key range = 569, duplicates = 0 */ + + +struct StaticNameTable { + char* tag; + PRInt32 id; +}; + +static const unsigned char kLowerLookup[256] = { + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, + 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, + 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, + 64, + 97,98,99,100,101,102,103,104,105,106,107,108,109, + 110,111,112,113,114,115,116,117,118,119,120,121,122, + + 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, + + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 +}; + +#define MYLOWER(x) kLowerLookup[((x) & 0x7f)] + +/** + * Map a name to an ID or -1 + */ +PRInt32 nsColorNames::LookupName(const char* str) +{ + static unsigned short asso_values[] = + { + 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, + 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, + 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, + 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, + 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, + 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, + 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, + 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, + 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, + 574, 574, 574, 574, 574, 574, 574, 0, 200, 245, + 30, 0, 105, 90, 0, 10, 0, 80, 0, 0, + 0, 0, 140, 30, 20, 5, 25, 10, 10, 70, + 574, 203, 5, 574, 574, 574, 574, 574, + }; + static unsigned char lengthtable[] = + { + 0, 0, 0, 0, 0, 5, 6, 0, 0, 0, 5, 6, 0, 8, + 4, 5, 0, 0, 0, 0, 0, 6, 0, 8, 0, 0, 0, 0, + 3, 4, 15, 0, 7, 8, 4, 0, 16, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 0, 0, 13, 14, 0, 11, 17, 3, 0, 0, + 6, 7, 8, 0, 10, 6, 0, 0, 9, 15, 0, 12, 0, 0, + 0, 0, 0, 0, 14, 5, 6, 12, 0, 4, 15, 0, 0, 0, + 0, 10, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 6, 0, + 0, 9, 0, 0, 7, 0, 0, 5, 6, 0, 0, 0, 0, 0, + 0, 0, 0, 5, 6, 7, 13, 9, 0, 0, 0, 0, 4, 5, + 0, 0, 0, 9, 0, 11, 0, 0, 0, 0, 0, 7, 0, 9, + 0, 0, 0, 13, 4, 0, 0, 0, 0, 9, 10, 0, 0, 0, + 4, 10, 6, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 9, 0, 0, + 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 11, 0, 0, 9, 0, 0, 0, 0, 4, 5, 0, 4, 0, 9, + 0, 0, 0, 0, 9, 0, 11, 0, 0, 0, 10, 0, 0, 13, + 0, 5, 6, 0, 13, 9, 10, 0, 0, 0, 4, 0, 11, 0, + 0, 9, 0, 0, 9, 0, 9, 20, 0, 0, 8, 9, 5, 0, + 7, 13, 9, 10, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, + 0, 0, 8, 0, 10, 13, 0, 0, 0, 0, 0, 7, 0, 14, + 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 10, 0, 0, 13, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 12, + 0, 0, 0, 8, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 12, 0, 0, 0, + 11, 0, 0, 0, 0, 0, 12, 0, 0, 10, 0, 0, 8, 6, + 0, 8, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 12, 0, + 0, 5, 0, 0, 0, 0, 0, 0, 14, 0, 11, 0, 0, 0, + 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 9, 0, 0, + 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, + 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 8, 0, 0, 14, + 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 10, 9, 0, 0, 0, 0, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 10, + + }; + static struct StaticNameTable wordlist[] = + { + {"",}, {"",}, {"",}, {"",}, {"",}, + {"olive", 97}, + {"maroon", 80}, + {"",}, {"",}, {"",}, + {"azure", 4}, + {"salmon", 117}, + {"",}, + {"seashell", 120}, + {"lime", 76}, + {"linen", 78}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"sienna", 121}, + {"",}, + {"moccasin", 93}, + {"",}, {"",}, {"",}, {"",}, + {"tan", 129}, + {"teal", 130}, + {"mediumslateblue", 86}, + {"",}, + {"magenta", 79}, + {"seagreen", 119}, + {"aqua", 2}, + {"",}, + {"mediumaquamarine", 81}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"darksalmon", 32}, + {"",}, {"",}, + {"darkslateblue", 34}, + {"mediumseagreen", 85}, + {"",}, + {"lightsalmon", 70}, + {"mediumspringgreen", 87}, + {"red", 113}, + {"",}, {"",}, + {"tomato", 132}, + {"thistle", 131}, + {"lavender", 59}, + {"",}, + {"aquamarine", 3}, + {"silver", 122}, + {"",}, {"",}, + {"turquoise", 133}, + {"mediumvioletred", 89}, + {"",}, + {"darkseagreen", 33}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"darkolivegreen", 28}, + {"white", 136}, + {"violet", 134}, + {"antiquewhite", 1}, + {"",}, + {"snow", 126}, + {"mediumturquoise", 88}, + {"",}, {"",}, {"",}, {"",}, + {"darkviolet", 37}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"navajowhite", 94}, + {"",}, {"",}, {"",}, {"",}, + {"orchid", 101}, + {"",}, {"",}, + {"indianred", 55}, + {"",}, {"",}, + {"skyblue", 123}, + {"",}, {"",}, + {"khaki", 58}, + {"indigo", 56}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"green", 51}, + {"orange", 99}, + {"darkred", 31}, + {"darkturquoise", 36}, + {"lawngreen", 61}, + {"",}, {"",}, {"",}, {"",}, + {"gold", 48}, + {"wheat", 135}, + {"",}, {"",}, {"",}, + {"limegreen", 77}, + {"",}, + {"darkmagenta", 27}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"fuchsia", 45}, + {"",}, + {"darkkhaki", 26}, + {"",}, {"",}, {"",}, + {"lightseagreen", 71}, + {"plum", 110}, + {"",}, {"",}, {"",}, {"",}, + {"darkgreen", 25}, + {"darkorange", 29}, + {"",}, {"",}, {"",}, + {"peru", 108}, + {"lightgreen", 67}, + {"purple", 112}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"whitesmoke", 137}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, + {"hotpink", 54}, + {"",}, + {"goldenrod", 49}, + {"",}, {"",}, + {"mediumpurple", 84}, + {"darkgoldenrod", 23}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, + {"floralwhite", 43}, + {"",}, {"",}, + {"orangered", 100}, + {"",}, {"",}, {"",}, {"",}, + {"blue", 9}, + {"beige", 5}, + {"",}, + {"navy", 95}, + {"",}, + {"aliceblue", 0}, + {"",}, {"",}, {"",}, {"",}, + {"slateblue", 124}, + {"",}, + {"saddlebrown", 116}, + {"",}, {"",}, {"",}, + {"ghostwhite", 47}, + {"",}, {"",}, + {"palevioletred", 105}, + {"",}, + {"brown", 11}, + {"bisque", 6}, + {"",}, + {"paleturquoise", 104}, + {"royalblue", 115}, + {"mediumblue", 82}, + {"",}, {"",}, {"",}, + {"pink", 109}, + {"",}, + {"forestgreen", 44}, + {"",}, {"",}, + {"steelblue", 128}, + {"",}, {"",}, + {"mistyrose", 92}, + {"",}, + {"lightblue", 63}, + {"lightgoldenrodyellow", 66}, + {"",}, {"",}, + {"darkblue", 21}, + {"rosybrown", 114}, + {"coral", 16}, + {"",}, + {"oldlace", 96}, + {"lavenderblush", 60}, + {"chocolate", 15}, + {"blueviolet", 10}, + {"",}, {"",}, {"",}, + {"palegreen", 103}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"deeppink", 38}, + {"",}, + {"dodgerblue", 41}, + {"darkslategray", 35}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"crimson", 19}, + {"",}, + {"lightsteelblue", 74}, + {"",}, {"",}, {"",}, {"",}, + {"mintcream", 91}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"lightcoral", 64}, + {"",}, {"",}, + {"palegoldenrod", 102}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, + {"gainsboro", 46}, + {"chartreuse", 14}, + {"",}, + {"mediumorchid", 83}, + {"",}, {"",}, {"",}, + {"honeydew", 53}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"gray", 50}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, + {"deepskyblue", 39}, + {"",}, {"",}, + {"midnightblue", 90}, + {"",}, {"",}, {"",}, + {"springgreen", 127}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"lightskyblue", 72}, + {"",}, {"",}, + {"darkorchid", 30}, + {"",}, {"",}, + {"cornsilk", 18}, + {"yellow", 138}, + {"",}, + {"darkgray", 24}, + {"",}, {"",}, + {"lightpink", 69}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"lemonchiffon", 62}, + {"",}, {"",}, + {"black", 7}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"lightslategray", 73}, + {"",}, + {"yellowgreen", 139}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"powderblue", 111}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"lightyellow", 75}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"ivory", 57}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, + {"cyan", 20}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"olivedrab", 98}, + {"",}, {"",}, {"",}, {"",}, + {"greenyellow", 52}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"dimgray", 40}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"cadetblue", 13}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"darkcyan", 22}, + {"",}, {"",}, + {"blanchedalmond", 8}, + {"",}, {"",}, + {"lightcyan", 65}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"sandybrown", 118}, + {"peachpuff", 107}, + {"",}, {"",}, {"",}, {"",}, + {"firebrick", 42}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"slategray", 125}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, + {"burlywood", 12}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"lightgrey", 68}, + {"",}, {"",}, {"",}, + {"cornflowerblue", 17}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"papayawhip", 106}, + }; + + if (str != NULL) { + int len = PL_strlen(str); + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) { + register int hval = len; + + switch (hval) + { + default: + case 11: + hval += asso_values[MYLOWER(str[10])]; + case 10: + case 9: + hval += asso_values[MYLOWER(str[8])]; + case 8: + case 7: + hval += asso_values[MYLOWER(str[6])]; + case 6: + hval += asso_values[MYLOWER(str[5])]; + case 5: + hval += asso_values[MYLOWER(str[4])]; + case 4: + case 3: + case 2: + hval += asso_values[MYLOWER(str[1])]; + case 1: + hval += asso_values[MYLOWER(str[0])]; + break; + } + hval += asso_values[MYLOWER(str[len - 1])]; + if (hval <= MAX_HASH_VALUE && hval >= MIN_HASH_VALUE) { + if (len == lengthtable[hval]) { + register const char *tag = wordlist[hval].tag; + + /* + ** While not at the end of the string, if they ever differ + ** they are not equal. We know "tag" is already lower case. + */ + while ((*tag != '\0')&&(*str != '\0')) { + if (*tag != (char) MYLOWER(*str)) { + return -1; + } + tag++; + str++; + } + + /* + ** One of the strings has ended, if they are both ended, then they + ** are equal, otherwise not. + */ + if ((*tag == '\0')&&(*str == '\0')) { + return wordlist[hval].id; + } + } + } + } + } + return -1; +} + +const nsColorNames::NameTableEntry nsColorNames::kNameTable[] = { + { "aliceblue", 0 }, + { "antiquewhite", 1 }, + { "aqua", 2 }, + { "aquamarine", 3 }, + { "azure", 4 }, + { "beige", 5 }, + { "bisque", 6 }, + { "black", 7 }, + { "blanchedalmond", 8 }, + { "blue", 9 }, + { "blueviolet", 10 }, + { "brown", 11 }, + { "burlywood", 12 }, + { "cadetblue", 13 }, + { "chartreuse", 14 }, + { "chocolate", 15 }, + { "coral", 16 }, + { "cornflowerblue", 17 }, + { "cornsilk", 18 }, + { "crimson", 19 }, + { "cyan", 20 }, + { "darkblue", 21 }, + { "darkcyan", 22 }, + { "darkgoldenrod", 23 }, + { "darkgray", 24 }, + { "darkgreen", 25 }, + { "darkkhaki", 26 }, + { "darkmagenta", 27 }, + { "darkolivegreen", 28 }, + { "darkorange", 29 }, + { "darkorchid", 30 }, + { "darkred", 31 }, + { "darksalmon", 32 }, + { "darkseagreen", 33 }, + { "darkslateblue", 34 }, + { "darkslategray", 35 }, + { "darkturquoise", 36 }, + { "darkviolet", 37 }, + { "deeppink", 38 }, + { "deepskyblue", 39 }, + { "dimgray", 40 }, + { "dodgerblue", 41 }, + { "firebrick", 42 }, + { "floralwhite", 43 }, + { "forestgreen", 44 }, + { "fuchsia", 45 }, + { "gainsboro", 46 }, + { "ghostwhite", 47 }, + { "gold", 48 }, + { "goldenrod", 49 }, + { "gray", 50 }, + { "green", 51 }, + { "greenyellow", 52 }, + { "honeydew", 53 }, + { "hotpink", 54 }, + { "indianred", 55 }, + { "indigo", 56 }, + { "ivory", 57 }, + { "khaki", 58 }, + { "lavender", 59 }, + { "lavenderblush", 60 }, + { "lawngreen", 61 }, + { "lemonchiffon", 62 }, + { "lightblue", 63 }, + { "lightcoral", 64 }, + { "lightcyan", 65 }, + { "lightgoldenrodyellow", 66 }, + { "lightgreen", 67 }, + { "lightgrey", 68 }, + { "lightpink", 69 }, + { "lightsalmon", 70 }, + { "lightseagreen", 71 }, + { "lightskyblue", 72 }, + { "lightslategray", 73 }, + { "lightsteelblue", 74 }, + { "lightyellow", 75 }, + { "lime", 76 }, + { "limegreen", 77 }, + { "linen", 78 }, + { "magenta", 79 }, + { "maroon", 80 }, + { "mediumaquamarine", 81 }, + { "mediumblue", 82 }, + { "mediumorchid", 83 }, + { "mediumpurple", 84 }, + { "mediumseagreen", 85 }, + { "mediumslateblue", 86 }, + { "mediumspringgreen", 87 }, + { "mediumturquoise", 88 }, + { "mediumvioletred", 89 }, + { "midnightblue", 90 }, + { "mintcream", 91 }, + { "mistyrose", 92 }, + { "moccasin", 93 }, + { "navajowhite", 94 }, + { "navy", 95 }, + { "oldlace", 96 }, + { "olive", 97 }, + { "olivedrab", 98 }, + { "orange", 99 }, + { "orangered", 100 }, + { "orchid", 101 }, + { "palegoldenrod", 102 }, + { "palegreen", 103 }, + { "paleturquoise", 104 }, + { "palevioletred", 105 }, + { "papayawhip", 106 }, + { "peachpuff", 107 }, + { "peru", 108 }, + { "pink", 109 }, + { "plum", 110 }, + { "powderblue", 111 }, + { "purple", 112 }, + { "red", 113 }, + { "rosybrown", 114 }, + { "royalblue", 115 }, + { "saddlebrown", 116 }, + { "salmon", 117 }, + { "sandybrown", 118 }, + { "seagreen", 119 }, + { "seashell", 120 }, + { "sienna", 121 }, + { "silver", 122 }, + { "skyblue", 123 }, + { "slateblue", 124 }, + { "slategray", 125 }, + { "snow", 126 }, + { "springgreen", 127 }, + { "steelblue", 128 }, + { "tan", 129 }, + { "teal", 130 }, + { "thistle", 131 }, + { "tomato", 132 }, + { "turquoise", 133 }, + { "violet", 134 }, + { "wheat", 135 }, + { "white", 136 }, + { "whitesmoke", 137 }, + { "yellow", 138 }, + { "yellowgreen", 139 }, +}; diff --git a/mozilla/gfx/src/nsColorNames.h b/mozilla/gfx/src/nsColorNames.h new file mode 100644 index 00000000000..10575caa724 --- /dev/null +++ b/mozilla/gfx/src/nsColorNames.h @@ -0,0 +1,44 @@ +/* -*- 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. + */ + +#ifndef nsColorNames_h___ +#define nsColorNames_h___ + +#include "nsColor.h" +#include "nsColorNameIDs.h" + +class NS_GFX nsColorNames { +public: + // Given a null terminated string of 7 bit characters, return the + // tag id (see nsHTMLTagIDs.h) for the tag or -1 if the tag is not + // known. The lookup function uses a perfect hash. + static PRInt32 LookupName(const char* str); + + // Color id to rgb value table + static nscolor kColors[]; + + struct NameTableEntry { + const char* name; + PRInt32 id; + }; + + // A table whose index is the id (from LookupName) + static const NameTableEntry kNameTable[]; +}; + +#endif /* nsColorNames_h___ */ diff --git a/mozilla/gfx/src/nsColorNamesRGB.cpp b/mozilla/gfx/src/nsColorNamesRGB.cpp new file mode 100644 index 00000000000..b8483290241 --- /dev/null +++ b/mozilla/gfx/src/nsColorNamesRGB.cpp @@ -0,0 +1,144 @@ +/* Do not edit - generated by tools/Makefile */ +#include "nsColorNames.h" +nscolor nsColorNames::kColors[COLOR_MAX] = { + NS_RGB(240, 248, 255), + NS_RGB(250, 235, 215), + NS_RGB( 0, 255, 255), + NS_RGB(127, 255, 212), + NS_RGB(240, 255, 255), + NS_RGB(245, 245, 220), + NS_RGB(255, 228, 196), + NS_RGB( 0, 0, 0), + NS_RGB(255, 235, 205), + NS_RGB( 0, 0, 255), + NS_RGB(138, 43, 226), + NS_RGB(165, 42, 42), + NS_RGB(222, 184, 135), + NS_RGB( 95, 158, 160), + NS_RGB(127, 255, 0), + NS_RGB(210, 105, 30), + NS_RGB(255, 127, 80), + NS_RGB(100, 149, 237), + NS_RGB(255, 248, 220), + NS_RGB(220, 20, 60), + NS_RGB( 0, 255, 255), + NS_RGB( 0, 0, 139), + NS_RGB( 0, 139, 139), + NS_RGB(184, 134, 11), + NS_RGB(169, 169, 169), + NS_RGB( 0, 100, 0), + NS_RGB(189, 183, 107), + NS_RGB(139, 0, 139), + NS_RGB( 85, 107, 47), + NS_RGB(255, 140, 0), + NS_RGB(153, 50, 204), + NS_RGB(139, 0, 0), + NS_RGB(233, 150, 122), + NS_RGB(143, 188, 143), + NS_RGB( 72, 61, 139), + NS_RGB( 47, 79, 79), + NS_RGB( 0, 206, 209), + NS_RGB(148, 0, 211), + NS_RGB(255, 20, 147), + NS_RGB( 0, 191, 255), + NS_RGB(105, 105, 105), + NS_RGB( 30, 144, 255), + NS_RGB(178, 34, 34), + NS_RGB(255, 250, 240), + NS_RGB( 34, 139, 34), + NS_RGB(255, 0, 255), + NS_RGB(220, 220, 220), + NS_RGB(248, 248, 255), + NS_RGB(255, 215, 0), + NS_RGB(218, 165, 32), + NS_RGB(128, 128, 128), + NS_RGB( 0, 128, 0), + NS_RGB(173, 255, 47), + NS_RGB(240, 255, 240), + NS_RGB(255, 105, 180), + NS_RGB(205, 92, 92), + NS_RGB( 75, 0, 130), + NS_RGB(255, 255, 240), + NS_RGB(240, 230, 140), + NS_RGB(230, 230, 250), + NS_RGB(255, 240, 245), + NS_RGB(124, 252, 0), + NS_RGB(255, 250, 205), + NS_RGB(173, 216, 230), + NS_RGB(240, 128, 128), + NS_RGB(224, 255, 255), + NS_RGB(250, 250, 210), + NS_RGB(144, 238, 144), + NS_RGB(211, 211, 211), + NS_RGB(255, 182, 193), + NS_RGB(255, 160, 122), + NS_RGB( 32, 178, 170), + NS_RGB(135, 206, 250), + NS_RGB(119, 136, 153), + NS_RGB(176, 196, 222), + NS_RGB(255, 255, 224), + NS_RGB( 0, 255, 0), + NS_RGB( 50, 205, 50), + NS_RGB(250, 240, 230), + NS_RGB(255, 0, 255), + NS_RGB(128, 0, 0), + NS_RGB(102, 205, 170), + NS_RGB( 0, 0, 205), + NS_RGB(186, 85, 211), + NS_RGB(147, 112, 219), + NS_RGB( 60, 179, 113), + NS_RGB(123, 104, 238), + NS_RGB( 0, 250, 154), + NS_RGB( 72, 209, 204), + NS_RGB(199, 21, 133), + NS_RGB( 25, 25, 112), + NS_RGB(245, 255, 250), + NS_RGB(255, 228, 225), + NS_RGB(255, 228, 181), + NS_RGB(255, 222, 173), + NS_RGB( 0, 0, 128), + NS_RGB(253, 245, 230), + NS_RGB(128, 128, 0), + NS_RGB(107, 142, 35), + NS_RGB(255, 165, 0), + NS_RGB(255, 69, 0), + NS_RGB(218, 112, 214), + NS_RGB(238, 232, 170), + NS_RGB(152, 251, 152), + NS_RGB(175, 238, 238), + NS_RGB(219, 112, 147), + NS_RGB(255, 239, 213), + NS_RGB(255, 218, 185), + NS_RGB(205, 133, 63), + NS_RGB(255, 192, 203), + NS_RGB(221, 160, 221), + NS_RGB(176, 224, 230), + NS_RGB(128, 0, 128), + NS_RGB(255, 0, 0), + NS_RGB(188, 143, 143), + NS_RGB( 65, 105, 225), + NS_RGB(139, 69, 19), + NS_RGB(250, 128, 114), + NS_RGB(244, 164, 96), + NS_RGB( 46, 139, 87), + NS_RGB(255, 245, 238), + NS_RGB(160, 82, 45), + NS_RGB(192, 192, 192), + NS_RGB(135, 206, 235), + NS_RGB(106, 90, 205), + NS_RGB(112, 128, 144), + NS_RGB(255, 250, 250), + NS_RGB( 0, 255, 127), + NS_RGB( 70, 130, 180), + NS_RGB(210, 180, 140), + NS_RGB( 0, 128, 128), + NS_RGB(216, 191, 216), + NS_RGB(255, 99, 71), + NS_RGB( 64, 224, 208), + NS_RGB(238, 130, 238), + NS_RGB(245, 222, 179), + NS_RGB(255, 255, 255), + NS_RGB(245, 245, 245), + NS_RGB(255, 255, 0), + NS_RGB(154, 205, 50), +}; diff --git a/mozilla/gfx/src/nsCoord.h b/mozilla/gfx/src/nsCoord.h new file mode 100644 index 00000000000..b28fb074146 --- /dev/null +++ b/mozilla/gfx/src/nsCoord.h @@ -0,0 +1,38 @@ +/* -*- 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. + */ + +#ifndef NSCOORD_H +#define NSCOORD_H + +#include "nscore.h" + +/* + * Basic type used for the geometry classes. By making it a typedef we can + * easily change it in the future. + * + * All coordinates are maintained as signed 32-bit integers in the twips + * coordinate space. A twip is 1/20th of a point, and there are 72 points per + * inch. + * + * Twips are used because they are a device-independent unit of measure. See + * header file nsUnitConversion.h for many useful macros to convert between + * different units of measure. + */ +typedef PRInt32 nscoord; + +#endif /* NSCOORD_H */ diff --git a/mozilla/gfx/src/nsFont.cpp b/mozilla/gfx/src/nsFont.cpp new file mode 100644 index 00000000000..35dfd32e21a --- /dev/null +++ b/mozilla/gfx/src/nsFont.cpp @@ -0,0 +1,80 @@ +/* -*- 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 "nsFont.h" +#include "nsString.h" + +nsFont::nsFont(const char* aName, PRUint8 aStyle, PRUint8 aVariant, + PRUint16 aWeight, PRUint8 aDecoration, nscoord aSize) + : name(aName) +{ + style = aStyle; + variant = aVariant; + weight = aWeight; + decorations = aDecoration; + size = aSize; +} + +nsFont::nsFont(const nsString& aName, PRUint8 aStyle, PRUint8 aVariant, + PRUint16 aWeight, PRUint8 aDecoration, nscoord aSize) + : name(aName) +{ + style = aStyle; + variant = aVariant; + weight = aWeight; + decorations = aDecoration; + size = aSize; +} + +nsFont::nsFont(const nsFont& aOther) + : name(aOther.name) +{ + style = aOther.style; + variant = aOther.variant; + weight = aOther.weight; + decorations = aOther.decorations; + size = aOther.size; +} + +nsFont::~nsFont() +{ +} + +PRBool nsFont::Equals(const nsFont& aOther) const +{ + if ((style == aOther.style) && + (variant == aOther.variant) && + (weight == aOther.weight) && + (decorations == aOther.decorations) && + (size == aOther.size) && + name.EqualsIgnoreCase(aOther.name)) { + return PR_TRUE; + } + return PR_FALSE; +} + +nsFont& nsFont::operator=(const nsFont& aOther) +{ + name = aOther.name; + style = aOther.style; + variant = aOther.variant; + weight = aOther.weight; + decorations = aOther.decorations; + size = aOther.size; + return *this; +} diff --git a/mozilla/gfx/src/nsFont.h b/mozilla/gfx/src/nsFont.h new file mode 100644 index 00000000000..5615021ddd9 --- /dev/null +++ b/mozilla/gfx/src/nsFont.h @@ -0,0 +1,86 @@ +/* -*- 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. + */ + +#ifndef nsFont_h___ +#define nsFont_h___ + +#include "nscore.h" +#include "nsCoord.h" +#include "nsString.h" + +// XXX we need a method to enumerate all of the possible fonts on the +// system across family, weight, style, size, etc. But not here! + +// Font structure. +struct NS_GFX nsFont { + // The family name of the font + nsString name; + + // The style of font (normal, italic, oblique) + PRUint8 style; + + // The variant of the font (normal, small-caps) + PRUint8 variant; + + // The weight of the font (0-999) + PRUint16 weight; + + // The decorations on the font (underline, overline, + // line-through). The decorations can be binary or'd together. + PRUint8 decorations; + + // The size of the font, in nscoord units + nscoord size; + + // Initialize the font struct with an iso-latin1 name + nsFont(const char* aName, PRUint8 aStyle, PRUint8 aVariant, + PRUint16 aWeight, PRUint8 aDecoration, nscoord aSize); + + // Initialize the font struct with a (potentially) unicode name + nsFont(const nsString& aName, PRUint8 aStyle, PRUint8 aVariant, + PRUint16 aWeight, PRUint8 aDecoration, nscoord aSize); + + // Make a copy of the given font + nsFont(const nsFont& aFont); + + ~nsFont(); + + PRBool operator==(const nsFont& aOther) const { + return Equals(aOther); + } + + PRBool Equals(const nsFont& aOther) const ; + + nsFont& operator=(const nsFont& aOther); +}; + +#define NS_FONT_STYLE_NORMAL 0 +#define NS_FONT_STYLE_ITALIC 1 +#define NS_FONT_STYLE_OBLIQUE 2 + +#define NS_FONT_VARIANT_NORMAL 0 +#define NS_FONT_VARIANT_SMALL_CAPS 1 + +#define NS_FONT_DECORATION_UNDERLINE 0x1 +#define NS_FONT_DECORATION_OVERLINE 0x2 +#define NS_FONT_DECORATION_LINE_THROUGH 0x4 + +#define NS_FONT_WEIGHT_NORMAL 400 +#define NS_FONT_WEIGHT_BOLD 700 + +#endif /* nsFont_h___ */ diff --git a/mozilla/gfx/src/nsFontCache.cpp b/mozilla/gfx/src/nsFontCache.cpp new file mode 100644 index 00000000000..73354c4a1f6 --- /dev/null +++ b/mozilla/gfx/src/nsFontCache.cpp @@ -0,0 +1,139 @@ +/* -*- 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 "nsIFontCache.h" +#include "nsFont.h" +#include "nsVoidArray.h" +#include "nsIFontMetrics.h" +#include "nsIDeviceContext.h" +#include "nsGfxCIID.h" + +static NS_DEFINE_IID(kIFontCacheIID, NS_IFONT_CACHE_IID); + +class FontCacheImpl : public nsIFontCache +{ +public: + FontCacheImpl(); + ~FontCacheImpl(); + + NS_DECL_ISUPPORTS + + virtual nsresult Init(nsIDeviceContext* aContext); + virtual nsIDeviceContext* GetDeviceContext() const; + virtual nsIFontMetrics* GetMetricsFor(const nsFont& aFont); + virtual void Flush(); + +protected: + nsVoidArray mFontMetrics; + nsIDeviceContext *mContext; +}; + +FontCacheImpl :: FontCacheImpl() +{ + NS_INIT_REFCNT(); + + mContext = nsnull; +} + +FontCacheImpl :: ~FontCacheImpl() +{ + Flush(); + NS_IF_RELEASE(mContext); +} + +NS_IMPL_ISUPPORTS(FontCacheImpl, kIFontCacheIID) + +nsresult FontCacheImpl :: Init(nsIDeviceContext* aContext) +{ + NS_PRECONDITION(nsnull != aContext, "null ptr"); + mContext = aContext; + NS_ADDREF(mContext); + return NS_OK; +} + +nsIDeviceContext* FontCacheImpl::GetDeviceContext() const +{ + NS_IF_ADDREF(mContext); + return mContext; +} + +nsIFontMetrics* FontCacheImpl :: GetMetricsFor(const nsFont& aFont) +{ + nsIFontMetrics* fm; + + // First check our cache + PRInt32 n = mFontMetrics.Count(); + + for (PRInt32 cnt = 0; cnt < n; cnt++) + { + fm = (nsIFontMetrics*) mFontMetrics.ElementAt(cnt); + + if (aFont.Equals(fm->GetFont())) + { + NS_ADDREF(fm); + return fm; + } + } + + // It's not in the cache. Get font metrics and then cache them. + + static NS_DEFINE_IID(kFontMetricsCID, NS_FONT_METRICS_CID); + static NS_DEFINE_IID(kFontMetricsIID, NS_IFONT_METRICS_IID); + + nsresult rv = NSRepository::CreateInstance(kFontMetricsCID, nsnull, + kFontMetricsIID, (void **)&fm); + if (NS_OK != rv) + return nsnull; + + rv = fm->Init(aFont, mContext); + + if (NS_OK != rv) + return nsnull;/* XXX losing error code */ + + mFontMetrics.AppendElement(fm); + + NS_ADDREF(fm); + + return fm; +} + +void FontCacheImpl::Flush() +{ + PRInt32 i, n = mFontMetrics.Count(); + for (i = 0; i < n; i++) { + nsIFontMetrics* fm = (nsIFontMetrics*) mFontMetrics.ElementAt(i); + NS_RELEASE(fm); + } + mFontMetrics.Clear(); +} + +NS_GFX nsresult +NS_NewFontCache(nsIFontCache **aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + + if (nsnull == aInstancePtrResult) + return NS_ERROR_NULL_POINTER; + + nsIFontCache *cache = new FontCacheImpl(); + + if (nsnull == cache) + return NS_ERROR_OUT_OF_MEMORY; + + return cache->QueryInterface(kIFontCacheIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/gfx/src/nsGfxCIID.h b/mozilla/gfx/src/nsGfxCIID.h new file mode 100644 index 00000000000..8f747908906 --- /dev/null +++ b/mozilla/gfx/src/nsGfxCIID.h @@ -0,0 +1,42 @@ +/* -*- 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. + */ + +#ifndef nsGfxCIID_h__ +#define nsGfxCIID_h__ + +#include "nsISupports.h" +#include "nsIFactory.h" +#include "nsRepository.h" + +#define NS_IMAGE_CID \ +{ 0x6049b260, 0xc1e6, 0x11d1, \ +{ 0xa8, 0x27, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9 } } + +#define NS_RENDERING_CONTEXT_CID \ +{ 0x6049b261, 0xc1e6, 0x11d1, \ +{ 0xa8, 0x27, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9 } } + +#define NS_DEVICE_CONTEXT_CID \ +{ 0x6049b262, 0xc1e6, 0x11d1, \ +{ 0xa8, 0x27, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9 } } + +#define NS_FONT_METRICS_CID \ +{ 0x6049b263, 0xc1e6, 0x11d1, \ +{ 0xa8, 0x27, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9 } } + +#endif \ No newline at end of file diff --git a/mozilla/gfx/src/nsIDeviceContext.h b/mozilla/gfx/src/nsIDeviceContext.h new file mode 100644 index 00000000000..f8f5fc32c40 --- /dev/null +++ b/mozilla/gfx/src/nsIDeviceContext.h @@ -0,0 +1,79 @@ +/* -*- 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. + */ + +#ifndef nsIDeviceContext_h___ +#define nsIDeviceContext_h___ + +#include "nsISupports.h" +#include "nsIRenderingContext.h" +#include "nsCoord.h" +#include "nsRect.h" + +class nsIView; +class nsIRenderingContext; +class nsIFontCache; +class nsIFontMetrics; +class nsIWidget; +struct nsFont; + +#define NS_IDEVICE_CONTEXT_IID \ +{ 0x5931c580, 0xb917, 0x11d1, \ +{ 0xa8, 0x24, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9 } } + +class nsIDeviceContext : public nsISupports +{ +public: + virtual nsresult Init() = 0; + + virtual nsIRenderingContext * CreateRenderingContext(nsIView *aView) = 0; + virtual void InitRenderingContext(nsIRenderingContext *aContext, nsIWidget *aWindow) = 0; + + //these are queries to figure out how large an output unit + //(i.e. pixel) is in terms of twips (1/20 of a point) + virtual float GetDevUnitsToTwips() const = 0; + virtual float GetTwipsToDevUnits() const = 0; + + //these are set by the object that created this + //device context to define what the scale is + //between the units used by the app and the + //device units + virtual void SetAppUnitsToDevUnits(float aAppUnits) = 0; + virtual void SetDevUnitsToAppUnits(float aDevUnits) = 0; + + //these are used to query the scale values defined + //by the above Set*() methods + virtual float GetAppUnitsToDevUnits() const = 0; + virtual float GetDevUnitsToAppUnits() const = 0; + + virtual float GetScrollBarWidth() const = 0; + virtual float GetScrollBarHeight() const = 0; + + //be sure to Relase() after you are done with the Get() + virtual nsIFontCache * GetFontCache() = 0; + virtual void FlushFontCache() = 0; + + // Get the font metrics for a given font. + virtual nsIFontMetrics* GetMetricsFor(const nsFont& aFont) = 0; + + //get and set the document zoom value used for display-time + //scaling. default is 1.0 (no zoom) + virtual void SetZoom(float aZoom) = 0; + virtual float GetZoom() const = 0; +}; + +#endif /* nsIDeviceContext_h___ */ diff --git a/mozilla/gfx/src/nsIFontCache.h b/mozilla/gfx/src/nsIFontCache.h new file mode 100644 index 00000000000..9201bf59e34 --- /dev/null +++ b/mozilla/gfx/src/nsIFontCache.h @@ -0,0 +1,68 @@ +/* -*- 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. + */ + +#ifndef nsIFontCache_h___ +#define nsIFontCache_h___ + +#include +#include "nscore.h" +#include "nsISupports.h" + +class nsIFontMetrics; +class nsIDeviceContext; +struct nsFont; + +// IID for the nsIFontCache interface +#define NS_IFONT_CACHE_IID \ +{ 0x894758e0, 0xb49a, 0x11d1, \ +{ 0xa8, 0x24, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9 } } + +/** + * Font cache interface. A font cache is bound to a particular device + * context which it uses to realize the font metrics. The cache uses + * the nsFont as a key. + */ +class nsIFontCache : public nsISupports +{ +public: + /** + * Initialize the font cache. Call this after creating the font + * cache and before trying to use it. + */ + virtual nsresult Init(nsIDeviceContext* aContext) = 0; + + /** + * Get the device context associated with this cache + */ + virtual nsIDeviceContext* GetDeviceContext() const = 0; + + /** + * Get metrics for a given font. + */ + virtual nsIFontMetrics* GetMetricsFor(const nsFont& aFont) = 0; + + /** + * Flush the cache. + */ + virtual void Flush() = 0; +}; + +extern NS_GFX nsresult + NS_NewFontCache(nsIFontCache **aInstancePtrResult); + +#endif diff --git a/mozilla/gfx/src/nsIFontMetrics.h b/mozilla/gfx/src/nsIFontMetrics.h new file mode 100644 index 00000000000..18b98536ded --- /dev/null +++ b/mozilla/gfx/src/nsIFontMetrics.h @@ -0,0 +1,87 @@ +/* -*- 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. + */ + +#ifndef nsIFontMetrics_h___ +#define nsIFontMetrics_h___ + +#include "nsISupports.h" +#include "nsCoord.h" + +struct nsFont; +class nsString; +class nsIDeviceContext; + +// IID for the nsIFontMetrics interface +#define NS_IFONT_METRICS_IID \ +{ 0xc74cb770, 0xa33e, 0x11d1, \ +{ 0xa8, 0x24, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9 } } + +//---------------------------------------------------------------------- + +// Native font handle +typedef void* nsFontHandle; + +// FontMetrics interface +class nsIFontMetrics : public nsISupports +{ + //what about encoding, where do we put that? MMP + +public: + //initializer + virtual nsresult Init(const nsFont& aFont, nsIDeviceContext* aContext) = 0; + + //get the width of an 8 bit char + virtual nscoord GetWidth(char aC) = 0; + + //get the width of a unicode char + virtual nscoord GetWidth(PRUnichar aC) = 0; + + //get the width of an nsString + virtual nscoord GetWidth(const nsString& aString) = 0; + + //get the width of 8 bit character string + virtual nscoord GetWidth(const char *aString) = 0; + + //get the width of a Unicode character string + virtual nscoord GetWidth(const PRUnichar *aString, PRUint32 aLength) = 0; + + //get the height as this font + virtual nscoord GetHeight() = 0; + + //get height - (ascent + descent) + virtual nscoord GetLeading() = 0; + + //get the maximum character ascent + virtual nscoord GetMaxAscent() = 0; + + //get the maximum character descent + virtual nscoord GetMaxDescent() = 0; + + //get the maximum character advance for the font + virtual nscoord GetMaxAdvance() = 0; + + //get the widths of the first 256 characters of the font + virtual const nscoord *GetWidths() = 0; + + //get the font associated width these metrics + virtual const nsFont& GetFont() = 0; + + virtual nsFontHandle GetFontHandle() = 0; +}; + +#endif /* nsIFontMetrics_h___ */ diff --git a/mozilla/gfx/src/nsIImage.h b/mozilla/gfx/src/nsIImage.h new file mode 100644 index 00000000000..b21e5c5c6e7 --- /dev/null +++ b/mozilla/gfx/src/nsIImage.h @@ -0,0 +1,109 @@ +/* -*- 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. + */ + +#ifndef nsIImage_h___ +#define nsIImage_h___ + +#include "nsISupports.h" +#include "nsRect.h" +#include "nsIRenderingContext.h" + +typedef struct +{ + //I lifted this from the image lib. The difference is that + //this uses nscolor instead of NI_RGB. Multiple color pollution + //is a bad thing. MMP + PRInt32 NumColors; // Number of colors in the colormap. + // A negative value can be used to denote a + // possibly non-unique set. + //nscolor *Map; // Colormap colors. + PRUint8 *Index; // NULL, if map is in index order, otherwise + // specifies the indices of the map entries. */ +} nsColorMap; + +typedef enum { + nsMaskRequirements_kNoMask, + nsMaskRequirements_kNeeds1Bit, + nsMaskRequirements_kNeeds8Bit +} nsMaskRequirements; + + +#define nsImageUpdateFlags_kColorMapChanged 0x1 +#define nsImageUpdateFlags_kBitsChanged 0x2 + +// IID for the nsIImage interface +#define NS_IIMAGE_IID \ +{ 0x0b4faaa0, 0xaa3a, 0x11d1, \ +{ 0xa8, 0x24, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9 } } + +// Interface to Images +class nsIImage : public nsISupports +{ +public: + //initialize the image. aDepth is either 8 or 24. if the image has an alpha + //channel, aNeedAlpha will be true + // had nsqresult for return, need to fix fix + virtual nsresult Init(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth, nsMaskRequirements aMaskRequirements) = 0; + + //dimensioning in PIXELS + virtual PRInt32 GetWidth() = 0; + virtual PRInt32 GetHeight() = 0; + + //if the image is not optimzed, get a pointer to the bits + virtual PRUint8 * GetBits() = 0; + + //get the number of bytes to jump from scanline to scanline + virtual PRInt32 GetLineStride() = 0; + + //if the image is not optimzed, get a pointer to the bits + virtual PRUint8 * GetAlphaBits() = 0; + + //get the number of bytes to jump from scanline to scanline + virtual PRInt32 GetAlphaLineStride() = 0; + + virtual void ImageUpdated(PRUint8 aFlags, nsRect *aUpdateRect) = 0; + + //has this image been optimized? + virtual PRBool IsOptimized() = 0; + + //convert this image to a version optimized for display + virtual nsresult Optimize(nsDrawingSurface aSurface) = 0; + + //if this returns non-null, this image is color mapped + virtual nsColorMap * GetColorMap() = 0; + + virtual PRBool Draw(nsDrawingSurface aSurface, PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight) = 0; + virtual PRBool Draw(nsDrawingSurface aSurface, PRInt32 aSX, PRInt32 aSY, PRInt32 aSWidth, PRInt32 aSHeight, + PRInt32 aDX, PRInt32 aDY, PRInt32 aDWidth, PRInt32 aDHeight) = 0; + + //get the color space metrics for this image + //virtual NI_ColorSpec * GetColorSpec() = 0; fix + + //get the color which should be considered transparent. + //if this image is color mapped, this value will be an + //index into the color map. hokey? yes, but it avoids + //another silly api or struct. + //virtual nscolor GetTransparentColor() = 0; fix. +}; + +//change notification API flag bits +#define NS_IMAGE_UPDATE_COLORMAP 1 +#define NS_IMAGE_UPDATE_PIXELS 2 +#define NS_IMAGE_UPDATE_ALPHA 4 + +#endif diff --git a/mozilla/gfx/src/nsIImageGroup.h b/mozilla/gfx/src/nsIImageGroup.h new file mode 100644 index 00000000000..97cbc5793cb --- /dev/null +++ b/mozilla/gfx/src/nsIImageGroup.h @@ -0,0 +1,93 @@ +/* -*- 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. + */ + +#ifndef nsIImageGroup_h___ +#define nsIImageGroup_h___ + +#include +#include "nsISupports.h" +#include "nscore.h" +#include "nsColor.h" + +class nsIImageGroupObserver; +class nsIImageRequestObserver; +class nsIImageRequest; +class nsIRenderingContext; + +/* For important images, like backdrops. */ +#define nsImageLoadFlags_kHighPriority 0x01 +/* Don't throw this image out of cache. */ +#define nsImageLoadFlags_kSticky 0x02 +/* Don't get image out of image cache. */ +#define nsImageLoadFlags_kBypassCache 0x04 +/* Don't load if image cache misses. */ +#define nsImageLoadFlags_kOnlyFromCache 0x08 + +// IID for the nsIImageGroup interface +#define NS_IIMAGEGROUP_IID \ +{ 0xbe927e40, 0xaeaa, 0x11d1, \ +{ 0x9b, 0xc3, 0x00, 0x60, 0x08, 0x8c, 0xa6, 0xb3 } } + +//---------------------------------------------------------------------- +// +// Image group. A convenient way to group a set of image load requests +// and control them as a group. +class nsIImageGroup : public nsISupports +{ +public: + virtual nsresult Init(nsIRenderingContext *aRenderingContext) = 0; + + // Add and remove observers to listen in on image group notifications + virtual PRBool AddObserver(nsIImageGroupObserver *aObserver) = 0; + virtual PRBool RemoveObserver(nsIImageGroupObserver *aObserver) = 0; + + // Fetch the image corresponding to the specified URL. + // + // The observer is notified at significant points in image loading. + // + // The width and height parameters specify the target dimensions of + // the image. The image will be stretched horizontally, vertically or + // both to meet these parameters. If both width and height are zero, + // the image is decoded using its "natural" size. If only one of + // width and height is zero, the image is scaled to the provided + // dimension, with the unspecified dimension scaled to maintain the + // image's original aspect ratio. + // + // If the background color is NULL, a mask will be generated for any + // transparent images. If background color is non-NULL, it indicates + // the RGB value to be painted into the image for "transparent" areas + // of the image, in which case no mask is created. This is intended + // for backdrops and printing. + // + // Image load flags are specified above + virtual nsIImageRequest* GetImage(const char* aUrl, + nsIImageRequestObserver *aObserver, + nscolor aBackgroundColor, + PRUint32 aWidth, PRUint32 aHeight, + PRUint32 aFlags) = 0; + + // Halt decoding of images or animation without destroying associated + // pixmap data. All ImageRequests created with this ImageGroup + // are interrupted. + virtual void Interrupt(void) = 0; +}; + +extern NS_GFX nsresult + NS_NewImageGroup(nsIImageGroup **aInstancePtrResult); + +#endif diff --git a/mozilla/gfx/src/nsIImageManager.h b/mozilla/gfx/src/nsIImageManager.h new file mode 100644 index 00000000000..2187cce20ea --- /dev/null +++ b/mozilla/gfx/src/nsIImageManager.h @@ -0,0 +1,67 @@ +/* -*- 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. + */ + +#ifndef nsIImageManager_h___ +#define nsIImageManager_h___ + +#include +#include "nsISupports.h" +#include "nscore.h" + +typedef enum +{ + nsImageType_kUnknown = 0, + nsImageType_kGIF = 1, + nsImageType_kXBM = 2, + nsImageType_kJPEG = 3, + nsImageType_kPPM = 4, + nsImageType_kPNG = 5 +} nsImageType; + +// IID for the nsIImageManager interface +#define NS_IIMAGEMANAGER_IID \ +{ 0x9f327100, 0xad5a, 0x11d1, \ +{ 0x9b, 0xc3, 0x00, 0x60, 0x08, 0x8c, 0xa6, 0xb3 } } + +//---------------------------------------------------------------------- +// +// Image manager. There is only a single instance, created when the +// class is initially loaded. +class nsIImageManager : public nsISupports +{ +public: + virtual nsresult Init() = 0; + + // Set and get the cache size in bytes + virtual void SetCacheSize(PRInt32 aCacheSize) = 0; + virtual PRInt32 GetCacheSize(void) = 0; + + // Attempts to release some memory by freeing an image from the image + // cache. This may not always be possible either because all images + // in the cache are in use or because the cache is empty. Returns the + // new approximate size of the imagelib cache. + virtual PRInt32 ShrinkCache(void) = 0; + + // Determine the type of the image, based on the first few bytes of data. + virtual nsImageType GetImageType(const char *buf, PRInt32 length) = 0; +}; + +extern NS_GFX nsresult + NS_NewImageManager(nsIImageManager **aInstancePtrResult); + +#endif diff --git a/mozilla/gfx/src/nsIImageObserver.h b/mozilla/gfx/src/nsIImageObserver.h new file mode 100644 index 00000000000..5d6f6c1eaef --- /dev/null +++ b/mozilla/gfx/src/nsIImageObserver.h @@ -0,0 +1,139 @@ +/* -*- 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. + */ + +#ifndef nsIImageObserver_h___ +#define nsIImageObserver_h___ + +#include +#include "nsISupports.h" +#include "nscore.h" + +class nsIImage; +class nsIImageRequest; +class nsIImageGroup; + +typedef enum { + // Image request notifications + nsImageNotification_kStartURL, // Start of decode/display for URL. + nsImageNotification_kDescription, // Availability of image description. + nsImageNotification_kDimensions, // Availability of image dimensions. + nsImageNotification_kIsTransparent, // This image is transparent. + nsImageNotification_kPixmapUpdate, // Change in a rectangular area of + // pixels. + nsImageNotification_kFrameComplete, // Completion of a frame of an animated + // image. + nsImageNotification_kProgress, // Notification of percentage decoded. + nsImageNotification_kImageComplete, // Completion of image decoding. There + // may be multiple instances of this + // event per URL due to server push, + // client pull or looping GIF animation. + nsImageNotification_kStopURL, // Completion of decode/display for URL. + nsImageNotification_kImageDestroyed,// Finalization of an image request. This + // is an indication to perform any + // observer related cleanup. + nsImageNotification_kAborted, // Image decode was aborted by either + // the network library or Interrupt(). + nsImageNotification_kInternalImage, // Internal image icon. +} nsImageNotification; + +typedef enum { + + // Start of image loading. Sent when a loading image is + // added to an image group which currently has no loading images. + nsImageGroupNotification_kStartedLoading, + + // Some images were aborted. A finished loading message will not be sent + // until the aborted images have been destroyed. + nsImageGroupNotification_kAbortedLoading, + + // End of image loading. Sent when the last of the images currently + // in the image group has finished loading. + nsImageGroupNotification_kFinishedLoading, + + // Start of image looping. Sent when an animated image starts looping in + // an image group which currently has no looping animations. + nsImageGroupNotification_kStartedLooping, + + // End of image looping. Sent when the last of the images currently in + // the image group has finished looping. + nsImageGroupNotification_kFinishedLooping + +} nsImageGroupNotification; + +typedef enum { + nsImageError_kNotInCache, // Image URL not available in cache when + // kOnlyFromCache flag was set. + nsImageError_kNoData, // Network library unable to fetch + // provided URL. + nsImageError_kImageDataCorrupt, // Checksum error of some kind in + // image data. + nsImageError_kImageDataTruncated, // Missing data at end of stream. + nsImageError_kImageDataIllegal, // Generic image data error. + nsImageError_kInternalError // Internal Image Library error. + +} nsImageError; + +// IID for the nsIImageRequestObserver interface +#define NS_IIMAGEREQUESTOBSERVER_IID \ +{ 0x965467a0, 0xb8f4, 0x11d1, \ +{ 0x9b, 0xc3, 0x00, 0x60, 0x08, 0x8c, 0xa6, 0xb3 } } + +// IID for the nsIImageGroupObserver interface +#define NS_IIMAGEGROUPOBSERVER_IID \ +{ 0xb3cad300, 0xb8f4, 0x11d1, \ +{ 0x9b, 0xc3, 0x00, 0x60, 0x08, 0x8c, 0xa6, 0xb3 } } + +class nsIImageRequestObserver : public nsISupports { +public: + // Notify the observer of some significant image event. The parameter + // values depend on the notification type as specified below: + // + // kDescription - aParam3 is a string containing the human readable + // description of an image, e.g. "GIF89a 320 x 240 pixels". + // The string storage is static, so it must be copied if + // it is to be preserved after the call to the observer. + // kDimensions - aParam1 and aParam2 are the width and height respectively + // of the image. + // kPixmapUpdate - aParame3 is a pointer to a nsRect struct containing the + // rectangular area of pixels which has been modified by + // the image library. This notification enables the + // client to drive the progressive display of the image. + // kProgress - aParam1 represents the estimated percentage decoded. This + // notification occurs at unspecified intervals. Provided + // that decoding proceeds without error, it is guaranteed that + // notification will take place on completion with a + // percent_progress value of 100. + // + virtual void Notify(nsIImageRequest *aImageRequest, + nsIImage *aImage, + nsImageNotification aNotificationType, + PRInt32 aParam1, PRInt32 aParam2, + void *aParam3)=0; + + // Notify the observer of an error during image loading. + virtual void NotifyError(nsIImageRequest *aImageRequest, + nsImageError aErrorType)=0; +}; + +class nsIImageGroupObserver : public nsISupports { +public: + virtual void Notify(nsIImageGroup *aImageGroup, + nsImageGroupNotification aNotificationType)=0; +}; + +#endif diff --git a/mozilla/gfx/src/nsIImageRequest.h b/mozilla/gfx/src/nsIImageRequest.h new file mode 100644 index 00000000000..cd5129b3e5d --- /dev/null +++ b/mozilla/gfx/src/nsIImageRequest.h @@ -0,0 +1,54 @@ +/* -*- 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. + */ + +#ifndef nsIImageRequest_h___ +#define nsIImageRequest_h___ + +#include +#include "nsISupports.h" +#include "nscore.h" + +class nsIImageRequestObserver; +class nsIImage; + +// IID for the nsIImageRequest interface +#define NS_IIMAGEREQUEST_IID \ +{ 0xc31444c0, 0xaec9, 0x11d1, \ +{ 0x9b, 0xc3, 0x00, 0x60, 0x08, 0x8c, 0xa6, 0xb3 } } + +class nsIImageRequest : public nsISupports { +public: + // Get the image associated with the request. + virtual nsIImage* GetImage() = 0; + + // Return the natural dimensions of the image. Returns 0,0 + //if the dimensions are unknown. + virtual void GetNaturalDimensions(PRUint32 *aWidth, PRUint32 *aHeight) = 0; + + // Add and remove observers to listen in on image loading notifications + virtual PRBool AddObserver(nsIImageRequestObserver *aObserver) = 0; + virtual PRBool RemoveObserver(nsIImageRequestObserver *aObserver) = 0; + + // Interrupt loading of just this image. + virtual void Interrupt() = 0; +}; + +extern NS_GFX nsresult + NS_NewImageRequest(nsIImageRequest **aInstancePtrResult); + +#endif diff --git a/mozilla/gfx/src/nsIRenderingContext.h b/mozilla/gfx/src/nsIRenderingContext.h new file mode 100644 index 00000000000..10feb642a8e --- /dev/null +++ b/mozilla/gfx/src/nsIRenderingContext.h @@ -0,0 +1,141 @@ +/* -*- 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. + */ + +#ifndef nsIRenderingContext_h___ +#define nsIRenderingContext_h___ + +#include "nscore.h" +#include "nsISupports.h" +#include "nsColor.h" +#include "nsCoord.h" + +class nsIWidget; +class nsIFontMetrics; +class nsIImage; +class nsTransform2D; +class nsString; +class nsIFontCache; +class nsIDeviceContext; + +struct nsFont; +struct nsPoint; +struct nsRect; + +// IID for the nsIRenderingContext interface +#define NS_IRENDERING_CONTEXT_IID \ +{ 0x7fd8c0f0, 0xa265, 0x11d1, \ +{ 0xa8, 0x24, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9 } } + +//---------------------------------------------------------------------- + +//a cross platform way of specifying a navite rendering context +typedef void * nsDrawingSurface; + +// RenderingContext interface +class nsIRenderingContext : public nsISupports +{ +public: + //TBD: bind/unbind, transformation of scalars (hacky), + //potential drawmode for selection, polygons. MMP + + virtual nsresult Init(nsIDeviceContext* aContext,nsIWidget *aWidget) = 0; + virtual nsresult Init(nsIDeviceContext* aContext,nsDrawingSurface aSurface) = 0; + + virtual void Reset() = 0; + virtual nsresult SelectOffScreenDrawingSurface(nsDrawingSurface aSurface) = 0; + + virtual void PushState() = 0; + virtual void PopState() = 0; + + virtual PRBool IsVisibleRect(const nsRect& aRect) = 0; + + //set aIntersect to true to cause the new cliprect to be intersected + //with any other cliprects already in the renderingcontext. + virtual void SetClipRect(const nsRect& aRect, PRBool aIntersect) = 0; + virtual const nsRect& GetClipRect() = 0; + + virtual void SetColor(nscolor aColor) = 0; + virtual nscolor GetColor() const = 0; + + virtual void SetFont(const nsFont& aFont) = 0; + virtual const nsFont& GetFont() = 0; + + virtual nsIFontMetrics* GetFontMetrics() = 0; + + virtual void Translate(nscoord aX, nscoord aY) = 0; + virtual void Scale(float aSx, float aSy) = 0; + virtual nsTransform2D * GetCurrentTransform() = 0; + + //create and destroy offscreen renderingsurface compatible with this RC + virtual nsDrawingSurface CreateDrawingSurface(nsRect &aBounds) = 0; + virtual void DestroyDrawingSurface(nsDrawingSurface aDS) = 0; + + virtual nsDrawingSurface CreateOptimizeSurface() = 0; + + virtual nsDrawingSurface getDrawingSurface() = 0; + + virtual void DrawLine(nscoord aX0, nscoord aY0, nscoord aX1, nscoord aY1) = 0; + + virtual void DrawRect(const nsRect& aRect) = 0; + virtual void DrawRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) = 0; + virtual void FillRect(const nsRect& aRect) = 0; + virtual void FillRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) = 0; + + virtual void DrawPolygon(nsPoint aPoints[], PRInt32 aNumPoints) = 0; + virtual void FillPolygon(nsPoint aPoints[], PRInt32 aNumPoints) = 0; + + virtual void DrawEllipse(const nsRect& aRect) = 0; + virtual void DrawEllipse(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) = 0; + virtual void FillEllipse(const nsRect& aRect) = 0; + virtual void FillEllipse(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) = 0; + + virtual void DrawArc(const nsRect& aRect, + float aStartAngle, float aEndAngle) = 0; + virtual void DrawArc(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, + float aStartAngle, float aEndAngle) = 0; + virtual void FillArc(const nsRect& aRect, + float aStartAngle, float aEndAngle) = 0; + virtual void FillArc(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, + float aStartAngle, float aEndAngle) = 0; + + virtual void DrawString(const char *aString, PRUint32 aLength, + nscoord aX, nscoord aY, + nscoord aWidth) = 0; + virtual void DrawString(const PRUnichar *aString, PRUint32 aLength, + nscoord aX, nscoord aY, + nscoord aWidth) = 0; + virtual void DrawString(const nsString& aString, nscoord aX, nscoord aY, + nscoord aWidth) = 0; + + virtual void DrawImage(nsIImage *aImage, nscoord aX, nscoord aY) = 0; + virtual void DrawImage(nsIImage *aImage, nscoord aX, nscoord aY, + nscoord aWidth, nscoord aHeight) = 0; + virtual void DrawImage(nsIImage *aImage, const nsRect& aRect) = 0; + virtual void DrawImage(nsIImage *aImage, const nsRect& aSRect, const nsRect& aDRect)=0; + + virtual nsresult CopyOffScreenBits(nsRect &aBounds) = 0; +}; + +//modifiers for text rendering + +#define NS_DRAWSTRING_NORMAL 0x0 +#define NS_DRAWSTRING_UNDERLINE 0x1 +#define NS_DRAWSTRING_OVERLINE 0x2 +#define NS_DRAWSTRING_LINE_THROUGH 0x4 + +#endif /* nsIRenderingContext_h___ */ diff --git a/mozilla/gfx/src/nsImage.h b/mozilla/gfx/src/nsImage.h new file mode 100644 index 00000000000..f104ef58de4 --- /dev/null +++ b/mozilla/gfx/src/nsImage.h @@ -0,0 +1,87 @@ +/* -*- 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. + */ + +#ifndef nsImage_h___ +#define nsImage_h___ + +#include "nsIImage.h" + +class nsImage : public nsIImage +{ + + public: + + private: + PRInt8 mNumBytesColor; // number of bytes per color + PRInt16 mNumPalleteColors; // either 8 or 0 + PRInt32 mSizeImage; // number of bits, not BITYMAPINFOHEADER + PRInt32 mRowBytes; // number of bytes per row + PRUint8 *mColorTable; // color table for the bitmap + LPBYTE mImageBits; // starting address of DIB bits + LPBYTE mAlphaBits; // alpha layer if we made one + PRBool mIsOptimized; // Have we turned our DIB into a GDI? + nsColorMap *mColorMap; // Redundant with mColorTable, but necessary + // for Set/GetColorMap + +#ifdef XP_PC + HPALETTE mHPalette; + HBITMAP mHBitmap; // the GDI bitmap + LPBITMAPINFOHEADER mBHead; // BITMAPINFOHEADER +#endif + +public: + nsImage(); + ~nsImage(); + + +#ifdef XP_PC + virtual BOOL Draw(void *aDrawPort,PRInt32 aX,PRInt32 aY,PRInt32 aWidth,PRInt32 aHeight); // until we implement CreateDibSection + virtual PRInt32 GetHeight() { return mBHead->biHeight;} + int GetSizeHeader(){return sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD) * mNumPalleteColors;} + virtual PRInt32 GetWidth() { return mBHead->biWidth;} + BOOL SetSystemPalette(HDC* aHdc); + UINT UsePalette(HDC* aHdc, BOOL bBackground = FALSE); +#endif + + void CleanUp(); + virtual PRUint8* GetAlphaBits(){return mAlphaBits;} + virtual PRInt32 GetAlphaLineStride() {return mBHead->biWidth;} + virtual PRUint8* GetBits() {return mImageBits;} + virtual PRInt32 GetLineStride() {return mRowBytes;} + int GetSizeImage() {return mSizeImage;} + virtual void Init(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth,nsMaskRequirements aMaskRequirements); + virtual PRBool IsOptimized() { return mIsOptimized;} + BOOL MakePalette(); + virtual nsresult Optimize(void *aDrawPort); + void TestFillBits(); + + // methods not complete + virtual nsColorMap* GetColorMap(); + virtual void ImageUpdated(PRUint8 aFlags, nsRect *aUpdateRect); + + NS_DECL_ISUPPORTS + +private: +#ifdef XP_PC + void ComputePaletteSize(int aBitCount); + void ComputeMetrics(); +#endif + +}; + +#endif diff --git a/mozilla/gfx/src/nsImageGroup.cpp b/mozilla/gfx/src/nsImageGroup.cpp new file mode 100644 index 00000000000..329de96a39f --- /dev/null +++ b/mozilla/gfx/src/nsImageGroup.cpp @@ -0,0 +1,293 @@ +/* -*- 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 "nsIImageGroup.h" +#include "nsIImageManager.h" +#include "nsIImageObserver.h" +#include "nsIImageRequest.h" +#include "nsImageRequest.h" +#include "ilIImageRenderer.h" +#include "nsImageNet.h" +#include "nsVoidArray.h" +#include "nsIRenderingContext.h" +#include "nsCRT.h" +#include "libimg.h" +#include "il_util.h" + +static NS_DEFINE_IID(kIImageGroupIID, NS_IIMAGEGROUP_IID); + +static void ns_observer_proc (XP_Observable aSource, + XP_ObservableMsg aMsg, + void* aMsgData, + void* aClosure); + +class ImageGroupImpl : public nsIImageGroup +{ +public: + ImageGroupImpl(nsIImageManager *aManager); + ~ImageGroupImpl(); + + nsresult Init(nsIRenderingContext *aRenderingContext); + + void* operator new(size_t sz) { + void* rv = new char[sz]; + nsCRT::zero(rv, sz); + return rv; + } + + NS_DECL_ISUPPORTS + + virtual PRBool AddObserver(nsIImageGroupObserver *aObserver); + virtual PRBool RemoveObserver(nsIImageGroupObserver *aObserver); + + virtual nsIImageRequest* GetImage(const char* aUrl, + nsIImageRequestObserver *aObserver, + nscolor aBackgroundColor, + PRUint32 aWidth, PRUint32 aHeight, + PRUint32 aFlags); + + virtual void Interrupt(void); + + IL_GroupContext *GetGroupContext() { return mGroupContext; } + nsVoidArray *GetObservers() { return mObservers; } + +private: + nsIImageManager *mManager; + IL_GroupContext *mGroupContext; + nsVoidArray *mObservers; + nsIRenderingContext *mRenderingContext; + IL_ColorSpace *mColorSpace; +}; + +ImageGroupImpl::ImageGroupImpl(nsIImageManager *aManager) +{ + NS_INIT_REFCNT(); + mManager = aManager; +} + +ImageGroupImpl::~ImageGroupImpl() +{ + if (mRenderingContext != nsnull) { + NS_RELEASE(mRenderingContext); + } + + if (mObservers != nsnull) { + PRInt32 i, count = mObservers->Count(); + nsIImageGroupObserver *observer; + for (i = 0; i < count; i++) { + observer = (nsIImageGroupObserver *)mObservers->ElementAt(i); + if (observer != nsnull) { + NS_RELEASE(observer); + } + } + + delete mObservers; + } + + if (mGroupContext != nsnull) { + IL_DestroyGroupContext(mGroupContext); + } + + if (mColorSpace != nsnull) { + IL_ReleaseColorSpace(mColorSpace); + } + + if (mManager != nsnull) { + NS_RELEASE(mManager); + } +} + +NS_IMPL_ISUPPORTS(ImageGroupImpl, kIImageGroupIID) + +nsresult +ImageGroupImpl::Init(nsIRenderingContext *aRenderingContext) +{ + ilIImageRenderer *renderer; + nsresult result; + + if ((result = NS_NewImageRenderer(&renderer)) != NS_OK) { + return result; + } + + // XXX Need to create an image renderer + mGroupContext = IL_NewGroupContext((void *)aRenderingContext, + renderer); + + if (mGroupContext == nsnull) { + return NS_ERROR_OUT_OF_MEMORY; + } + + mRenderingContext = aRenderingContext; + NS_ADDREF(mRenderingContext); + + // XXX Hard coded to be 24-bit. We need to get the right information + // from the rendering context (or device context). + IL_RGBBits colorRGBBits; + + colorRGBBits.red_shift = 16; + colorRGBBits.red_bits = 8; + colorRGBBits.green_shift = 8; + colorRGBBits.green_bits = 8; + colorRGBBits.blue_shift = 0; + colorRGBBits.blue_bits = 8; + mColorSpace = IL_CreateTrueColorSpace(&colorRGBBits, 24); + IL_AddRefToColorSpace(mColorSpace); + + IL_DisplayData displayData; + displayData.dither_mode = IL_Auto; + displayData.color_space = mColorSpace; + displayData.progressive_display = PR_TRUE; + IL_SetDisplayMode(mGroupContext, + IL_COLOR_SPACE | IL_PROGRESSIVE_DISPLAY | IL_DITHER_MODE, + &displayData); + + return NS_OK; +} + +PRBool +ImageGroupImpl::AddObserver(nsIImageGroupObserver *aObserver) +{ + if (aObserver == nsnull) { + return PR_FALSE; + } + + if (mObservers == nsnull) { + mObservers = new nsVoidArray(); + if (mObservers == nsnull) { + return PR_FALSE; + } + IL_AddGroupObserver(mGroupContext, ns_observer_proc, (void *)this); + } + + NS_ADDREF(aObserver); + mObservers->AppendElement((void *)aObserver); + + return PR_TRUE; +} + +PRBool +ImageGroupImpl::RemoveObserver(nsIImageGroupObserver *aObserver) +{ + PRBool ret; + + if (aObserver == nsnull || mObservers == nsnull) { + return PR_FALSE; + } + + ret = mObservers->RemoveElement((void *)aObserver); + + if (ret == PR_TRUE) { + NS_RELEASE(aObserver); + } + + return ret; +} + +nsIImageRequest* +ImageGroupImpl::GetImage(const char* aUrl, + nsIImageRequestObserver *aObserver, + nscolor aBackgroundColor, + PRUint32 aWidth, PRUint32 aHeight, + PRUint32 aFlags) +{ + NS_PRECONDITION(nsnull != aUrl, "null URL"); + + ImageRequestImpl *image_req = new ImageRequestImpl(); + if (image_req != nsnull) { + if (image_req->Init(mGroupContext, aUrl, aObserver, aBackgroundColor, + aWidth, aHeight, aFlags) == NS_OK) { + NS_ADDREF(image_req); + } + else { + delete image_req; + image_req = nsnull; + } + } + + return image_req; +} + +void +ImageGroupImpl::Interrupt(void) +{ + if (mGroupContext != nsnull) { + IL_InterruptContext(mGroupContext); + } +} + +nsresult +NS_NewImageGroup(nsIImageGroup **aInstancePtrResult) +{ + nsresult result; + + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + + nsIImageManager *manager; + if ((result = NS_NewImageManager(&manager)) != NS_OK) { + return result; + } + + nsIImageGroup *group = new ImageGroupImpl(manager); + if (group == nsnull) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return group->QueryInterface(kIImageGroupIID, (void **) aInstancePtrResult); +} + + +static void ns_observer_proc (XP_Observable aSource, + XP_ObservableMsg aMsg, + void* aMsgData, + void* aClosure) +{ + ImageGroupImpl *image_group = (ImageGroupImpl *)aClosure; + nsVoidArray *observer_list = image_group->GetObservers(); + + if (observer_list != nsnull) { + PRInt32 i, count = observer_list->Count(); + nsIImageGroupObserver *observer; + for (i = 0; i < count; i++) { + observer = (nsIImageGroupObserver *)observer_list->ElementAt(i); + if (observer != nsnull) { + switch (aMsg) { + case IL_STARTED_LOADING: + observer->Notify(image_group, + nsImageGroupNotification_kStartedLoading); + break; + case IL_ABORTED_LOADING: + observer->Notify(image_group, + nsImageGroupNotification_kAbortedLoading); + case IL_FINISHED_LOADING: + observer->Notify(image_group, + nsImageGroupNotification_kFinishedLoading); + case IL_STARTED_LOOPING: + observer->Notify(image_group, + nsImageGroupNotification_kStartedLooping); + case IL_FINISHED_LOOPING: + observer->Notify(image_group, + nsImageGroupNotification_kFinishedLooping); + } + } + } + } +} + diff --git a/mozilla/gfx/src/nsImageManager.cpp b/mozilla/gfx/src/nsImageManager.cpp new file mode 100644 index 00000000000..28328cf7939 --- /dev/null +++ b/mozilla/gfx/src/nsImageManager.cpp @@ -0,0 +1,136 @@ +/* -*- 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 "nsIImageManager.h" +#include "libimg.h" +#include "il_strm.h" +#include "nsCRT.h" +#include "nsImageNet.h" + +static NS_DEFINE_IID(kIImageManagerIID, NS_IIMAGEMANAGER_IID); + +class ImageManagerImpl : public nsIImageManager { +public: + static ImageManagerImpl *sTheImageManager; + + ImageManagerImpl(); + ~ImageManagerImpl(); + + nsresult Init(); + + void* operator new(size_t sz) { + void* rv = new char[sz]; + nsCRT::zero(rv, sz); + return rv; + } + + NS_DECL_ISUPPORTS + + virtual void SetCacheSize(PRInt32 aCacheSize); + virtual PRInt32 GetCacheSize(void); + virtual PRInt32 ShrinkCache(void); + virtual nsImageType GetImageType(const char *buf, PRInt32 length); + +private: + ilISystemServices *mSS; +}; + +ImageManagerImpl* ImageManagerImpl::sTheImageManager = nsnull; + +ImageManagerImpl::ImageManagerImpl() +{ + NS_NewImageSystemServices(&mSS); + NS_ADDREF(mSS); + IL_Init(mSS); +} + +ImageManagerImpl::~ImageManagerImpl() +{ + IL_Shutdown(); + NS_RELEASE(mSS); +} + +NS_IMPL_ISUPPORTS(ImageManagerImpl, kIImageManagerIID) + +nsresult +ImageManagerImpl::Init() +{ + return NS_OK; +} + +void +ImageManagerImpl::SetCacheSize(PRInt32 aCacheSize) +{ + IL_SetCacheSize(aCacheSize); +} + +PRInt32 +ImageManagerImpl::GetCacheSize() +{ + return IL_GetCacheSize(); +} + +PRInt32 +ImageManagerImpl::ShrinkCache(void) +{ + return IL_ShrinkCache(); +} + +nsImageType +ImageManagerImpl::GetImageType(const char *buf, PRInt32 length) +{ + int ret; + + NS_PRECONDITION(nsnull != buf, "null ptr"); + ret = IL_Type(buf, length); + + switch(ret) { + case(IL_GIF): + return nsImageType_kGIF; + case(IL_XBM): + return nsImageType_kXBM; + case(IL_JPEG): + return nsImageType_kJPEG; + case(IL_PPM): + return nsImageType_kPPM; + case(IL_PNG): + return nsImageType_kPNG; + default: + return nsImageType_kUnknown; + } +} + +NS_GFX nsresult +NS_NewImageManager(nsIImageManager **aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + + if (ImageManagerImpl::sTheImageManager == nsnull) { + ImageManagerImpl::sTheImageManager = new ImageManagerImpl(); + } + + if (ImageManagerImpl::sTheImageManager == nsnull) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return ImageManagerImpl::sTheImageManager->QueryInterface(kIImageManagerIID, + (void **) aInstancePtrResult); +} diff --git a/mozilla/gfx/src/nsImageNet.h b/mozilla/gfx/src/nsImageNet.h new file mode 100644 index 00000000000..f2de7695ebb --- /dev/null +++ b/mozilla/gfx/src/nsImageNet.h @@ -0,0 +1,31 @@ +/* -*- 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 "ilINetContext.h" +#include "ilIURL.h" +#include "ilIImageRenderer.h" +#include "ilISystemServices.h" +#include "nscore.h" + +extern NS_GFX nsresult NS_NewImageNetContext(ilINetContext **aInstancePtrResult); +extern NS_GFX nsresult NS_NewImageURL(ilIURL **aInstancePtrResult, + const char *aURL); + +extern NS_GFX nsresult NS_NewImageRenderer(ilIImageRenderer **aInstancePtrResult); + +extern NS_GFX nsresult NS_NewImageSystemServices(ilISystemServices **aInstancePtrResult); diff --git a/mozilla/gfx/src/nsImageNetContext.cpp b/mozilla/gfx/src/nsImageNetContext.cpp new file mode 100644 index 00000000000..4029909378d --- /dev/null +++ b/mozilla/gfx/src/nsImageNetContext.cpp @@ -0,0 +1,350 @@ +/* -*- 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 "libimg.h" +#include "nsImageNet.h" +#include "ilINetContext.h" +#include "ilIURL.h" +#include "ilINetReader.h" +#include "nsIInputStream.h" +#include "nsIURL.h" +#include "nsITimer.h" +#include "nsVoidArray.h" +#include "prmem.h" +#include "plstr.h" +#include "il_strm.h" + +static NS_DEFINE_IID(kIImageNetContextIID, IL_INETCONTEXT_IID); +static NS_DEFINE_IID(kIURLIID, NS_IURL_IID); + +class ImageNetContextImpl : public ilINetContext { +public: + ImageNetContextImpl(NET_ReloadMethod aReloadPolicy); + ~ImageNetContextImpl(); + + NS_DECL_ISUPPORTS + + virtual ilINetContext* Clone(); + + virtual NET_ReloadMethod GetReloadPolicy(); + + virtual void AddReferer(ilIURL *aUrl); + + virtual void Interrupt(); + + virtual ilIURL* CreateURL(const char *aUrl, + NET_ReloadMethod aReloadMethod); + + virtual PRBool IsLocalFileURL(char *aAddress); + + virtual PRBool IsURLInMemCache(ilIURL *aUrl); + + virtual PRBool IsURLInDiskCache(ilIURL *aUrl); + + virtual int GetURL (ilIURL * aUrl, NET_ReloadMethod aLoadMethod, + ilINetReader *aReader); + + nsITimer *mTimer; + nsVoidArray *mRequests; + NET_ReloadMethod mReloadPolicy; +}; + +typedef struct { + ilIURL *mURL; + nsIInputStream *mStream; +} NetRequestStr; + +ImageNetContextImpl::ImageNetContextImpl(NET_ReloadMethod aReloadPolicy) +{ + NS_INIT_REFCNT(); + mTimer = nsnull; + mRequests = nsnull; + mReloadPolicy = aReloadPolicy; +} + +ImageNetContextImpl::~ImageNetContextImpl() +{ + if (mTimer != nsnull) { + mTimer->Cancel(); + NS_RELEASE(mTimer); + } + + if (mRequests != nsnull) { + int i, count = mRequests->Count(); + for (i=0; i < count; i++) { + NetRequestStr *req = (NetRequestStr *)mRequests->ElementAt(i); + + if (req->mURL != nsnull) { + NS_RELEASE(req->mURL); + } + + if (req->mStream != nsnull) { + NS_RELEASE(req->mStream); + } + + PR_DELETE(req); + } + delete mRequests; + } +} + +NS_IMPL_ISUPPORTS(ImageNetContextImpl, kIImageNetContextIID) + +ilINetContext* +ImageNetContextImpl::Clone() +{ + ilINetContext *cx; + + if (NS_NewImageNetContext(&cx) == NS_OK) { + return cx; + } + else { + return nsnull; + } +} + +NET_ReloadMethod +ImageNetContextImpl::GetReloadPolicy() +{ + return mReloadPolicy; +} + +void +ImageNetContextImpl::AddReferer(ilIURL *aUrl) +{ +} + +void +ImageNetContextImpl::Interrupt() +{ +} + +ilIURL* +ImageNetContextImpl::CreateURL(const char *aURL, + NET_ReloadMethod aReloadMethod) +{ + ilIURL *url; + + if (NS_NewImageURL(&url, aURL) == NS_OK) { + return url; + } + else { + return nsnull; + } +} + +PRBool +ImageNetContextImpl::IsLocalFileURL(char *aAddress) +{ + if (PL_strncasecmp(aAddress, "file:", 5) == 0) { + return PR_TRUE; + } + else { + return PR_FALSE; + } +} + +PRBool +ImageNetContextImpl::IsURLInMemCache(ilIURL *aUrl) +{ + return PR_FALSE; +} + +PRBool +ImageNetContextImpl::IsURLInDiskCache(ilIURL *aUrl) +{ + return PR_TRUE; +} + +#define IMAGE_BUF_SIZE 4096 + +void +LoadURLs (nsITimer *aTimer, void *aClosure) +{ + ImageNetContextImpl *cx = (ImageNetContextImpl *)aClosure; + + NS_RELEASE(aTimer); + cx->mTimer = nsnull; + + if (cx->mRequests) { + int i, count = cx->mRequests->Count(); + + char *buffer = (char *)PR_MALLOC(IMAGE_BUF_SIZE); + if (buffer == nsnull) { + return; + } + + for (i=0; i < count; i++) { + NetRequestStr *req = (NetRequestStr *)cx->mRequests->ElementAt(i); + ilIURL *ilurl = req->mURL; + PRInt32 status = 0; + PRBool reschedule = PR_FALSE; + + if (ilurl != nsnull) { + nsIURL *nsurl; + ilINetReader *reader = ilurl->GetReader(); + nsIInputStream *stream = nsnull; + + if (req->mStream != nsnull) { + stream = req->mStream; + } + else { + if (reader->StreamCreated(ilurl, IL_UNKNOWN) == PR_TRUE && + ilurl->QueryInterface(kIURLIID, (void **)&nsurl) == NS_OK) { + PRInt32 ec; + stream = nsurl->Open(&ec); + if (nsnull == stream) { + reader->StreamAbort(-1); + status = -1; + } + } + else { + reader->StreamAbort(-1); + status = -1; + } + } + + if (status == 0) { + PRInt32 err = 0, nb; + PRBool first = (PRBool)(req->mStream == nsnull); + do { + if (reader->WriteReady() <= 0) { + req->mStream = stream; + reschedule = PR_TRUE; + break; + } + err = 0; + nb = stream->Read(&err, buffer, 0, + IMAGE_BUF_SIZE); + if (err != 0 && err != NS_INPUTSTREAM_EOF) { + break; + } + if (first == PR_TRUE) { + PRInt32 ilErr; + + ilErr = reader->FirstWrite((const unsigned char *)buffer, nb); + first = PR_FALSE; + /* + * If FirstWrite(...) fails then the image type + * cannot be determined and the il_container + * stream functions have not been initialized! + */ + if (ilErr != 0) { + break; + } + } + + reader->Write((const unsigned char *)buffer, nb); + } while (err != NS_INPUTSTREAM_EOF); + + if (err == NS_INPUTSTREAM_EOF) { + reader->StreamComplete(PR_FALSE); + } + else if (err != 0) { + reader->StreamAbort(-1); + status = -1; + } + } + + if (!reschedule) { + if (stream != nsnull) { + NS_RELEASE(stream); + } + req->mStream = nsnull; + reader->NetRequestDone(ilurl, status); + NS_RELEASE(reader); + NS_RELEASE(ilurl); + } + } + } + + for (i=count-1; i >= 0; i--) { + NetRequestStr *req = (NetRequestStr *)cx->mRequests->ElementAt(i); + + if (req->mStream == nsnull) { + cx->mRequests->RemoveElementAt(i); + PR_DELETE(req); + } + else if (cx->mTimer == nsnull) { + if (NS_NewTimer(&cx->mTimer) == NS_OK) { + cx->mTimer->Init(LoadURLs, (void *)cx, 0); + } + } + } + + PR_FREEIF(buffer); + } +} + +int +ImageNetContextImpl::GetURL (ilIURL * aURL, + NET_ReloadMethod aLoadMethod, + ilINetReader *aReader) +{ + NS_PRECONDITION(nsnull != aURL, "null URL"); + NS_PRECONDITION(nsnull != aReader, "null reader"); + if (aURL == nsnull || aReader == nsnull) { + return -1; + } + + if (mRequests == nsnull) { + mRequests = new nsVoidArray(); + if (mRequests == nsnull) { + // XXX Should still call exit function + return -1; + } + } + + if (mTimer == nsnull) { + if (NS_NewTimer(&mTimer) != NS_OK) { + // XXX Should still call exit function + return -1; + } + + if (mTimer->Init(LoadURLs, (void *)this, 0) != NS_OK) { + // XXX Should still call exit function + return -1; + } + } + + aURL->SetReader(aReader); + + NetRequestStr *req = PR_NEWZAP(NetRequestStr); + req->mURL = aURL; + NS_ADDREF(aURL); + + mRequests->AppendElement((void *)req); + + return 0; +} + +nsresult +NS_NewImageNetContext(ilINetContext **aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + + ilINetContext *cx = new ImageNetContextImpl(NET_NORMAL_RELOAD); + if (cx == nsnull) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return cx->QueryInterface(kIImageNetContextIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/gfx/src/nsImageRenderer.cpp b/mozilla/gfx/src/nsImageRenderer.cpp new file mode 100644 index 00000000000..77d209ff2e5 --- /dev/null +++ b/mozilla/gfx/src/nsImageRenderer.cpp @@ -0,0 +1,269 @@ +/* -*- 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 "libimg.h" +#include "ilIImageRenderer.h" +#include "nsIImage.h" +#include "nsIRenderingContext.h" +#include "ni_pixmp.h" +#include "il_util.h" +#include "nsGfxCIID.h" + +static NS_DEFINE_IID(kIImageRendererIID, IL_IIMAGERENDERER_IID); + +class ImageRendererImpl : public ilIImageRenderer { +public: + static IL_ColorSpace *sPseudoColorSpace; + + ImageRendererImpl(); + ~ImageRendererImpl(); + + NS_DECL_ISUPPORTS + + virtual void NewPixmap(void* aDisplayContext, + PRInt32 aWidth, PRInt32 aHeight, + IL_Pixmap* aImage, IL_Pixmap* aMask); + + virtual void UpdatePixmap(void* aDisplayContext, + IL_Pixmap* aImage, + PRInt32 aXOffset, PRInt32 aYOffset, + PRInt32 aWidth, PRInt32 aHeight); + + virtual void ControlPixmapBits(void* aDisplayContext, + IL_Pixmap* aImage, PRUint32 aControlMsg); + + virtual void DestroyPixmap(void* aDisplayContext, IL_Pixmap* aImage); + + virtual void DisplayPixmap(void* aDisplayContext, + IL_Pixmap* aImage, IL_Pixmap* aMask, + PRInt32 aX, PRInt32 aY, + PRInt32 aXOffset, PRInt32 aYOffset, + PRInt32 aWidth, PRInt32 aHeight); + + virtual void DisplayIcon(void* aDisplayContext, + PRInt32 aX, PRInt32 aY, PRUint32 aIconNumber); + + virtual void GetIconDimensions(void* aDisplayContext, + PRInt32 *aWidthPtr, PRInt32 *aHeightPtr, + PRUint32 aIconNumber); +}; + +IL_ColorSpace *ImageRendererImpl::sPseudoColorSpace = nsnull; + +ImageRendererImpl::ImageRendererImpl() +{ + NS_INIT_REFCNT(); +} + +ImageRendererImpl::~ImageRendererImpl() +{ +} + +NS_IMPL_ISUPPORTS(ImageRendererImpl, kIImageRendererIID) + + +void +ImageRendererImpl::NewPixmap(void* aDisplayContext, + PRInt32 aWidth, PRInt32 aHeight, + IL_Pixmap* aImage, IL_Pixmap* aMask) +{ + nsIRenderingContext *rc = (nsIRenderingContext *)aDisplayContext; + nsIImage *img; + nsresult rv; + + static NS_DEFINE_IID(kImageCID, NS_IMAGE_CID); + static NS_DEFINE_IID(kImageIID, NS_IIMAGE_IID); + + rv = NSRepository::CreateInstance(kImageCID, nsnull, kImageIID, (void **)&img); + + if (NS_OK != rv) + return; + + PRInt32 depth; + if (aImage->header.color_space->pixmap_depth == 8) { + depth = 8; + } + else { + depth = 24; + } + + img->Init(aWidth, aHeight, depth, + (aMask == nsnull) ? nsMaskRequirements_kNoMask : + nsMaskRequirements_kNeeds1Bit); + + aImage->bits = img->GetBits(); + aImage->client_data = img; + NS_ADDREF(img); + aImage->header.width = aWidth; + aImage->header.height = aHeight; + aImage->header.widthBytes = img->GetLineStride(); + + if (aMask) { + aMask->bits = img->GetAlphaBits(); + aMask->client_data = img; + aMask->header.width = aWidth; + aMask->header.height = aHeight; + } + + if (aImage->header.color_space->pixmap_depth == 8) { + IL_ColorMap *cmap; + if (sPseudoColorSpace == nsnull) { + cmap = IL_NewCubeColorMap(nsnull, 0, 216); + + if (cmap != nsnull) { + sPseudoColorSpace = IL_CreatePseudoColorSpace(cmap, 8, 8); + + if (sPseudoColorSpace == nsnull) { + IL_DestroyColorMap(cmap); + + // XXX We should do something here + return; + } + } + else { + // XXX We should do something here + return; + } + } + IL_AddRefToColorSpace(sPseudoColorSpace); + IL_ReleaseColorSpace(aImage->header.color_space); + aImage->header.color_space = sPseudoColorSpace; + + cmap = &sPseudoColorSpace->cmap; + nsColorMap *nscmap = img->GetColorMap(); + PRUint8 *mapptr = nscmap->Index; + int i; + + for (i=0; i < cmap->num_colors; i++) { + *mapptr++ = cmap->map[i].red; + *mapptr++ = cmap->map[i].green; + *mapptr++ = cmap->map[i].blue; + } + img->ImageUpdated(nsImageUpdateFlags_kColorMapChanged, nsnull); + + if (aImage->header.transparent_pixel) { + PRUint8 red, green, blue; + PRUint8 *lookup_table = (PRUint8 *)aImage->header.color_space->cmap.table; + red = aImage->header.transparent_pixel->red; + green = aImage->header.transparent_pixel->green; + blue = aImage->header.transparent_pixel->blue; + aImage->header.transparent_pixel->index = + lookup_table[((red >> 3) << 10) | + ((green >> 3) << 5) | + (blue >> 3)]; + } + } + else { + IL_RGBBits colorRGBBits; + IL_ColorSpace *colorSpace; + + colorRGBBits.red_shift = 16; + colorRGBBits.red_bits = 8; + colorRGBBits.green_shift = 8; + colorRGBBits.green_bits = 8; + colorRGBBits.blue_shift = 0; + colorRGBBits.blue_bits = 8; + colorSpace = IL_CreateTrueColorSpace(&colorRGBBits, 24); + IL_AddRefToColorSpace(colorSpace); + IL_ReleaseColorSpace(aImage->header.color_space); + aImage->header.color_space = colorSpace; + } +} + +void +ImageRendererImpl::UpdatePixmap(void* aDisplayContext, + IL_Pixmap* aImage, + PRInt32 aXOffset, PRInt32 aYOffset, + PRInt32 aWidth, PRInt32 aHeight) +{ + nsIRenderingContext *rc = (nsIRenderingContext *)aDisplayContext; + nsIImage *img = (nsIImage *)aImage->client_data; + + // XXX The nsIImage interface has an ImageUpdated method that + // has been commented out. +} + +void +ImageRendererImpl::ControlPixmapBits(void* aDisplayContext, + IL_Pixmap* aImage, PRUint32 aControlMsg) +{ + nsIRenderingContext *rc = (nsIRenderingContext *)aDisplayContext; + nsIImage *img = (nsIImage *)aImage->client_data; + + if (aControlMsg == IL_RELEASE_BITS) { + img->Optimize(0); + } +} + +void +ImageRendererImpl::DestroyPixmap(void* aDisplayContext, IL_Pixmap* aImage) +{ + nsIRenderingContext *rc = (nsIRenderingContext *)aDisplayContext; + nsIImage *img = (nsIImage *)aImage->client_data; + + aImage->client_data = nsnull; + if (img) { + NS_RELEASE(img); + } +} + +void +ImageRendererImpl::DisplayPixmap(void* aDisplayContext, + IL_Pixmap* aImage, IL_Pixmap* aMask, + PRInt32 aX, PRInt32 aY, + PRInt32 aXOffset, PRInt32 aYOffset, + PRInt32 aWidth, PRInt32 aHeight) +{ + nsIRenderingContext *rc = (nsIRenderingContext *)aDisplayContext; + nsIImage *img = (nsIImage *)aImage->client_data; + + // XXX Need better version of DrawImage + rc->DrawImage(img, aX, aY); +} + +void +ImageRendererImpl::DisplayIcon(void* aDisplayContext, + PRInt32 aX, PRInt32 aY, PRUint32 aIconNumber) +{ + nsIRenderingContext *rc = (nsIRenderingContext *)aDisplayContext; +} + +void +ImageRendererImpl::GetIconDimensions(void* aDisplayContext, + PRInt32 *aWidthPtr, PRInt32 *aHeightPtr, + PRUint32 aIconNumber) +{ + nsIRenderingContext *rc = (nsIRenderingContext *)aDisplayContext; +} + +nsresult +NS_NewImageRenderer(ilIImageRenderer **aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + + ilIImageRenderer *renderer = new ImageRendererImpl(); + if (renderer == nsnull) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return renderer->QueryInterface(kIImageRendererIID, + (void **) aInstancePtrResult); +} diff --git a/mozilla/gfx/src/nsImageRequest.cpp b/mozilla/gfx/src/nsImageRequest.cpp new file mode 100644 index 00000000000..23dbd0f5757 --- /dev/null +++ b/mozilla/gfx/src/nsImageRequest.cpp @@ -0,0 +1,326 @@ +/* -*- 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 "nsImageRequest.h" +#include "nsIImageGroup.h" +#include "nsIImageObserver.h" +#include "nsIImage.h" +#include "nsVoidArray.h" +#include "nsRect.h" +#include "ilINetContext.h" +#include "nsImageNet.h" + +static NS_DEFINE_IID(kIImageRequestIID, NS_IIMAGEREQUEST_IID); + +static void ns_observer_proc (XP_Observable aSource, + XP_ObservableMsg aMsg, + void* aMsgData, + void* aClosure); + +ImageRequestImpl::ImageRequestImpl() +{ +} + +ImageRequestImpl::~ImageRequestImpl() +{ + // Observer list destroyed by the image library +} + +nsresult +ImageRequestImpl::Init(IL_GroupContext *aGroupContext, + const char* aUrl, + nsIImageRequestObserver *aObserver, + nscolor aBackgroundColor, + PRUint32 aWidth, PRUint32 aHeight, + PRUint32 aFlags) +{ + NS_PRECONDITION(nsnull != aGroupContext, "null group context"); + NS_PRECONDITION(nsnull != aUrl, "null URL"); + + NS_Error status; + IL_IRGB bgcolor; + PRUint32 flags; + nsresult result; + + mGroupContext = aGroupContext; + + if (AddObserver(aObserver) == PR_FALSE) { + return NS_ERROR_OUT_OF_MEMORY; + } + + status = XP_NewObserverList(NULL, &mXPObserver); + if (status < 0) { + return NS_ERROR_OUT_OF_MEMORY; + } + + status = XP_AddObserver(mXPObserver, ns_observer_proc, (void *)this); + if (status < 0) { + XP_DisposeObserverList(mXPObserver); + mXPObserver = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + + bgcolor.red = NS_GET_R(aBackgroundColor); + bgcolor.green = NS_GET_G(aBackgroundColor); + bgcolor.blue = NS_GET_B(aBackgroundColor); + + flags = ((aFlags & IL_HIGH_PRIORITY) ? nsImageLoadFlags_kHighPriority : 0) | + ((aFlags & IL_STICKY) ? nsImageLoadFlags_kSticky : 0) | + ((aFlags & IL_BYPASS_CACHE) ? nsImageLoadFlags_kBypassCache : 0) | + ((aFlags & IL_ONLY_FROM_CACHE) ? nsImageLoadFlags_kOnlyFromCache : 0); + + ilINetContext *net_cx; + + if ((result = NS_NewImageNetContext(&net_cx)) != NS_OK) { + XP_DisposeObserverList(mXPObserver); + mXPObserver = nsnull; + return result; + } + + mImageReq = IL_GetImage(aUrl, aGroupContext, mXPObserver, &bgcolor, + aWidth, aHeight, flags, (void *)net_cx); + + if (mImageReq == nsnull) { + XP_DisposeObserverList(mXPObserver); + mXPObserver = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + + return NS_OK; +} + +NS_IMPL_ADDREF(ImageRequestImpl) +NS_IMPL_QUERY_INTERFACE(ImageRequestImpl, kIImageRequestIID) + +nsrefcnt ImageRequestImpl::Release(void) +{ + if (--mRefCnt == 0) { + IL_DestroyImage(mImageReq); + delete this; + return 0; + } + return mRefCnt; +} + +nsIImage* +ImageRequestImpl::GetImage() +{ + if (mImageReq != nsnull) { + IL_Pixmap *pixmap = IL_GetImagePixmap(mImageReq); + + if (pixmap != nsnull) { + nsIImage *image = (nsIImage *)pixmap->client_data; + + if (image != nsnull) { + NS_ADDREF(image); + return image; + } + } + } + + return nsnull; +} + +void +ImageRequestImpl::GetNaturalDimensions(PRUint32 *aWidth, PRUint32 *aHeight) +{ + if (mImageReq != nsnull) { + IL_GetNaturalDimensions(mImageReq, (int *)aWidth, (int *)aHeight); + } + else { + *aWidth = 0; + *aHeight = 0; + } +} + +PRBool +ImageRequestImpl::AddObserver(nsIImageRequestObserver *aObserver) +{ + if (aObserver == nsnull) { + return PR_FALSE; + } + + if (mObservers == nsnull) { + mObservers = new nsVoidArray(); + if (mObservers == nsnull) { + return PR_FALSE; + } + } + + NS_ADDREF(aObserver); + mObservers->AppendElement((void *)aObserver); + + return PR_TRUE; +} + +PRBool +ImageRequestImpl::RemoveObserver(nsIImageRequestObserver *aObserver) +{ + PRBool ret; + + if (aObserver == nsnull || mObservers == nsnull) { + return PR_FALSE; + } + + ret = mObservers->RemoveElement((void *)aObserver); + + if (ret == PR_TRUE) { + NS_RELEASE(aObserver); + } + + return ret; +} + +void +ImageRequestImpl::Interrupt() +{ + if (mImageReq != nsnull) { + IL_InterruptRequest(mImageReq); + } +} + + +static void ns_observer_proc (XP_Observable aSource, + XP_ObservableMsg aMsg, + void* aMsgData, + void* aClosure) +{ + ImageRequestImpl *image_request = (ImageRequestImpl *)aClosure; + IL_MessageData *message_data = (IL_MessageData *)aMsgData; + nsVoidArray *observer_list = image_request->GetObservers(); + nsIImage *image = nsnull; + // IL_ImageReq *il_image_req = image_request->GetImageRequest(); + IL_ImageReq *il_image_req = (IL_ImageReq *)aSource; + + if (il_image_req != nsnull) { + IL_Pixmap *pixmap = IL_GetImagePixmap(il_image_req); + + if (pixmap != nsnull) { + image = (nsIImage *)pixmap->client_data; + } + } + + if (observer_list != nsnull) { + PRInt32 i, count = observer_list->Count(); + nsIImageRequestObserver *observer; + for (i = 0; i < count; i++) { + observer = (nsIImageRequestObserver *)observer_list->ElementAt(i); + if (observer != nsnull) { + switch (aMsg) { + case IL_START_URL: + observer->Notify(image_request, + image, nsImageNotification_kStartURL, 0, 0, + nsnull); + break; + case IL_DESCRIPTION: + observer->Notify(image_request, + image, nsImageNotification_kDescription, 0, 0, + message_data->description); + break; + case IL_DIMENSIONS: + observer->Notify(image_request, + image, nsImageNotification_kDimensions, + (PRInt32)message_data->width, + (PRInt32)message_data->height, + nsnull); + break; + case IL_IS_TRANSPARENT: + observer->Notify(image_request, + image, nsImageNotification_kIsTransparent, 0, 0, + nsnull); + break; + case IL_PIXMAP_UPDATE: + { + nsRect rect(message_data->update_rect.x_origin, + message_data->update_rect.y_origin, + message_data->update_rect.width, + message_data->update_rect.height); + + observer->Notify(image_request, + image, nsImageNotification_kPixmapUpdate, 0, 0, + &rect); + } + break; + case IL_FRAME_COMPLETE: + observer->Notify(image_request, + image, nsImageNotification_kFrameComplete, 0, 0, + nsnull); + break; + case IL_PROGRESS: + observer->Notify(image_request, + image, nsImageNotification_kProgress, + message_data->percent_progress, 0, + nsnull); + break; + case IL_IMAGE_COMPLETE: + observer->Notify(image_request, + image, nsImageNotification_kImageComplete, 0, 0, + nsnull); + break; + case IL_STOP_URL: + observer->Notify(image_request, + image, nsImageNotification_kStopURL, 0, 0, + nsnull); + break; + case IL_IMAGE_DESTROYED: + image_request->SetImageRequest(nsnull); + observer->Notify(image_request, + image, nsImageNotification_kImageDestroyed, 0, 0, + nsnull); + break; + case IL_ABORTED: + observer->Notify(image_request, + image, nsImageNotification_kAborted, 0, 0, + nsnull); + break; + case IL_INTERNAL_IMAGE: + observer->Notify(image_request, + image, nsImageNotification_kInternalImage, 0, 0, + nsnull); + break; + case IL_NOT_IN_CACHE: + observer->NotifyError(image_request, + nsImageError_kNotInCache); + break; + case IL_ERROR_NO_DATA: + observer->NotifyError(image_request, + nsImageError_kNoData); + break; + case IL_ERROR_IMAGE_DATA_CORRUPT: + observer->NotifyError(image_request, + nsImageError_kImageDataCorrupt); + break; + case IL_ERROR_IMAGE_DATA_TRUNCATED: + observer->NotifyError(image_request, + nsImageError_kImageDataTruncated); + break; + case IL_ERROR_IMAGE_DATA_ILLEGAL: + observer->NotifyError(image_request, + nsImageError_kImageDataIllegal); + break; + case IL_ERROR_INTERNAL: + observer->NotifyError(image_request, + nsImageError_kInternalError); + break; + } + } + } + } +} + + diff --git a/mozilla/gfx/src/nsImageRequest.h b/mozilla/gfx/src/nsImageRequest.h new file mode 100644 index 00000000000..e93ea26684f --- /dev/null +++ b/mozilla/gfx/src/nsImageRequest.h @@ -0,0 +1,74 @@ +/* -*- 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. + */ + +#ifndef nsImageRequest_h___ +#define nsImageRequest_h___ + +#include "nsIImageRequest.h" +#include "libimg.h" +#include "nsCRT.h" +#include "nsColor.h" + +class nsVoidArray; +class nsIImageRequestObserver; + +class ImageRequestImpl : public nsIImageRequest { +public: + ImageRequestImpl(); + ~ImageRequestImpl(); + + nsresult Init(IL_GroupContext *aGroupContext, const char* aUrl, + nsIImageRequestObserver *aObserver, + nscolor aBackgroundColor, + PRUint32 aWidth, PRUint32 aHeight, + PRUint32 aFlags); + + void* operator new(size_t sz) { + void* rv = new char[sz]; + nsCRT::zero(rv, sz); + return rv; + } + + NS_DECL_ISUPPORTS + + // Get the image associated with the request. + virtual nsIImage* GetImage(); + + // Return the natural dimensions of the image. Returns 0,0 + //if the dimensions are unknown. + virtual void GetNaturalDimensions(PRUint32 *aWidth, PRUint32 *aHeight); + + // Add and remove observers to listen in on image loading notifications + virtual PRBool AddObserver(nsIImageRequestObserver *aObserver); + virtual PRBool RemoveObserver(nsIImageRequestObserver *aObserver); + + // Interrupt loading of just this image. + virtual void Interrupt(); + + IL_ImageReq *GetImageRequest() { return mImageReq; } + void SetImageRequest(IL_ImageReq *aImageReq) { mImageReq = aImageReq; } + nsVoidArray *GetObservers() { return mObservers; } + +private: + IL_ImageReq *mImageReq; + IL_GroupContext *mGroupContext; + nsVoidArray *mObservers; + XP_ObserverList mXPObserver; +}; + +#endif diff --git a/mozilla/gfx/src/nsImageSystemServices.cpp b/mozilla/gfx/src/nsImageSystemServices.cpp new file mode 100644 index 00000000000..ff3b7dc19e7 --- /dev/null +++ b/mozilla/gfx/src/nsImageSystemServices.cpp @@ -0,0 +1,134 @@ +/* -*- 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 "ilISystemServices.h" +#include "nsITimer.h" +#include "prtypes.h" +#include "prmem.h" +#include "nsCRT.h" + +static NS_DEFINE_IID(kISystemServicesIID, IL_ISYSTEMSERVICES_IID); + +class ImageSystemServicesImpl : public ilISystemServices { +public: + static ImageSystemServicesImpl *sSS; + + ImageSystemServicesImpl(); + ~ImageSystemServicesImpl(); + + void* operator new(size_t sz) { + void* rv = new char[sz]; + nsCRT::zero(rv, sz); + return rv; + } + + NS_DECL_ISUPPORTS + + virtual void * SetTimeout(ilTimeoutCallbackFunction aFunc, + void * aClosure, PRUint32 aMsecs); + + virtual void ClearTimeout(void *aTimerID); +}; + +typedef struct { + ilTimeoutCallbackFunction mFunc; + void *mClosure; +} TimerClosure; + +ImageSystemServicesImpl* ImageSystemServicesImpl::sSS = nsnull; + +ImageSystemServicesImpl::ImageSystemServicesImpl() +{ +} + +ImageSystemServicesImpl::~ImageSystemServicesImpl() +{ +} + +NS_IMPL_ISUPPORTS(ImageSystemServicesImpl, kISystemServicesIID) + +void +timer_callback (nsITimer *aTimer, void *aClosure) +{ + TimerClosure *tc = (TimerClosure *)aClosure; + + (*tc->mFunc)(tc->mClosure); + + NS_RELEASE(aTimer); + PR_DELETE(tc); +} + +void * +ImageSystemServicesImpl::SetTimeout(ilTimeoutCallbackFunction aFunc, + void * aClosure, PRUint32 aMsecs) +{ + nsITimer *timer; + TimerClosure *tc; + + if (NS_NewTimer(&timer) != NS_OK) { + return nsnull; + } + + tc = (TimerClosure *)PR_NEWZAP(TimerClosure); + if (tc == nsnull) { + NS_RELEASE(timer); + return nsnull; + } + + tc->mFunc = aFunc; + tc->mClosure = aClosure; + + if (timer->Init(timer_callback, (void *)tc, aMsecs) != NS_OK) { + NS_RELEASE(timer); + PR_DELETE(tc); + return nsnull; + } + + NS_ADDREF(timer); + + return (void *)timer; +} + +void +ImageSystemServicesImpl::ClearTimeout(void *aTimerID) +{ + nsITimer *timer = (nsITimer *)aTimerID; + + timer->Cancel(); + NS_RELEASE(timer); +} + +nsresult +NS_NewImageSystemServices(ilISystemServices **aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + + if (ImageSystemServicesImpl::sSS == nsnull) { + ImageSystemServicesImpl::sSS = new ImageSystemServicesImpl(); + } + + if (ImageSystemServicesImpl::sSS == nsnull) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return ImageSystemServicesImpl::sSS->QueryInterface(kISystemServicesIID, + (void **) aInstancePtrResult); +} diff --git a/mozilla/gfx/src/nsImageURL.cpp b/mozilla/gfx/src/nsImageURL.cpp new file mode 100644 index 00000000000..26202593fe0 --- /dev/null +++ b/mozilla/gfx/src/nsImageURL.cpp @@ -0,0 +1,179 @@ +/* -*- 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 "libimg.h" +#include "nsImageNet.h" +#include "ilINetContext.h" +#include "ilINetReader.h" +#include "ilIURL.h" +#include "nsIURL.h" +#include "nsString.h" +#include "il_strm.h" + + +static NS_DEFINE_IID(kIImageURLIID, IL_IURL_IID); + +class ImageURLImpl : public ilIURL { +public: + ImageURLImpl(const char *aURL); + ~ImageURLImpl(); + + NS_DECL_ISUPPORTS + + virtual void SetReader(ilINetReader *aReader); + + virtual ilINetReader *GetReader(); + + virtual int GetContentLength(); + + virtual const char* GetAddress(); + + virtual time_t GetExpires(); + + virtual void SetBackgroundLoad(PRBool aBgload); + +private: + nsIURL *mURL; + ilINetReader *mReader; +}; + +ImageURLImpl::ImageURLImpl(const char *aURL) +{ + NS_INIT_REFCNT(); + NS_NewURL(&mURL, aURL); + mReader = nsnull; +} + +ImageURLImpl::~ImageURLImpl() +{ + if (mURL != nsnull) { + NS_RELEASE(mURL); + } + + if (mReader != nsnull) { + NS_RELEASE(mReader); + } +} + +nsresult +ImageURLImpl::QueryInterface(const nsIID& aIID, + void** aInstancePtr) +{ + if (NULL == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + static NS_DEFINE_IID(kClassIID, kIImageURLIID); + static NS_DEFINE_IID(kURLIID, NS_IURL_IID); + + if (aIID.Equals(kURLIID)) { + *aInstancePtr = (void*) mURL; + mURL->AddRef(); + return NS_OK; + } + if (aIID.Equals(kClassIID)) { + *aInstancePtr = (void*) this; + AddRef(); + return NS_OK; + } + if (aIID.Equals(kISupportsIID)) { + *aInstancePtr = (void*) ((nsISupports*)this); + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +NS_IMPL_ADDREF(ImageURLImpl) + +nsrefcnt ImageURLImpl::Release(void) +{ + if (--mRefCnt == 0) { + delete this; + return 0; + } + return mRefCnt; +} + +void +ImageURLImpl::SetReader(ilINetReader *aReader) +{ + if (mReader != nsnull) { + NS_RELEASE(mReader); + } + + mReader = aReader; + + if (mReader != nsnull) { + NS_ADDREF(mReader); + } +} + +ilINetReader * +ImageURLImpl::GetReader() +{ + if (mReader != nsnull) { + NS_ADDREF(mReader); + } + + return mReader; +} + +int +ImageURLImpl::GetContentLength() +{ + return 0; +} + +const char* +ImageURLImpl::GetAddress() +{ + if (mURL != nsnull) { + return mURL->GetSpec(); + } + else { + return nsnull; + } +} + +time_t +ImageURLImpl::GetExpires() +{ + return 0x7FFFFFFF; +} + +void +ImageURLImpl::SetBackgroundLoad(PRBool aBgload) +{ +} + +nsresult +NS_NewImageURL(ilIURL **aInstancePtrResult, const char *aURL) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + + ilIURL *url = new ImageURLImpl(aURL); + if (url == nsnull) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return url->QueryInterface(kIImageURLIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/gfx/src/nsMargin.h b/mozilla/gfx/src/nsMargin.h new file mode 100644 index 00000000000..2c519865004 --- /dev/null +++ b/mozilla/gfx/src/nsMargin.h @@ -0,0 +1,71 @@ +/* -*- 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. + */ + +#ifndef NSMARGIN_H +#define NSMARGIN_H + +#include "nsCoord.h" + +struct nsMargin { + nscoord left, top, right, bottom; + + // Constructors + nsMargin() {} + nsMargin(const nsMargin& aMargin) {*this = aMargin;} + nsMargin(nscoord aLeft, nscoord aTop, + nscoord aRight, nscoord aBottom) {left = aLeft; top = aTop; + right = aRight; bottom = aBottom;} + + void SizeTo(nscoord aLeft, nscoord aTop, + nscoord aRight, nscoord aBottom) {left = aLeft; top = aTop; + right = aRight; bottom = aBottom;} + void SizeBy(nscoord aLeft, nscoord aTop, + nscoord aRight, nscoord aBottom) {left += aLeft; top += aTop; + right += aRight; bottom += aBottom;} + + // Overloaded operators. Note that '=' isn't defined so we'll get the + // compiler generated default assignment operator + PRBool operator==(const nsMargin& aMargin) const { + return (PRBool) ((left == aMargin.left) && (top == aMargin.top) && + (right == aMargin.right) && (bottom == aMargin.bottom)); + } + PRBool operator!=(const nsMargin& aMargin) const { + return (PRBool) ((left != aMargin.left) || (top != aMargin.top) || + (right != aMargin.right) || (bottom != aMargin.bottom)); + } + nsMargin operator+(const nsMargin& aMargin) const { + return nsMargin(left + aMargin.left, top + aMargin.top, + right + aMargin.right, bottom + aMargin.bottom); + } + nsMargin operator-(const nsMargin& aMargin) const { + return nsMargin(left - aMargin.left, top - aMargin.top, + right - aMargin.right, bottom - aMargin.bottom); + } + nsMargin& operator+=(const nsMargin& aMargin) {left += aMargin.left; + top += aMargin.top; + right += aMargin.right; + bottom += aMargin.bottom; + return *this;} + nsMargin& operator-=(const nsMargin& aMargin) {left -= aMargin.left; + top -= aMargin.top; + right -= aMargin.right; + bottom -= aMargin.bottom; + return *this;} +}; + +#endif /* NSMARGIN_H */ diff --git a/mozilla/gfx/src/nsPoint.h b/mozilla/gfx/src/nsPoint.h new file mode 100644 index 00000000000..5aa2c1eb710 --- /dev/null +++ b/mozilla/gfx/src/nsPoint.h @@ -0,0 +1,61 @@ +/* -*- 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. + */ + +#ifndef NSPOINT_H +#define NSPOINT_H + +#include "nsCoord.h" + +struct nsPoint { + nscoord x, y; + + // Constructors + nsPoint() {} + nsPoint(const nsPoint& aPoint) {x = aPoint.x; y = aPoint.y;} + nsPoint(nscoord aX, nscoord aY) {x = aX; y = aY;} + + void MoveTo(nscoord aX, nscoord aY) {x = aX; y = aY;} + void MoveBy(nscoord aDx, nscoord aDy) {x += aDx; y += aDy;} + + // Overloaded operators. Note that '=' isn't defined so we'll get the + // compiler generated default assignment operator + PRBool operator==(const nsPoint& aPoint) const { + return (PRBool) ((x == aPoint.x) && (y == aPoint.y)); + } + PRBool operator!=(const nsPoint& aPoint) const { + return (PRBool) ((x != aPoint.x) || (y != aPoint.y)); + } + nsPoint operator+(const nsPoint& aPoint) const { + return nsPoint(x + aPoint.x, y + aPoint.y); + } + nsPoint operator-(const nsPoint& aPoint) const { + return nsPoint(x - aPoint.x, y - aPoint.y); + } + nsPoint& operator+=(const nsPoint& aPoint) { + x += aPoint.x; + y += aPoint.y; + return *this; + } + nsPoint& operator-=(const nsPoint& aPoint) { + x -= aPoint.x; + y -= aPoint.y; + return *this; + } +}; + +#endif /* NSPOINT_H */ diff --git a/mozilla/gfx/src/nsRect.cpp b/mozilla/gfx/src/nsRect.cpp new file mode 100644 index 00000000000..6c00a6da1dc --- /dev/null +++ b/mozilla/gfx/src/nsRect.cpp @@ -0,0 +1,169 @@ +/* -*- 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 "nsRect.h" +#include "nsString.h" +#include "nsUnitConversion.h" + +#define MIN(a,b)\ + ((a) < (b) ? (a) : (b)) +#define MAX(a,b)\ + ((a) > (b) ? (a) : (b)) + +// Containment +PRBool nsRect::Contains(nscoord aX, nscoord aY) const +{ + return (PRBool) ((aX >= x) && (aY >= y) && + (aX < XMost()) && (aY < YMost())); +} + +PRBool nsRect::Contains(const nsRect &aRect) const +{ + return (PRBool) ((aRect.x >= x) && (aRect.y >= y) && + (aRect.XMost() <= XMost()) && (aRect.YMost() <= YMost())); +} + +// Intersection. Returns TRUE if the receiver overlaps aRect and +// FALSE otherwise +PRBool nsRect::Intersects(const nsRect &aRect) const +{ + return (PRBool) ((x < aRect.XMost()) && (y < aRect.YMost()) && + (aRect.x < XMost()) && (aRect.y < YMost())); +} + +// Computes the area in which aRect1 and aRect2 overlap and fills 'this' with +// the result. Returns FALSE if the rectangles don't intersect. +PRBool nsRect::IntersectRect(const nsRect &aRect1, const nsRect &aRect2) +{ + nscoord xmost1 = aRect1.XMost(); + nscoord ymost1 = aRect1.YMost(); + nscoord xmost2 = aRect2.XMost(); + nscoord ymost2 = aRect2.YMost(); + nscoord temp; + + x = MAX(aRect1.x, aRect2.x); + y = MAX(aRect1.y, aRect2.y); + + // Compute the destination width + temp = MIN(xmost1, xmost2); + if (temp <= x) + return PR_FALSE; + width = temp - x; + + // Compute the destination height + temp = MIN(ymost1, ymost2); + if (temp <= y) + return PR_FALSE; + height = temp - y; + + return PR_TRUE; +} + +// Computes the smallest rectangle that contains both aRect1 and aRect2 and +// fills 'this' with the result. Returns FALSE if both aRect1 and aRect2 are +// empty and TRUE otherwise +PRBool nsRect::UnionRect(const nsRect &aRect1, const nsRect &aRect2) +{ + PRBool result = PR_TRUE; + + // Is aRect1 empty? + if (aRect1.IsEmpty()) { + if (aRect2.IsEmpty()) { + // Both rectangles are empty which is an error + Empty(); + result = PR_FALSE; + } else { + // aRect1 is empty so set the result to aRect2 + *this = aRect2; + } + } else if (aRect2.IsEmpty()) { + // aRect2 is empty so set the result to aRect1 + *this = aRect1; + } else { + nscoord xmost1 = aRect1.XMost(); + nscoord xmost2 = aRect2.XMost(); + nscoord ymost1 = aRect1.YMost(); + nscoord ymost2 = aRect2.YMost(); + + // Compute the origin + x = MIN(aRect1.x, aRect2.x); + y = MIN(aRect1.y, aRect2.y); + + // Compute the size + width = MAX(xmost1, xmost2) - x; + height = MAX(ymost1, ymost2) - y; + } + + return result; +} + +// Inflate the rect by the specified width and height +void nsRect::Inflate(nscoord aDx, nscoord aDy) +{ + x -= aDx; + y -= aDy; + width += 2 * aDx; + height += 2 * aDy; +} + +// Inflate the rect by the specified margin +void nsRect::Inflate(const nsMargin &aMargin) +{ + x -= aMargin.left; + y -= aMargin.top; + width += aMargin.left + aMargin.right; + height += aMargin.top + aMargin.bottom; +} + +// Deflate the rect by the specified width and height +void nsRect::Deflate(nscoord aDx, nscoord aDy) +{ + x += aDx; + y += aDy; + width -= 2 * aDx; + height -= 2 * aDy; +} + +// Deflate the rect by the specified margin +void nsRect::Deflate(const nsMargin &aMargin) +{ + x += aMargin.left; + y += aMargin.top; + width -= aMargin.left + aMargin.right; + height -= aMargin.top + aMargin.bottom; +} + +// Diagnostics + +FILE* operator<<(FILE* out, const nsRect& rect) +{ + nsAutoString tmp; + + // Output the coordinates in fractional points so they're easier to read + tmp.Append("{"); + tmp.Append(NS_TWIPS_TO_POINTS_FLOAT(rect.x)); + tmp.Append(", "); + tmp.Append(NS_TWIPS_TO_POINTS_FLOAT(rect.y)); + tmp.Append(", "); + tmp.Append(NS_TWIPS_TO_POINTS_FLOAT(rect.width)); + tmp.Append(", "); + tmp.Append(NS_TWIPS_TO_POINTS_FLOAT(rect.height)); + tmp.Append("}"); + fputs(tmp, out); + return out; +} diff --git a/mozilla/gfx/src/nsRect.h b/mozilla/gfx/src/nsRect.h new file mode 100644 index 00000000000..c9019467b13 --- /dev/null +++ b/mozilla/gfx/src/nsRect.h @@ -0,0 +1,126 @@ +/* -*- 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. + */ + + +#ifndef NSRECT_H +#define NSRECT_H + +#include +#include "nsCoord.h" +#include "nsPoint.h" +#include "nsSize.h" +#include "nsMargin.h" +#include "nsUnitConversion.h" + +struct NS_GFX nsRect { + nscoord x, y; + nscoord width, height; + + // Constructors + nsRect() {} + nsRect(const nsRect& aRect) {*this = aRect;} + nsRect(const nsPoint& aOrigin, const nsSize &aSize) {x = aOrigin.x; y = aOrigin.y; + width = aSize.width; height = aSize.height;} + nsRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) {x = aX; y = aY; + width = aWidth; height = aHeight;} + + // Emptiness. An empty rect is one that has no area, i.e. its width of height + // is <= 0 + PRBool IsEmpty() const { + return (PRBool) ((width <= 0) || (height <= 0)); + } + void Empty() {width = height = 0;} + + // Containment + PRBool Contains(const nsRect& aRect) const; + PRBool Contains(nscoord aX, nscoord aY) const; + PRBool Contains(const nsPoint& aPoint) const {return Contains(aPoint.x, aPoint.y);} + + // Intersection. Returns TRUE if the receiver overlaps aRect and + // FALSE otherwise + PRBool Intersects(const nsRect& aRect) const; + + // Computes the area in which aRect1 and aRect2 overlap and fills 'this' with + // the result. Returns FALSE if the rectangles don't intersect. + // + // 'this' can be the same object as either aRect1 or aRect2 + PRBool IntersectRect(const nsRect& aRect1, const nsRect& aRect2); + + // Computes the smallest rectangle that contains both aRect1 and aRect2 and + // fills 'this' with the result. Returns FALSE if both aRect1 and aRect2 are + // empty and TRUE otherwise + PRBool UnionRect(const nsRect& aRect1, const nsRect& aRect2); + + // Accessors + void SetRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) { + x = aX; y = aY; width = aWidth; height = aHeight; + } + void MoveTo(nscoord aX, nscoord aY) {x = aX; y = aY;} + void MoveTo(const nsPoint& aPoint) {x = aPoint.y; y = aPoint.y;} + void MoveBy(nscoord aDx, nscoord aDy) {x += aDx; y += aDy;} + void SizeTo(nscoord aWidth, nscoord aHeight) {width = aWidth; height = aHeight;} + void SizeTo(const nsSize& aSize) {SizeTo(aSize.width, aSize.height);} + void SizeBy(nscoord aDeltaWidth, nscoord aDeltaHeight) {width += aDeltaWidth; + height += aDeltaHeight;} + + // Inflate the rect by the specified width/height or margin + void Inflate(nscoord aDx, nscoord aDy); + void Inflate(const nsSize& aSize) {Inflate(aSize.width, aSize.height);} + void Inflate(const nsMargin& aMargin); + + // Deflate the rect by the specified width/height or margin + void Deflate(nscoord aDx, nscoord aDy); + void Deflate(const nsSize& aSize) {Deflate(aSize.width, aSize.height);} + void Deflate(const nsMargin& aMargin); + + // Overloaded operators. Note that '=' isn't defined so we'll get the + // compiler generated default assignment operator + PRBool operator==(const nsRect& aRect) const { + return (PRBool) ((x == aRect.x) && (y == aRect.y) && + (width == aRect.width) && (height == aRect.height)); + } + PRBool operator!=(const nsRect& aRect) const { + return (PRBool) ((x != aRect.x) || (y != aRect.y) || + (width != aRect.width) || (height != aRect.height)); + } + nsRect operator+(const nsRect& aRect) const { + return nsRect(x + aRect.x, y + aRect.y, + width + aRect.width, height + aRect.height); + } + nsRect operator-(const nsRect& aRect) const { + return nsRect(x - aRect.x, y - aRect.y, + width - aRect.width, height - aRect.height); + } + nsRect& operator+=(const nsPoint& aPoint) {x += aPoint.x; y += aPoint.y; return *this;} + nsRect& operator-=(const nsPoint& aPoint) {x -= aPoint.x; y -= aPoint.y; return *this;} + + nsRect& operator*=(const float aScale) {x = NS_TO_INT_ROUND(x * aScale); + y = NS_TO_INT_ROUND(y * aScale); + width = NS_TO_INT_ROUND(width * aScale); + height = NS_TO_INT_ROUND(height * aScale); + return *this;} + + // Helper methods for computing the extents + nscoord XMost() const {return x + width;} + nscoord YMost() const {return y + height;} +}; + +// Diagnostics +extern NS_GFX FILE* operator<<(FILE* out, const nsRect& rect); + +#endif /* NSRECT_H */ diff --git a/mozilla/gfx/src/nsRegion.h b/mozilla/gfx/src/nsRegion.h new file mode 100644 index 00000000000..e05b13f4f79 --- /dev/null +++ b/mozilla/gfx/src/nsRegion.h @@ -0,0 +1,160 @@ +/* -*- 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. + */ + +#ifndef nsRegion_h___ +#define nsRegion_h___ + +#include "nscore.h" +#include "nsRect.h" + +// Function type passed into nsRegion::forEachRect, invoked +// for each rectangle in a region +typedef void (*nsRectInRegionFunc)(void *closure, nsRect& rect); + +// An implementation of a region primitive that can be used to +// represent arbitrary pixel areas. Probably implemented on top +// of the native region primitive. The assumption is that, at worst, +// it is a rectangle list. +class nsRegion : public nsObjBase +{ +public: + /** + * copy operator equivalent that takes another region + * + * @param region to copy + * @return void + * + **/ + virtual void setRegion(const nsRegion* region) = 0; + + /** + * copy operator equivalent that takes a rect + * + * @param rect to copy + * @return void + * + **/ + virtual void setRect(const nsRect* rect) = 0; + + /** + * destructively intersect another region with this one + * + * @param region to intersect + * @return void + * + **/ + virtual void intersect(const nsRegion* region) = 0; + + /** + * destructively intersect a rect with this region + * + * @param rect to intersect + * @return void + * + **/ + virtual void intersect(const nsRect* rect) = 0; + + /** + * destructively union another region with this one + * + * @param region to union + * @return void + * + **/ + virtual void union(const nsRegion* region) = 0; + + /** + * destructively union a rect with this region + * + * @param rect to union + * @return void + * + **/ + virtual void union(const nsRect* rect) = 0; + + /** + * destructively subtract another region with this one + * + * @param region to subtract + * @return void + * + **/ + virtual void subtract(const nsRegion* region) = 0; + + /** + * is this region empty? i.e. does it contain any pixels + * + * @param none + * @return returns whether the region is empty + * + **/ + virtual nsbool isEmpty() = 0; + + /** + * == operator equivalent i.e. do the regions contain exactly + * the same pixels + * + * @param region to compare + * @return whether the regions are identical + * + **/ + virtual nsbool isEqual(const nsRegion* region) = 0; + + /** + * returns the bounding box of the region i.e. the smallest + * rectangle that completely contains the region. + * + * @param rect to set to the bounding box + * @return void + * + **/ + virtual void getBoundingBox(nsRect* rect) = 0; + + /** + * offsets the region in x and y + * + * @param xoffset pixel offset in x + * @param yoffset pixel offset in y + * @return void + * + **/ + virtual void offset(nsfloat xoffset, nsfloat yoffset) = 0; + + /** + * does the region completely contain the rectangle? + * + * @param rect to check for containment + * @return true iff the rect is completely contained + * + **/ + virtual nsbool containsRect(const nsRect* rect) = 0; + + /** + * invoke a function for each rectangle in the region + * + * @param func Function to invoke for each rectangle + * @param closure Arbitrary data to pass to the function + * @return void + * + **/ + virtual void forEachRect(nsRectInRegionFunc* func, void* closure) = 0; +}; + +extern NS_GFX nsRegion* NS_NewRegion(nsPresentationContext* context); + +#endif // nsRegion_h___ diff --git a/mozilla/gfx/src/nsSize.h b/mozilla/gfx/src/nsSize.h new file mode 100644 index 00000000000..9755c03c0d9 --- /dev/null +++ b/mozilla/gfx/src/nsSize.h @@ -0,0 +1,61 @@ +/* -*- 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. + */ + +#ifndef NSSIZE_H +#define NSSIZE_H + +#include "nsCoord.h" + +// Maximum allowable size +#define NS_MAXSIZE nscoord(1 << 30) + +struct nsSize { + nscoord width, height; + + // Constructors + nsSize() {} + nsSize(const nsSize& aSize) {width = aSize.width; height = aSize.height;} + nsSize(nscoord aWidth, nscoord aHeight) {width = aWidth; height = aHeight;} + + void SizeTo(nscoord aWidth, nscoord aHeight) {width = aWidth; height = aHeight;} + void SizeBy(nscoord aDeltaWidth, nscoord aDeltaHeight) {width += aDeltaWidth; + height += aDeltaHeight;} + + // Overloaded operators. Note that '=' isn't defined so we'll get the + // compiler generated default assignment operator + PRBool operator==(const nsSize& aSize) const { + return (PRBool) ((width == aSize.width) && (height == aSize.height)); + } + PRBool operator!=(const nsSize& aSize) const { + return (PRBool) ((width != aSize.width) || (height != aSize.height)); + } + nsSize operator+(const nsSize& aSize) const { + return nsSize(width + aSize.width, height + aSize.height); + } + nsSize operator-(const nsSize& aSize) const { + return nsSize(width - aSize.width, height - aSize.height); + } + nsSize& operator+=(const nsSize& aSize) {width += aSize.width; + height += aSize.height; + return *this;} + nsSize& operator-=(const nsSize& aSize) {width -= aSize.width; + height -= aSize.height; + return *this;} +}; + +#endif /* NSSIZE_H */ diff --git a/mozilla/gfx/src/nsTransform2D.cpp b/mozilla/gfx/src/nsTransform2D.cpp new file mode 100644 index 00000000000..5670f7cc464 --- /dev/null +++ b/mozilla/gfx/src/nsTransform2D.cpp @@ -0,0 +1,567 @@ +/* -*- 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 "nsTransform2D.h" + +void nsTransform2D :: SetToScale(float sx, float sy) +{ + m01 = m10 = m20 = m21 = 0.0f; + m00 = sx; + m11 = sy; + type = MG_2DSCALE; +} + +void nsTransform2D :: SetToTranslate(float tx, float ty) +{ + m01 = m10 = 0.0f; + m00 = m11 = 1.0f; + m20 = tx; + m21 = ty; + type = MG_2DTRANSLATION; +} + +void nsTransform2D :: SetMatrix(nsTransform2D *aTransform2D) +{ + m00 = aTransform2D->m00; + m01 = aTransform2D->m01; + m10 = aTransform2D->m10; + m11 = aTransform2D->m11; + m20 = aTransform2D->m20; + m21 = aTransform2D->m21; + type = aTransform2D->type; +} + +void nsTransform2D :: Concatenate(nsTransform2D *newxform) +{ + float temp00, temp01, temp10, temp11; + float new00, new01, new10, new11, new20, new21; + PRUint16 newtype = newxform->type; + + if (type == MG_2DIDENTITY) + { + //current matrix is identity + + if (newtype != MG_2DIDENTITY) + SetMatrix(newxform); + + return; + } + else if (newtype == MG_2DIDENTITY) + return; + else if ((type & MG_2DSCALE) != 0) + { + //current matrix is at least scale + + if ((newtype & (MG_2DGENERAL | MG_2DSCALE)) != 0) + { + //new matrix is general or scale + + if ((newtype & MG_2DTRANSLATION) != 0) + { + m20 += newxform->m20 * m00; + m21 += newxform->m21 * m11; + } + + m00 *= newxform->m00; + m11 *= newxform->m11; + } + else + { + //new matrix must be translation only + + m20 += newxform->m20 * m00; + m21 += newxform->m21 * m11; + } + } + else if ((type & MG_2DGENERAL) != 0) + { + //current matrix is at least general + + if ((newtype & MG_2DGENERAL) != 0) + { + //new matrix is general - worst case + + temp00 = m00; + temp01 = m01; + temp10 = m10; + temp11 = m11; + + new00 = newxform->m00; + new01 = newxform->m01; + new10 = newxform->m10; + new11 = newxform->m11; + + if ((newtype & MG_2DTRANSLATION) != 0) + { + new20 = newxform->m20; + new21 = newxform->m21; + + m20 += new20 * temp00 + new21 * temp10; + m21 += new20 * temp01 + new21 * temp11; + } + + m00 = new00 * temp00 + new01 * temp10; + m01 = new00 * temp01 + new01 * temp11; + m10 = new10 * temp00 + new11 * temp10; + m11 = new10 * temp01 + new11 * temp11; + } + else if ((newtype & MG_2DSCALE) != 0) + { + //new matrix is at least scale + + temp00 = m00; + temp01 = m01; + temp10 = m10; + temp11 = m11; + + new00 = newxform->m00; + new11 = newxform->m11; + + if ((newtype & MG_2DTRANSLATION) != 0) + { + new20 = newxform->m20; + new21 = newxform->m21; + + m20 += new20 * temp00 + new21 * temp10; + m21 += new20 * temp01 + new21 * temp11; + } + + m00 = new00 * temp00; + m01 = new00 * temp01; + m10 = new11 * temp10; + m11 = new11 * temp11; + } + else + { + //new matrix must be translation only + + new20 = newxform->m20; + new21 = newxform->m21; + + m20 += new20 * m00 + new21 * m10; + m21 += new20 * m01 + new21 * m11; + } + } + else + { + //current matrix is translation only + + if ((newtype & (MG_2DGENERAL | MG_2DSCALE)) != 0) + { + //new matrix is general or scale + + if ((newtype & MG_2DTRANSLATION) != 0) + { + m20 += newxform->m20; + m21 += newxform->m21; + } + + m00 = newxform->m00; + m11 = newxform->m11; + } + else + { + //new matrix must be translation only + + m20 += newxform->m20; + m21 += newxform->m21; + } + } + +/* temp00 = m00; + temp01 = m01; + temp10 = m10; + temp11 = m11; + temp20 = m20; + temp21 = m21; + + new00 = newxform.m00; + new01 = newxform.m01; + new10 = newxform.m10; + new11 = newxform.m11; + new20 = newxform.m20; + new21 = newxform.m21; + + m00 = new00 * temp00 + new01 * temp10; // + new02 * temp20 == 0 + m01 = new00 * temp01 + new01 * temp11; // + new02 * temp21 == 0 +// m02 += new00 * temp02 + new01 * temp12; // + new02 * temp22 == 0 + m10 = new10 * temp00 + new11 * temp10; // + new12 * temp20 == 0 + m11 = new10 * temp01 + new11 * temp11; // + new12 * temp21 == 0 +// m12 += new10 * temp02 + new11 * temp12; // + new12 * temp22 == 0 + m20 = new20 * temp00 + new21 * temp10 + temp20; // + new22 * temp20 == temp20 + m21 = new20 * temp01 + new21 * temp11 + temp21; // + new22 * temp21 == temp21 +// m22 += new20 * temp02 + new21 * temp12; // + new22 * temp22 == 1 +*/ + type |= newtype; +} + +void nsTransform2D :: PreConcatenate(nsTransform2D *newxform) +{ + float temp00, temp01, temp10, temp11, temp20, temp21; + float new00, new01, new10, new11, new20, new21; + + //this is totally unoptimized MMP + + temp00 = m00; + temp01 = m01; + temp10 = m10; + temp11 = m11; + temp20 = m20; + temp21 = m21; + + new00 = newxform->m00; + new01 = newxform->m01; + new10 = newxform->m10; + new11 = newxform->m11; + new20 = newxform->m20; + new21 = newxform->m21; + + m00 = temp00 * new00 + temp01 * new10; // + temp02 * new20 == 0 + m01 = temp00 * new01 + temp01 * new11; // + temp02 * new21 == 0 +// m02 += temp00 * new02 + temp01 * new12; // + temp02 * new22 == 0 + m10 = temp10 * new00 + temp11 * new10; // + temp12 * new20 == 0 + m11 = temp10 * new01 + temp11 * new11; // + temp12 * new21 == 0 +// m12 += temp10 * new02 + temp11 * new12; // + temp12 * new22 == 0 + m20 = temp20 * new00 + temp21 * temp10 + temp20; // + temp22 * new20 == new20 + m21 = temp20 * new01 + temp21 * new11 + temp21; // + temp22 * new21 == new21 +// m22 += temp20 * new02 + temp21 * new12; // + temp22 * new22 == 1 + + type |= newxform->type; +} + +void nsTransform2D :: TransformNoXLate(float *ptX, float *ptY) +{ + float x, y; + + switch (type) + { + case MG_2DIDENTITY: + break; + + case MG_2DSCALE: + *ptX *= m00; + *ptY *= m11; + break; + + default: + case MG_2DGENERAL: + x = *ptX; + y = *ptY; + + *ptX = x * m00 + y * m10; + *ptY = x * m01 + y * m11; + + break; + } +} + +void nsTransform2D :: TransformNoXLateCoord(nscoord *ptX, nscoord *ptY) +{ + float x, y; + + switch (type) + { + case MG_2DIDENTITY: + break; + + case MG_2DSCALE: + *ptX = NS_TO_INT_ROUND(*ptX * m00); + *ptY = NS_TO_INT_ROUND(*ptY * m11); + break; + + default: + case MG_2DGENERAL: + x = (float)*ptX; + y = (float)*ptY; + + *ptX = NS_TO_INT_ROUND(x * m00 + y * m10); + *ptY = NS_TO_INT_ROUND(x * m01 + y * m11); + + break; + } +} + +void nsTransform2D :: Transform(float *ptX, float *ptY) +{ + float x, y; + + switch (type) + { + case MG_2DIDENTITY: + break; + + case MG_2DTRANSLATION: + *ptX += m20; + *ptY += m21; + break; + + case MG_2DSCALE: + *ptX *= m00; + *ptY *= m11; + break; + + case MG_2DGENERAL: + x = *ptX; + y = *ptY; + + *ptX = x * m00 + y * m10; + *ptY = x * m01 + y * m11; + + break; + + case MG_2DSCALE | MG_2DTRANSLATION: + *ptX = *ptX * m00 + m20; + *ptY = *ptY * m11 + m21; + break; + + default: + case MG_2DGENERAL | MG_2DTRANSLATION: + x = *ptX; + y = *ptY; + + *ptX = x * m00 + y * m10 + m20; + *ptY = x * m01 + y * m11 + m21; + + break; + } +} + +void nsTransform2D :: TransformCoord(nscoord *ptX, nscoord *ptY) +{ + float x, y; + + switch (type) + { + case MG_2DIDENTITY: + break; + + case MG_2DTRANSLATION: + *ptX += NS_TO_INT_ROUND(m20); + *ptY += NS_TO_INT_ROUND(m21); + break; + + case MG_2DSCALE: + *ptX = NS_TO_INT_ROUND(*ptX * m00); + *ptY = NS_TO_INT_ROUND(*ptY * m11); + break; + + case MG_2DGENERAL: + x = (float)*ptX; + y = (float)*ptY; + + *ptX = NS_TO_INT_ROUND(x * m00 + y * m10); + *ptY = NS_TO_INT_ROUND(x * m01 + y * m11); + + break; + + case MG_2DSCALE | MG_2DTRANSLATION: + *ptX = NS_TO_INT_ROUND(*ptX * m00 + m20); + *ptY = NS_TO_INT_ROUND(*ptY * m11 + m21); + break; + + default: + case MG_2DGENERAL | MG_2DTRANSLATION: + x = (float)*ptX; + y = (float)*ptY; + + *ptX = NS_TO_INT_ROUND(x * m00 + y * m10 + m20); + *ptY = NS_TO_INT_ROUND(x * m01 + y * m11 + m21); + + break; + } +} + +void nsTransform2D :: Transform(float *aX, float *aY, float *aWidth, float *aHeight) +{ + float x, y; + + switch (type) + { + case MG_2DIDENTITY: + break; + + case MG_2DTRANSLATION: + *aX += m20; + *aY += m21; + break; + + case MG_2DSCALE: + *aX *= m00; + *aY *= m11; + *aWidth *= m00; + *aHeight *= m11; + break; + + case MG_2DGENERAL: + x = *aX; + y = *aY; + + *aX = x * m00 + y * m10; + *aY = x * m01 + y * m11; + + x = *aWidth; + y = *aHeight; + + *aHeight = x * m00 + y * m10; + *aHeight = x * m01 + y * m11; + + break; + + case MG_2DSCALE | MG_2DTRANSLATION: + *aX = *aX * m00 + m20; + *aY = *aY * m11 + m21; + *aWidth *= m00; + *aHeight *= m11; + break; + + default: + case MG_2DGENERAL | MG_2DTRANSLATION: + x = *aX; + y = *aY; + + *aX = x * m00 + y * m10 + m20; + *aY = x * m01 + y * m11 + m21; + + x = *aWidth; + y = *aHeight; + + *aWidth = x * m00 + y * m10; + *aHeight = x * m01 + y * m11; + + break; + } +} + +void nsTransform2D :: TransformCoord(nscoord *aX, nscoord *aY, nscoord *aWidth, nscoord *aHeight) +{ + float x, y; + + switch (type) + { + case MG_2DIDENTITY: + break; + + case MG_2DTRANSLATION: + *aX += NS_TO_INT_ROUND(m20); + *aY += NS_TO_INT_ROUND(m21); + break; + + case MG_2DSCALE: + *aX = NS_TO_INT_ROUND(*aX * m00); + *aY = NS_TO_INT_ROUND(*aY * m11); + *aWidth = NS_TO_INT_ROUND(*aWidth * m00); + *aHeight = NS_TO_INT_ROUND(*aHeight * m11); + break; + + case MG_2DGENERAL: + x = (float)*aX; + y = (float)*aY; + + *aX = NS_TO_INT_ROUND(x * m00 + y * m10); + *aY = NS_TO_INT_ROUND(x * m01 + y * m11); + + x = (float)*aWidth; + y = (float)*aHeight; + + *aHeight = NS_TO_INT_ROUND(x * m00 + y * m10); + *aHeight = NS_TO_INT_ROUND(x * m01 + y * m11); + + break; + + case MG_2DSCALE | MG_2DTRANSLATION: + *aX = NS_TO_INT_ROUND(*aX * m00 + m20); + *aY = NS_TO_INT_ROUND(*aY * m11 + m21); + *aWidth = NS_TO_INT_ROUND(*aWidth * m00); + *aHeight = NS_TO_INT_ROUND(*aHeight * m11); + break; + + default: + case MG_2DGENERAL | MG_2DTRANSLATION: + x = (float)*aX; + y = (float)*aY; + + *aX = NS_TO_INT_ROUND(x * m00 + y * m10 + m20); + *aY = NS_TO_INT_ROUND(x * m01 + y * m11 + m21); + + x = (float)*aWidth; + y = (float)*aHeight; + + *aWidth = NS_TO_INT_ROUND(x * m00 + y * m10); + *aHeight = NS_TO_INT_ROUND(x * m01 + y * m11); + + break; + } +} + +void nsTransform2D :: AddTranslation(float ptX, float ptY) +{ + if (type == MG_2DIDENTITY) + { + m20 = ptX; + m21 = ptY; + } + else if ((type & MG_2DSCALE) != 0) + { + //current matrix is at least scale + + m20 += ptX * m00; + m21 += ptY * m11; + } + else if ((type & MG_2DGENERAL) != 0) + { + //current matrix is at least general + + m20 += ptX * m00 + ptY * m10; + m21 += ptX * m01 + ptY * m11; + } + else + { + m20 += ptX; + m21 += ptY; + } + + type |= MG_2DTRANSLATION; +} + +void nsTransform2D :: AddScale(float ptX, float ptY) +{ + if ((type == MG_2DIDENTITY) || (type == MG_2DTRANSLATION)) + { + m00 = ptX; + m11 = ptY; + } + else if ((type & MG_2DSCALE) != 0) + { + //current matrix is at least scale + + m00 *= ptX; + m11 *= ptY; + } + else if ((type & MG_2DGENERAL) != 0) + { + //current matrix is at least general + + m00 *= ptX; + m01 *= ptX; + m10 *= ptY; + m11 *= ptY; + } + + type |= MG_2DSCALE; +} diff --git a/mozilla/gfx/src/nsTransform2D.h b/mozilla/gfx/src/nsTransform2D.h new file mode 100644 index 00000000000..523158a1ab0 --- /dev/null +++ b/mozilla/gfx/src/nsTransform2D.h @@ -0,0 +1,211 @@ +/* -*- 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. + */ + +#ifndef nsTransform2D_h___ +#define nsTransform2D_h___ + +#include "nscore.h" +#include "nsCoord.h" +#include "nsUnitConversion.h" + +#define MG_2DIDENTITY 0 +#define MG_2DTRANSLATION 1 +#define MG_2DSCALE 2 +#define MG_2DGENERAL 4 + +class NS_GFX nsTransform2D +{ +private: + //accelerators + + float m00, m01, m10, m11, m20, m21; + PRUint16 type; + +public: + //constructors + + nsTransform2D(void) { SetToIdentity(); } + nsTransform2D(nsTransform2D *aTransform2D) { SetMatrix(aTransform2D); } + + //destructor + + ~nsTransform2D(void) { } + + /** + * get the type of this transform + * + * @param + * @return type from above set + * @exception + * @author michaelp 09-25-97 1:56pm + **/ + + PRUint16 GetType(void) { return type; } + + /** + * set this transform to identity + * + * @param + * @exception + * @author michaelp 09-25-97 1:56pm + **/ + + void SetToIdentity(void) { m01 = m10 = m20 = m21 = 0.0f; m00 = m11 = 1.0f; type = MG_2DIDENTITY; } + + /** + * set this transform to a scale + * + * @param sx, x scale + * @param sy, y scale + * @exception + * @author michaelp 09-25-97 1:56pm + **/ + + void SetToScale(float sx, float sy); + + /** + * set this transform to a translation + * + * @param tx, x translation + * @param ty, y translation + * @exception + * @author michaelp 09-25-97 1:56pm + **/ + + void SetToTranslate(float tx, float ty); + + /** + * get the translation portion of this transform + * + * @param pt, Point to return translation values in + * @exception + * @author michaelp 09-25-97 1:56pm + **/ + + void GetTranslation(float *ptX, float *ptY) { *ptX = m20; *ptY = m21; } + void GetTranslationCoord(nscoord *ptX, nscoord *ptY) { *ptX = NS_TO_INT_ROUND(m20); *ptY = NS_TO_INT_ROUND(m21); } + + /** + * get the X translation portion of this transform + * + * @param + * @returns x component of translation + * @exception + **/ + + float GetXTranslation(void) { return m20; } + nscoord GetXTranslationCoord(void) { return NS_TO_INT_ROUND(m20); } + + /** + * get the Y translation portion of this transform + * + * @param + * @returns y component of translation + * @exception + **/ + + float GetYTranslation(void) { return m21; } + nscoord GetYTranslationCoord(void) { return NS_TO_INT_ROUND(m21); } + + /** + * set this matrix and type from another Transform2D + * + * @param aTransform2D is the Transform2D to be copied from + * @exception + * @author michaelp 09-25-97 1:56pm + **/ + + void SetMatrix(nsTransform2D *aTransform2D); + + /** + * post-multiply a new Transform + * + * @param newxform new Transform2D + * @exception + * @author michaelp 09-25-97 1:56pm + **/ + + void Concatenate(nsTransform2D *newxform); + + /** + * pre-multiply a new Transform + * + * @param newxform new Transform2D + * @exception + * @author michaelp 09-25-97 1:56pm + **/ + + void PreConcatenate(nsTransform2D *newxform); + + /** + * apply nontranslation portion of matrix to vector + * + * @param pt Point to transform + * @exception + * @author michaelp 09-25-97 1:56pm + **/ + + void TransformNoXLate(float *ptX, float *ptY); + void TransformNoXLateCoord(nscoord *ptX, nscoord *ptY); + + /** + * apply matrix to vector + * + * @param pt Point to transform + * @exception + * @author michaelp 09-25-97 1:56pm + **/ + + void Transform(float *ptX, float *ptY); + void TransformCoord(nscoord *ptX, nscoord *ptY); + + /** + * apply matrix to rect + * + * @param rect Rect to transform + * @exception + * @author michaelp 09-25-97 1:56pm + **/ + + void Transform(float *aX, float *aY, float *aWidth, float *aHeight); + void TransformCoord(nscoord *aX, nscoord *aY, nscoord *aWidth, nscoord *aHeight); + + /** + * add a translation to a Transform via x, y pair + * + * @param ptX x value to add as x translation + * @param ptY y value to add as y translation + * @exception + * @author michaelp 09-25-97 1:56pm + **/ + + void AddTranslation(float ptX, float ptY); + + /** + * add a scale to a Transform via x, y pair + * + * @param ptX x value to add as x scale + * @param ptY y value to add as y scale + * @exception + * @author michaelp 09-25-97 1:56pm + **/ + + void AddScale(float ptX, float ptY); +}; + +#endif diff --git a/mozilla/gfx/src/windows/makefile.win b/mozilla/gfx/src/windows/makefile.win new file mode 100644 index 00000000000..845cf051479 --- /dev/null +++ b/mozilla/gfx/src/windows/makefile.win @@ -0,0 +1,60 @@ +#!nmake +# +# 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. + +DEPTH=..\..\.. +IGNORE_MANIFEST=1 + +MAKE_OBJ_TYPE = DLL +DLLNAME = raptorgfxwin +DLL=.\$(OBJDIR)\$(DLLNAME).dll +#RESFILE = $(DLLNAME).res + +MODULE=raptor + +DEFINES =-D_IMPL_NS_GFXNONXP + +OBJS = \ + .\$(OBJDIR)\nsDeviceContextWin.obj \ + .\$(OBJDIR)\nsRenderingContextWin.obj \ + .\$(OBJDIR)\nsFontMetricsWin.obj \ + .\$(OBJDIR)\nsImageWin.obj \ + .\$(OBJDIR)\nsGfxFactoryWin.obj \ + $(NULL) + +LINCS= \ + -I$(PUBLIC)\raptor \ + -I$(PUBLIC)\xpcom \ + $(NULL) + +LCFLAGS = \ + $(LCFLAGS) \ + -D_IMPL_NS_GFXNONXP \ + $(NULL) + +LLIBS= \ + $(DIST)\lib\xpcom32.lib \ + $(DIST)\lib\raptorbase.lib \ + $(DIST)\lib\raptorgfx.lib \ + $(LIBNSPR) + +include <$(DEPTH)\config\rules.mak> + +install:: $(DLL) + $(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).dll $(DIST)\bin + +clobber:: + rm -f $(DIST)\bin\$(DLLNAME).dll diff --git a/mozilla/gfx/src/windows/nsDeviceContextWin.cpp b/mozilla/gfx/src/windows/nsDeviceContextWin.cpp new file mode 100644 index 00000000000..a171da06657 --- /dev/null +++ b/mozilla/gfx/src/windows/nsDeviceContextWin.cpp @@ -0,0 +1,166 @@ +/* -*- 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 "nsDeviceContextWin.h" +#include "nsRenderingContextWin.h" +#include "../nsGfxCIID.h" + +static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); +static NS_DEFINE_IID(kDeviceContextIID, NS_IDEVICE_CONTEXT_IID); + +nsDeviceContextWin :: nsDeviceContextWin() +{ + NS_INIT_REFCNT(); + + HDC hdc = ::GetDC(NULL); + + mTwipsToPixels = ::GetDeviceCaps(hdc, LOGPIXELSX) / NS_POINTS_TO_TWIPS_FLOAT(72.0f); + mPixelsToTwips = 1.0f / mTwipsToPixels; + + ::ReleaseDC(NULL, hdc); + + mFontCache = nsnull; + + mDevUnitsToAppUnits = 1.0f; + mAppUnitsToDevUnits = 1.0f; + + mZoom = 1.0f; +} + +nsDeviceContextWin :: ~nsDeviceContextWin() +{ + NS_IF_RELEASE(mFontCache); +} + +NS_IMPL_QUERY_INTERFACE(nsDeviceContextWin, kDeviceContextIID) +NS_IMPL_ADDREF(nsDeviceContextWin) +NS_IMPL_RELEASE(nsDeviceContextWin) + +nsresult nsDeviceContextWin :: Init() +{ + return NS_OK; +} + +float nsDeviceContextWin :: GetTwipsToDevUnits() const +{ + return mTwipsToPixels; +} + +float nsDeviceContextWin :: GetDevUnitsToTwips() const +{ + return mPixelsToTwips; +} + +void nsDeviceContextWin :: SetAppUnitsToDevUnits(float aAppUnits) +{ + mAppUnitsToDevUnits = aAppUnits; +} + +void nsDeviceContextWin :: SetDevUnitsToAppUnits(float aDevUnits) +{ + mDevUnitsToAppUnits = aDevUnits; +} + +float nsDeviceContextWin :: GetAppUnitsToDevUnits() const +{ + return mAppUnitsToDevUnits; +} + +float nsDeviceContextWin :: GetDevUnitsToAppUnits() const +{ + return mDevUnitsToAppUnits; +} + +float nsDeviceContextWin :: GetScrollBarWidth() const +{ + return ::GetSystemMetrics(SM_CXVSCROLL) * mDevUnitsToAppUnits; +} + +float nsDeviceContextWin :: GetScrollBarHeight() const +{ + return ::GetSystemMetrics(SM_CXHSCROLL) * mDevUnitsToAppUnits; +} + +nsIRenderingContext * nsDeviceContextWin :: CreateRenderingContext(nsIView *aView) +{ + nsIRenderingContext *pContext = nsnull; + nsIWidget *win = aView->GetWidget(); + nsresult rv; + + static NS_DEFINE_IID(kRCCID, NS_RENDERING_CONTEXT_CID); + static NS_DEFINE_IID(kRCIID, NS_IRENDERING_CONTEXT_IID); + + rv = NSRepository::CreateInstance(kRCCID, nsnull, kRCIID, (void **)&pContext); + + if (NS_OK == rv) + InitRenderingContext(pContext, win); + + NS_IF_RELEASE(win); + return pContext; +} + +void nsDeviceContextWin :: InitRenderingContext(nsIRenderingContext *aContext, nsIWidget *aWin) +{ + aContext->Init(this, aWin); +} + +nsIFontCache* nsDeviceContextWin::GetFontCache() +{ + if (nsnull == mFontCache) { + if (NS_OK != CreateFontCache()) { + return nsnull; + } + } + NS_ADDREF(mFontCache); + return mFontCache; +} + +void nsDeviceContextWin::FlushFontCache() +{ + NS_RELEASE(mFontCache); +} + +nsresult nsDeviceContextWin::CreateFontCache() +{ + nsresult rv = NS_NewFontCache(&mFontCache); + if (NS_OK != rv) { + return rv; + } + mFontCache->Init(this); + return NS_OK; +} + +nsIFontMetrics* nsDeviceContextWin::GetMetricsFor(const nsFont& aFont) +{ + if (nsnull == mFontCache) { + if (NS_OK != CreateFontCache()) { + return nsnull; + } + } + return mFontCache->GetMetricsFor(aFont); +} + +void nsDeviceContextWin :: SetZoom(float aZoom) +{ + mZoom = aZoom; +} + +float nsDeviceContextWin :: GetZoom() const +{ + return mZoom; +} diff --git a/mozilla/gfx/src/windows/nsDeviceContextWin.h b/mozilla/gfx/src/windows/nsDeviceContextWin.h new file mode 100644 index 00000000000..62c4d628bbe --- /dev/null +++ b/mozilla/gfx/src/windows/nsDeviceContextWin.h @@ -0,0 +1,75 @@ +/* -*- 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. + */ + +#ifndef nsDeviceContextWin_h___ +#define nsDeviceContextWin_h___ + +#include "nsIDeviceContext.h" +#include "nsUnitConversion.h" +#include "nsIFontCache.h" +#include "nsIWidget.h" +#include "nsIView.h" +#include "nsIRenderingContext.h" +#include + +class nsDeviceContextWin : public nsIDeviceContext +{ +public: + nsDeviceContextWin(); + + NS_DECL_ISUPPORTS + + virtual nsresult Init(); + + virtual nsIRenderingContext * CreateRenderingContext(nsIView *aView); + virtual void InitRenderingContext(nsIRenderingContext *aContext, nsIWidget *aWidget); + + virtual float GetTwipsToDevUnits() const; + virtual float GetDevUnitsToTwips() const; + + virtual void SetAppUnitsToDevUnits(float aAppUnits); + virtual void SetDevUnitsToAppUnits(float aDevUnits); + + virtual float GetAppUnitsToDevUnits() const; + virtual float GetDevUnitsToAppUnits() const; + + virtual float GetScrollBarWidth() const; + virtual float GetScrollBarHeight() const; + + virtual nsIFontCache * GetFontCache(); + virtual void FlushFontCache(); + + virtual nsIFontMetrics* GetMetricsFor(const nsFont& aFont); + + virtual void SetZoom(float aZoom); + virtual float GetZoom() const; + +protected: + ~nsDeviceContextWin(); + + nsresult CreateFontCache(); + + float mTwipsToPixels; + float mPixelsToTwips; + float mAppUnitsToDevUnits; + float mDevUnitsToAppUnits; + nsIFontCache *mFontCache; + float mZoom; +}; + +#endif /* nsDeviceContextWin_h___ */ diff --git a/mozilla/gfx/src/windows/nsFontMetricsWin.cpp b/mozilla/gfx/src/windows/nsFontMetricsWin.cpp new file mode 100644 index 00000000000..48a491621b6 --- /dev/null +++ b/mozilla/gfx/src/windows/nsFontMetricsWin.cpp @@ -0,0 +1,237 @@ +/* -*- 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 "nsFontMetricsWin.h" + +static NS_DEFINE_IID(kIFontMetricsIID, NS_IFONT_METRICS_IID); + +nsFontMetricsWin :: nsFontMetricsWin() +{ + NS_INIT_REFCNT(); +} + +nsFontMetricsWin :: ~nsFontMetricsWin() +{ + if (nsnull != mFont) + { + delete mFont; + mFont = nsnull; + } +} + +NS_IMPL_ISUPPORTS(nsFontMetricsWin, kIFontMetricsIID) + +// Note: The presentation context has a reference to this font +// metrics, therefore avoid circular references by not AddRef'ing the +// presentation context. +nsresult nsFontMetricsWin :: Init(const nsFont& aFont, nsIDeviceContext* aCX) +{ + mFont = new nsFont(aFont); + mContext = aCX; + + RealizeFont(); + + return NS_OK; +} + +// XXX this function is a hack; the only logical font names we should +// support are the one used by css. +const char* nsFontMetricsWin::MapFamilyToFont(const nsString& aLogicalFontName) +{ + if (aLogicalFontName.EqualsIgnoreCase("Times Roman")) { + return "Times New Roman"; + } + if (aLogicalFontName.EqualsIgnoreCase("Times")) { + return "Times New Roman"; + } + if (aLogicalFontName.EqualsIgnoreCase("Unicode")) { + return "Bitstream Cyberbit"; + } + if (aLogicalFontName.EqualsIgnoreCase("Courier")) { + return "Courier New"; + } + + // the CSS generic names + if (aLogicalFontName.EqualsIgnoreCase("serif")) { + return "Times New Roman"; + } + if (aLogicalFontName.EqualsIgnoreCase("sans-serif")) { + return "Arial"; + } + if (aLogicalFontName.EqualsIgnoreCase("cursive")) { +// return "XXX"; + } + if (aLogicalFontName.EqualsIgnoreCase("fantasy")) { +// return "XXX"; + } + if (aLogicalFontName.EqualsIgnoreCase("monospace")) { + return "Courier New"; + } + return "Arial";/* XXX for now */ +} + +void nsFontMetricsWin::RealizeFont() +{ + // Fill in logFont structure; stolen from awt + LOGFONT logFont; + logFont.lfWidth = 0; + logFont.lfEscapement = 0; + logFont.lfOrientation = 0; + logFont.lfUnderline = + (mFont->decorations & NS_FONT_DECORATION_UNDERLINE) + ? TRUE : FALSE; + logFont.lfStrikeOut = + (mFont->decorations & NS_FONT_DECORATION_LINE_THROUGH) + ? TRUE : FALSE; + logFont.lfCharSet = DEFAULT_CHARSET; + logFont.lfOutPrecision = OUT_DEFAULT_PRECIS; + logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS; + logFont.lfQuality = DEFAULT_QUALITY; + logFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; + logFont.lfWeight = (mFont->weight > NS_FONT_WEIGHT_NORMAL) // XXX ??? this should be smarter + ? FW_BOLD : FW_NORMAL; + logFont.lfItalic = (mFont->style & NS_FONT_STYLE_ITALIC) + ? TRUE : FALSE; + float t2p = mContext->GetAppUnitsToDevUnits(); + logFont.lfHeight = (LONG)(-mFont->size * t2p); + strncpy(logFont.lfFaceName, + MapFamilyToFont(mFont->name), + LF_FACESIZE); + + // Create font handle from font spec + mFontHandle = ::CreateFontIndirect(&logFont); +//fprintf(stderr, "fFontHandle=%x\n", fFontHandle); + + // Find font metrics and character widths + HWND win = ::GetDesktopWindow(); + HDC dc = ::GetDC(win); + ::SelectObject(dc, (HGDIOBJ) mFontHandle); + + // Get font metrics + float p2t = mContext->GetDevUnitsToAppUnits(); + TEXTMETRIC metrics; + ::GetTextMetrics(dc, &metrics); + mHeight = nscoord(metrics.tmHeight * p2t); + mAscent = nscoord(metrics.tmAscent * p2t); + mDescent = nscoord(metrics.tmDescent * p2t); + mLeading = nscoord(metrics.tmInternalLeading * p2t); + mMaxAscent = nscoord(metrics.tmAscent * p2t); + mMaxDescent = nscoord(metrics.tmDescent * p2t); + mMaxAdvance = nscoord(metrics.tmMaxCharWidth * p2t); +#if 0 + fprintf(stderr, "fontmetrics: height=%d ascent=%d descent=%d leading=%d\n", + fHeight, fAscent, fDescent, fLeading); +#endif + + // Get character widths in twips + int widths[256]; + ::GetCharWidth(dc, 0, 255, widths); + nscoord* tp = mCharWidths; + int* fp = widths; + int* end = fp + 256; + while (fp < end) { + *tp++ = nscoord( *fp++ * p2t ); + } + + ::ReleaseDC(win, dc); +} + +nscoord nsFontMetricsWin :: GetWidth(char ch) +{ + return mCharWidths[PRUint8(ch)]; +} + +nscoord nsFontMetricsWin :: GetWidth(PRUnichar ch) +{ + if (ch < 256) { + return mCharWidths[ch]; + } + return 0;/* XXX */ +} + +nscoord nsFontMetricsWin :: GetWidth(const nsString& aString) +{ + return GetWidth(aString.GetUnicode(), aString.Length()); +} + +nscoord nsFontMetricsWin :: GetWidth(const char *aString) +{ + // XXX use native text measurement routine + nscoord sum = 0; + PRUint8 ch; + while ((ch = PRUint8(*aString++)) != 0) { + sum += mCharWidths[ch]; + } + return sum; +} + +nscoord nsFontMetricsWin :: GetWidth(const PRUnichar *aString, PRUint32 aLength) +{ + // XXX use native text measurement routine + nscoord sum = 0; + while (aLength != 0) { + PRUnichar ch = *aString++; + if (ch < 256) { + sum += mCharWidths[ch]; + } else { + // XXX not yet + } + --aLength; + } + return sum; +} + +nscoord nsFontMetricsWin :: GetHeight() +{ + return mHeight; +} + +nscoord nsFontMetricsWin :: GetLeading() +{ + return mLeading; +} + +nscoord nsFontMetricsWin :: GetMaxAscent() +{ + return mMaxAscent; +} + +nscoord nsFontMetricsWin :: GetMaxDescent() +{ + return mMaxDescent; +} + +nscoord nsFontMetricsWin :: GetMaxAdvance() +{ + return mMaxAdvance; +} + +const nscoord * nsFontMetricsWin :: GetWidths() +{ + return mCharWidths; +} + +const nsFont& nsFontMetricsWin :: GetFont() +{ + return *mFont; +} + +nsFontHandle nsFontMetricsWin::GetFontHandle() +{ + return mFontHandle; +} diff --git a/mozilla/gfx/src/windows/nsFontMetricsWin.h b/mozilla/gfx/src/windows/nsFontMetricsWin.h new file mode 100644 index 00000000000..d34fda55c61 --- /dev/null +++ b/mozilla/gfx/src/windows/nsFontMetricsWin.h @@ -0,0 +1,75 @@ +/* -*- 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. + */ + +#ifndef nsFontMetricsWin_h__ +#define nsFontMetricsWin_h__ + +#include "nsIFontMetrics.h" +#include "nsFont.h" +#include "nsString.h" +#include "nsUnitConversion.h" +#include "nsIDeviceContext.h" +#include "nsCRT.h" + +class nsFontMetricsWin : public nsIFontMetrics +{ +public: + nsFontMetricsWin(); + ~nsFontMetricsWin(); + + void* operator new(size_t sz) { + void* rv = new char[sz]; + nsCRT::zero(rv, sz); + return rv; + } + + NS_DECL_ISUPPORTS + + virtual nsresult Init(const nsFont& aFont, nsIDeviceContext* aContext); + virtual nscoord GetWidth(char aC); + virtual nscoord GetWidth(PRUnichar aC); + virtual nscoord GetWidth(const nsString& aString); + virtual nscoord GetWidth(const char *aString); + virtual nscoord GetWidth(const PRUnichar *aString, PRUint32 aLength); + virtual nscoord GetHeight(); + virtual nscoord GetLeading(); + virtual nscoord GetMaxAscent(); + virtual nscoord GetMaxDescent(); + virtual nscoord GetMaxAdvance(); + virtual const nscoord *GetWidths(); + virtual const nsFont& GetFont(); + virtual nsFontHandle GetFontHandle(); + +protected: + void RealizeFont(); + static const char* MapFamilyToFont(const nsString& aLogicalFontName); + + nsFont *mFont; + nsIDeviceContext *mContext; + nscoord mCharWidths[256]; + nscoord mHeight; + nscoord mAscent; + nscoord mDescent; + nscoord mLeading; + nscoord mMaxAscent; + nscoord mMaxDescent; + nscoord mMaxAdvance; + HFONT mFontHandle; +}; + +#endif diff --git a/mozilla/gfx/src/windows/nsGfxFactoryWin.cpp b/mozilla/gfx/src/windows/nsGfxFactoryWin.cpp new file mode 100644 index 00000000000..e141517a609 --- /dev/null +++ b/mozilla/gfx/src/windows/nsGfxFactoryWin.cpp @@ -0,0 +1,171 @@ +/* -*- 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 "nscore.h" +#include "nsIFactory.h" +#include "nsISupports.h" +#include "../nsGfxCIID.h" +#include "nsFontMetricsWin.h" +#include "nsRenderingContextWin.h" +#include "nsImageWin.h" +#include "nsDeviceContextWin.h" + +static NS_DEFINE_IID(kCFontMetrics, NS_FONT_METRICS_CID); +static NS_DEFINE_IID(kCRenderingContext, NS_RENDERING_CONTEXT_CID); +static NS_DEFINE_IID(kCImage, NS_IMAGE_CID); +static NS_DEFINE_IID(kCDeviceContext, NS_DEVICE_CONTEXT_CID); + +static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); +static NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID); + +class nsGfxFactoryWin : public nsIFactory +{ + public: + // nsISupports methods + NS_IMETHOD QueryInterface(const nsIID &aIID, + void **aResult); + NS_IMETHOD_(nsrefcnt) AddRef(void); + NS_IMETHOD_(nsrefcnt) Release(void); + + // nsIFactory methods + NS_IMETHOD CreateInstance(nsISupports *aOuter, + const nsIID &aIID, + void **aResult); + + NS_IMETHOD LockFactory(PRBool aLock); + + nsGfxFactoryWin(const nsCID &aClass); + ~nsGfxFactoryWin(); + + private: + nsrefcnt mRefCnt; + nsCID mClassID; +}; + +nsGfxFactoryWin::nsGfxFactoryWin(const nsCID &aClass) +{ + mRefCnt = 0; + mClassID = aClass; +} + +nsGfxFactoryWin::~nsGfxFactoryWin() +{ + NS_ASSERTION(mRefCnt == 0, "non-zero refcnt at destruction"); +} + +nsresult nsGfxFactoryWin::QueryInterface(const nsIID &aIID, + void **aResult) +{ + if (aResult == NULL) { + return NS_ERROR_NULL_POINTER; + } + + // Always NULL result, in case of failure + *aResult = NULL; + + if (aIID.Equals(kISupportsIID)) { + *aResult = (void *)(nsISupports*)this; + } else if (aIID.Equals(kIFactoryIID)) { + *aResult = (void *)(nsIFactory*)this; + } + + if (*aResult == NULL) { + return NS_NOINTERFACE; + } + + AddRef(); // Increase reference count for caller + return NS_OK; +} + +nsrefcnt nsGfxFactoryWin::AddRef() +{ + return ++mRefCnt; +} + +nsrefcnt nsGfxFactoryWin::Release() +{ + if (--mRefCnt == 0) { + delete this; + return 0; // Don't access mRefCnt after deleting! + } + return mRefCnt; +} + +nsresult nsGfxFactoryWin::CreateInstance(nsISupports *aOuter, + const nsIID &aIID, + void **aResult) +{ + if (aResult == NULL) { + return NS_ERROR_NULL_POINTER; + } + + *aResult = NULL; + + nsISupports *inst = nsnull; + + if (mClassID.Equals(kCFontMetrics)) { + inst = (nsISupports *)new nsFontMetricsWin(); + } + else if (mClassID.Equals(kCDeviceContext)) { + inst = (nsISupports *)new nsDeviceContextWin(); + } + else if (mClassID.Equals(kCRenderingContext)) { + inst = (nsISupports *)new nsRenderingContextWin(); + } + else if (mClassID.Equals(kCImage)) { + inst = (nsISupports *)new nsImageWin(); + } + + if (inst == NULL) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsresult res = inst->QueryInterface(aIID, aResult); + + if (res != NS_OK) { + // We didn't get the right interface, so clean up + delete inst; + } +// else { +// inst->Release(); +// } + + return res; +} + +nsresult nsGfxFactoryWin::LockFactory(PRBool aLock) +{ + // Not implemented in simplest case. + return NS_OK; +} + +// return the proper factory to the caller +extern "C" NS_GFXNONXP nsresult NSGetFactory(const nsCID &aClass, nsIFactory **aFactory) +{ + if (nsnull == aFactory) { + return NS_ERROR_NULL_POINTER; + } + + *aFactory = new nsGfxFactoryWin(aClass); + + if (nsnull == aFactory) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return (*aFactory)->QueryInterface(kIFactoryIID, (void**)aFactory); +} diff --git a/mozilla/gfx/src/windows/nsImageWin.cpp b/mozilla/gfx/src/windows/nsImageWin.cpp new file mode 100644 index 00000000000..92c804d32d8 --- /dev/null +++ b/mozilla/gfx/src/windows/nsImageWin.cpp @@ -0,0 +1,387 @@ +/* -*- 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 "nsImageWin.h" +#include "nsRenderingContextWin.h" + +static NS_DEFINE_IID(kIImageIID, NS_IIMAGE_IID); + +HDC nsImageWin::mOptimizeDC = nsnull; + +//------------------------------------------------------------ + +nsImageWin :: nsImageWin() +{ + NS_INIT_REFCNT(); + + mImageBits = nsnull; + mHBitmap = nsnull; + mHPalette = nsnull; + mAlphaBits = nsnull; + mColorMap = nsnull; + mBHead = nsnull; + CleanUp(PR_TRUE); +} + +//------------------------------------------------------------ + +nsImageWin :: ~nsImageWin() +{ + CleanUp(PR_TRUE); +} + +NS_IMPL_ISUPPORTS(nsImageWin, kIImageIID); + +//------------------------------------------------------------ + +nsresult nsImageWin :: Init(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth,nsMaskRequirements aMaskRequirements) +{ + mHBitmap = nsnull; + mHPalette = nsnull; + CleanUp(PR_TRUE); + ComputePaletteSize(aDepth); + + if (mNumPalleteColors >= 0) + { + mBHead = (LPBITMAPINFOHEADER) new char[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * mNumPalleteColors]; + mBHead->biSize = sizeof(BITMAPINFOHEADER); + mBHead->biWidth = aWidth; + mBHead->biHeight = aHeight; + mBHead->biPlanes = 1; + mBHead->biBitCount = (unsigned short) aDepth; + mBHead->biCompression = BI_RGB; + mBHead->biSizeImage = 0; // not compressed, so we dont need this to be set + mBHead->biXPelsPerMeter = 0; + mBHead->biYPelsPerMeter = 0; + mBHead->biClrUsed = mNumPalleteColors; + mBHead->biClrImportant = mNumPalleteColors; + + ComputeMetrics(); + memset(mColorTable, 0, sizeof(RGBQUAD) * mNumPalleteColors); + mImageBits = new unsigned char[mSizeImage]; + memset(mImageBits, 128, mSizeImage); + this->MakePalette(); + + if (aMaskRequirements != nsMaskRequirements_kNoMask) + mAlphaBits = new unsigned char[aWidth * aHeight]; + + mColorMap = new nsColorMap; + + if (mColorMap != nsnull) + { + mColorMap->NumColors = mNumPalleteColors; + mColorMap->Index = new PRUint8[3 * mNumPalleteColors]; + + // XXX Note: I added this because purify claims that we make a + // copy of the memory (which we do!). I'm not sure if this + // matters or not, but this shutup purify. + memset(mColorMap->Index, 0, sizeof(PRUint8) * (3 * mNumPalleteColors)); + } + } + + return NS_OK; +} + +//------------------------------------------------------------ + +// set up the pallete to the passed in color array, RGB only in this array +void nsImageWin :: ImageUpdated(PRUint8 aFlags, nsRect *aUpdateRect) +{ +PRInt32 i; +PRUint8 *cpointer; + + if (aFlags & nsImageUpdateFlags_kColorMapChanged) + { + if (mColorMap->NumColors > 0) + { + cpointer = mColorTable; + for(i = 0; i < mColorMap->NumColors; i++) + { + *cpointer++ = mColorMap->Index[(3 * i) + 2]; + *cpointer++ = mColorMap->Index[(3 * i) + 1]; + *cpointer++ = mColorMap->Index[(3 * i)]; + *cpointer++ = 0; + } + } + this->MakePalette(); + } +} + +//------------------------------------------------------------ + +PRUintn nsImageWin :: UsePalette(HDC* aHdc, PRBool bBackground) +{ + if (mHPalette == nsnull) + return 0; + + HPALETTE hOldPalette = ::SelectPalette(aHdc, mHPalette, (bBackground == PR_TRUE) ? TRUE : FALSE); + return ::RealizePalette(aHdc); +} + +//------------------------------------------------------------ + +// Draw the bitmap, this method has a source and destination coordinates +PRBool nsImageWin :: Draw(nsDrawingSurface aSurface, PRInt32 aSX, PRInt32 aSY, PRInt32 aSWidth, PRInt32 aSHeight, + PRInt32 aDX, PRInt32 aDY, PRInt32 aDWidth, PRInt32 aDHeight) +{ +PRUint32 value,error; +HDC the_hdc = (HDC)aSurface; + + if (mBHead == nsnull) + return PR_FALSE; + + if (!IsOptimized()) + { + value = ::StretchDIBits(the_hdc,aDX,aDY,aDWidth,aDHeight, + 0,0,aSWidth, aSHeight, + mImageBits,(LPBITMAPINFO)mBHead,DIB_RGB_COLORS,SRCCOPY); + if (value == GDI_ERROR) + error = ::GetLastError(); + } + else + { + SelectObject(mOptimizeDC,mHBitmap); + if(!::StretchBlt(the_hdc,aDX,aDY,aDWidth,aDHeight,mOptimizeDC,aSX,aSY, + aSWidth,aSHeight,SRCCOPY)) + { + error = ::GetLastError(); + } + } + + return PR_TRUE; +} + +//------------------------------------------------------------ + +// Draw the bitmap, this draw just has destination coordinates +PRBool nsImageWin :: Draw(nsDrawingSurface aSurface, PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight) +{ +PRUint32 value,error; +HDC the_hdc = (HDC)aSurface; + + if (mBHead == nsnull) + return PR_FALSE; + + if (!IsOptimized()) + { + + value = ::StretchDIBits(the_hdc,aX,aY,aWidth,aHeight, + 0,0,mBHead->biWidth, mBHead->biHeight, + mImageBits,(LPBITMAPINFO)mBHead,DIB_RGB_COLORS,SRCCOPY); + + if (value == GDI_ERROR) + error = ::GetLastError(); + } + else + { + SelectObject(mOptimizeDC,mHBitmap); + //if((aWidth == mBHead->biWidth) && (aHeight == mBHead->biHeight)) + //BitBlt(the_hdc,aX,aY,aWidth,aHeight,mOptimizeDC,0,0,SRCCOPY); + + if(!::StretchBlt(the_hdc,aX,aY,aWidth,aHeight,mOptimizeDC,0,0, + mBHead->biWidth,mBHead->biHeight,SRCCOPY)) + { + error = ::GetLastError(); + } + } + + return PR_TRUE; +} + +//------------------------------------------------------------ + +PRBool nsImageWin :: MakePalette() +{ + // makes a logical palette (mHPalette) from the DIB's color table + // this palette will be selected and realized prior to drawing the DIB + + if (mNumPalleteColors == 0) + return PR_FALSE; + if (mHPalette != nsnull) + ::DeleteObject(mHPalette); + + LPLOGPALETTE pLogPal = (LPLOGPALETTE) new char[2 * sizeof(WORD) + mNumPalleteColors * sizeof(PALETTEENTRY)]; + pLogPal->palVersion = 0x300; + pLogPal->palNumEntries = mNumPalleteColors; + LPRGBQUAD pDibQuad = (LPRGBQUAD) mColorTable; + + for (int i = 0; i < mNumPalleteColors; i++) + { + pLogPal->palPalEntry[i].peRed = pDibQuad->rgbRed; + pLogPal->palPalEntry[i].peGreen = pDibQuad->rgbGreen; + pLogPal->palPalEntry[i].peBlue = pDibQuad->rgbBlue; + pLogPal->palPalEntry[i].peFlags = 0; + pDibQuad++; + } + + mHPalette = ::CreatePalette(pLogPal); + delete pLogPal; + return PR_TRUE; +} + +//------------------------------------------------------------ + +PRBool nsImageWin :: SetSystemPalette(HDC* aHdc) +{ + PRInt32 nsyscol, npal, nument; + + // if the DIB doesn't have a color table, we can use the system palette + + if (mNumPalleteColors != 0) + return PR_FALSE; + + if (!::GetDeviceCaps(aHdc, RASTERCAPS) & RC_PALETTE) + return PR_FALSE; + + nsyscol = ::GetDeviceCaps(aHdc, NUMCOLORS); + npal = ::GetDeviceCaps(aHdc, SIZEPALETTE); + nument = (npal == 0) ? nsyscol : npal; + + LPLOGPALETTE pLogPal = (LPLOGPALETTE) new char[2 * sizeof(WORD) + nument * sizeof(PALETTEENTRY)]; + + pLogPal->palVersion = 0x300; + pLogPal->palNumEntries = nument; + + ::GetSystemPaletteEntries(aHdc, 0, nument, (LPPALETTEENTRY)((LPBYTE)pLogPal + 2 * sizeof(WORD))); + + mHPalette = ::CreatePalette(pLogPal); + + delete pLogPal; + + return PR_TRUE; +} + +//------------------------------------------------------------ + +// creates an optimized bitmap, or HBITMAP +nsresult nsImageWin :: Optimize(nsDrawingSurface aSurface) +{ +nsRenderingContextWin *therc = (nsRenderingContextWin*)aSurface; +HDC the_hdc; + + if ((therc != nsnull) && !IsOptimized() && (mSizeImage > 0)) + { + the_hdc = therc->getDrawingSurface(); + if(mOptimizeDC == nsnull) + mOptimizeDC = therc->CreateOptimizeSurface(); + + mHBitmap = ::CreateDIBitmap(the_hdc,mBHead,CBM_INIT,mImageBits,(LPBITMAPINFO)mBHead,DIB_RGB_COLORS); + mIsOptimized = PR_TRUE; + CleanUp(PR_FALSE); + } + + return NS_OK; +} + +//------------------------------------------------------------ + +// figure out how big our palette needs to be +void nsImageWin :: ComputePaletteSize(PRIntn nBitCount) +{ + switch (nBitCount) + { + case 8: + mNumPalleteColors = 256; + mNumBytesColor = 1; + break; + + case 24: + mNumPalleteColors = 0; + mNumBytesColor = 3; + break; + + default: + mNumPalleteColors = -1; + mNumBytesColor = 0; + break; + } +} + +//------------------------------------------------------------ + +void nsImageWin :: ComputeMetrics() +{ + + mSizeImage = mBHead->biSizeImage; + + if (mSizeImage == 0) + { + mRowBytes = ((PRUint32) mBHead->biWidth * mBHead->biBitCount) / 32; + + if (((PRUint32)mBHead->biWidth * mBHead->biBitCount) % 32) + mRowBytes++; + + mRowBytes *= 4; + mSizeImage = mRowBytes * mBHead->biHeight; // no compression + } + + // set the color table in the info header + + mColorTable = (PRUint8 *)mBHead + sizeof(BITMAPINFOHEADER); +} + +//------------------------------------------------------------ + +// clean up our memory +void nsImageWin :: CleanUp(PRBool aCleanUpAll) +{ + // this only happens when we need to clean up everything + if(aCleanUpAll) + { + if (mAlphaBits != nsnull) + delete [] mAlphaBits; + if (mHBitmap != nsnull) + ::DeleteObject(mHBitmap); + if(mBHead) + delete[] mBHead; + + mHBitmap = nsnull; + + mAlphaBits = nsnull; + mIsOptimized = PR_FALSE; + mBHead = nsnull; + if (mImageBits != nsnull) + delete [] mImageBits; + mImageBits = nsnull; + } + + // clean up the DIB + if (mImageBits != nsnull) + delete [] mImageBits; + if (mHPalette != nsnull) + ::DeleteObject(mHPalette); + + // Should be an ISupports, so we can release + if (mColorMap != nsnull) + { + if (mColorMap->Index != nsnull) + delete [] mColorMap->Index; + delete mColorMap; + } + + mColorTable = nsnull; + mNumPalleteColors = -1; + mNumBytesColor = 0; + mSizeImage = 0; + mHPalette = nsnull; + mImageBits = nsnull; + mColorMap = nsnull; +} + +//------------------------------------------------------------ + diff --git a/mozilla/gfx/src/windows/nsImageWin.h b/mozilla/gfx/src/windows/nsImageWin.h new file mode 100644 index 00000000000..c5f54a1e8f9 --- /dev/null +++ b/mozilla/gfx/src/windows/nsImageWin.h @@ -0,0 +1,83 @@ +/* -*- 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. + */ + +#ifndef nsImageWin_h___ +#define nsImageWin_h___ + +#include "nsIImage.h" + +class nsImageWin : public nsIImage +{ +public: + nsImageWin(); + ~nsImageWin(); + + NS_DECL_ISUPPORTS + + virtual PRInt32 GetHeight() { return mBHead->biHeight; } + virtual PRInt32 GetWidth() { return mBHead->biWidth; } + virtual PRUint8* GetAlphaBits() { return mAlphaBits; } + virtual PRInt32 GetAlphaLineStride(){ return mBHead->biWidth; } + virtual PRUint8* GetBits() { return mImageBits; } + PRIntn GetSizeHeader() {return sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * mNumPalleteColors;} + virtual PRInt32 GetLineStride() {return mRowBytes; } + PRIntn GetSizeImage() { return mSizeImage; } + virtual PRBool Draw(nsDrawingSurface aSurface, PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight); + virtual PRBool Draw(nsDrawingSurface aSurface, PRInt32 aSX, PRInt32 aSY, PRInt32 aSWidth, PRInt32 aSHeight, + PRInt32 aDX, PRInt32 aDY, PRInt32 aDWidth, PRInt32 aDHeight); + virtual nsColorMap* GetColorMap() {return mColorMap;} + virtual void ImageUpdated(PRUint8 aFlags, nsRect *aUpdateRect); + virtual nsresult Init(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth, nsMaskRequirements aMaskRequirements); + virtual PRBool IsOptimized() { return mIsOptimized; } + PRBool MakePalette(); + virtual nsresult Optimize(nsDrawingSurface aSurface); + PRBool SetSystemPalette(HDC* aHdc); + PRUintn UsePalette(HDC* aHdc, PRBool bBackground = PR_FALSE); + void TestFillBits(); + PRInt32 TestSpeedBits(nsDrawingSurface aSurface, PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight); + +private: + void CleanUp(PRBool aCleanUpAll); + void ComputePaletteSize(PRIntn aBitCount); + void ComputeMetrics(); + + PRInt8 mNumBytesColor; // number of bytes per color + PRInt16 mNumPalleteColors; // either 8 or 0 + PRInt32 mSizeImage; // number of bytes + PRInt32 mRowBytes; // number of bytes per row + PRUint8 *mColorTable; // color table for the bitmap + LPBYTE mImageBits; // starting address of DIB bits + LPBYTE mAlphaBits; // alpha layer if we made one + PRBool mIsOptimized; // Have we turned our DIB into a GDI? + nsColorMap *mColorMap; // Redundant with mColorTable, but necessary + // for Set/GetColorMap + HPALETTE mHPalette; + HBITMAP mHBitmap; // the GDI bitmap + static HDC mOptimizeDC; // optimized DC for hbitmap + LPBITMAPINFOHEADER mBHead; // BITMAPINFOHEADER +}; + + +/* TODO +=================================== +1.) Share teh offscreen DC between other nsImageWin objects if nessasary + + + +*/ +#endif diff --git a/mozilla/gfx/src/windows/nsRenderingContextWin.cpp b/mozilla/gfx/src/windows/nsRenderingContextWin.cpp new file mode 100644 index 00000000000..d48e0ff033a --- /dev/null +++ b/mozilla/gfx/src/windows/nsRenderingContextWin.cpp @@ -0,0 +1,784 @@ +/* -*- 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 "nsRenderingContextWin.h" +#include + +class GraphicsState +{ +public: + GraphicsState(); + GraphicsState(GraphicsState &aState); + ~GraphicsState(); + + GraphicsState *mNext; + nsTransform2D mMatrix; + nsRect mLocalClip; + nsRect mGlobalClip; + HRGN mClipRegion; +}; + +GraphicsState :: GraphicsState() +{ + mNext = nsnull; + mMatrix.SetToIdentity(); + mLocalClip.x = mLocalClip.y = mLocalClip.width = mLocalClip.height = 0; + mGlobalClip = mLocalClip; + mClipRegion = NULL; +} + +GraphicsState :: GraphicsState(GraphicsState &aState) : + mMatrix(&aState.mMatrix), + mLocalClip(aState.mLocalClip), + mGlobalClip(aState.mGlobalClip) +{ + mNext = &aState; + mClipRegion = NULL; +} + +GraphicsState :: ~GraphicsState() +{ + if (NULL != mClipRegion) + { + ::DeleteObject(mClipRegion); + mClipRegion = NULL; + } +} + +static NS_DEFINE_IID(kRenderingContextIID, NS_IRENDERING_CONTEXT_IID); + +// XXX add in code to setup a default font in the rendering context! + +nsRenderingContextWin :: nsRenderingContextWin() +{ + NS_INIT_REFCNT(); + + //mFont = nsnull; + mDC = nsnull; + mMainDC = nsnull; + mDCOwner = nsnull; + mFontMetrics = nsnull; + mFontCache = nsnull; +#ifdef NS_DEBUG + mInitialized = PR_FALSE; +#endif + + mStateCache = new nsVoidArray(); + + //create an initial GraphicsState + + PushState(); + + mP2T = 1.0f; +} + +nsRenderingContextWin :: ~nsRenderingContextWin() +{ + if (nsnull != mDCOwner) + { + //first try to get rid of a DC originally associated with the window + //but pushed over to a dest DC for offscreen rendering. if there is no + //rolled over DC, then the mDC is the one associated with the window. + + if (nsnull != mMainDC) + ReleaseDC((HWND)mDCOwner->GetNativeData(NS_NATIVE_WINDOW), mMainDC); + else if (nsnull != mDC) + ReleaseDC((HWND)mDCOwner->GetNativeData(NS_NATIVE_WINDOW), mDC); + } + + NS_IF_RELEASE(mFontMetrics); + NS_IF_RELEASE(mFontCache); + NS_IF_RELEASE(mDCOwner); + + //destroy the initial GraphicsState + + PopState(); + + if (nsnull != mStateCache) + { + PRInt32 cnt = mStateCache->Count(); + + while (--cnt >= 0) + { + GraphicsState *state = (GraphicsState *)mStateCache->ElementAt(cnt); + mStateCache->RemoveElementAt(cnt); + + if (nsnull != state) + delete state; + } + + delete mStateCache; + mStateCache = nsnull; + } + + mTMatrix = nsnull; + mDC = nsnull; + mMainDC = nsnull; +} + +NS_IMPL_QUERY_INTERFACE(nsRenderingContextWin, kRenderingContextIID) +NS_IMPL_ADDREF(nsRenderingContextWin) +NS_IMPL_RELEASE(nsRenderingContextWin) + +nsresult nsRenderingContextWin :: Init(nsIDeviceContext* aContext, + nsIWidget *aWindow) +{ + NS_PRECONDITION(PR_FALSE == mInitialized, "double init"); + + mDC = (HWND)aWindow->GetNativeData(NS_NATIVE_GRAPHIC); + mDCOwner = aWindow; + + if (mDCOwner) + NS_ADDREF(mDCOwner); + + mTMatrix->AddScale(aContext->GetAppUnitsToDevUnits(), + aContext->GetAppUnitsToDevUnits()); + mP2T = aContext->GetDevUnitsToAppUnits(); + mFontCache = aContext->GetFontCache(); + +#ifdef NS_DEBUG + mInitialized = PR_TRUE; +#endif + + return NS_OK; +} + +nsresult nsRenderingContextWin :: Init(nsIDeviceContext* aContext, + nsDrawingSurface aSurface) +{ + NS_PRECONDITION(PR_FALSE == mInitialized, "double init"); + + mDC = (HDC)aSurface; + mDCOwner = nsnull; + + mTMatrix->AddScale(aContext->GetAppUnitsToDevUnits(), + aContext->GetAppUnitsToDevUnits()); + mP2T = aContext->GetDevUnitsToAppUnits(); + mFontCache = aContext->GetFontCache(); + +#ifdef NS_DEBUG + mInitialized = PR_TRUE; +#endif + + return NS_OK; +} + +nsresult nsRenderingContextWin :: SelectOffScreenDrawingSurface(nsDrawingSurface aSurface) +{ + mMainDC = mDC; + mDC = (HDC)aSurface; + + return NS_OK; +} + +void nsRenderingContextWin :: Reset() +{ +} + +void nsRenderingContextWin :: PushState() +{ + PRInt32 cnt = mStateCache->Count(); + + if (cnt == 0) + { + if (nsnull == mStates) + mStates = new GraphicsState(); + else + mStates = new GraphicsState(*mStates); + } + else + { + GraphicsState *state = (GraphicsState *)mStateCache->ElementAt(cnt - 1); + mStateCache->RemoveElementAt(cnt - 1); + + state->mNext = mStates; + state->mMatrix = mStates->mMatrix; + + mStates = state; + } + + mTMatrix = &mStates->mMatrix; +} + +void nsRenderingContextWin :: PopState() +{ + if (nsnull == mStates) + { + NS_ASSERTION(!(nsnull == mStates), "state underflow"); + } + else + { + GraphicsState *state = mStates; + + mStates = mStates->mNext; + + mStateCache->AppendElement(state); + + if (nsnull != mStates) + { + mTMatrix = &mStates->mMatrix; + + if (state->mGlobalClip != mStates->mGlobalClip) + { + GraphicsState *pstate = mStates; + + //the clip rect has changed from state to state, so + //install the previous clip rect + + while (nsnull == pstate->mClipRegion) + pstate = pstate->mNext; + + if (nsnull != pstate) + ::SelectClipRgn(mDC, pstate->mClipRegion); + } + } + else + mTMatrix = nsnull; + } +} + +PRBool nsRenderingContextWin :: IsVisibleRect(const nsRect& aRect) +{ + return PR_TRUE; +} + +void nsRenderingContextWin :: SetClipRect(const nsRect& aRect, PRBool aIntersect) +{ + nsRect trect = aRect; + + mStates->mLocalClip = aRect; + + mTMatrix->TransformCoord(&trect.x, &trect.y, + &trect.width, &trect.height); + + //should we combine the new rect with the previous? + + if (aIntersect == PR_TRUE) + { + if (PR_FALSE == mStates->mGlobalClip.IntersectRect(mStates->mGlobalClip, trect)) + { + mStates->mGlobalClip.x = mStates->mGlobalClip.y = mStates->mGlobalClip.width = mStates->mGlobalClip.height = 0; + } + } + else + mStates->mGlobalClip = trect; + + if (NULL != mStates->mClipRegion) + ::DeleteObject(mStates->mClipRegion); + + mStates->mClipRegion = ::CreateRectRgn(mStates->mGlobalClip.x, + mStates->mGlobalClip.y, + mStates->mGlobalClip.XMost(), + mStates->mGlobalClip.YMost()); + ::SelectClipRgn(mDC, mStates->mClipRegion); +} + +const nsRect& nsRenderingContextWin :: GetClipRect() +{ + return mStates->mLocalClip; +} + +void nsRenderingContextWin :: SetColor(nscolor aColor) +{ + mCurrentColor = aColor; + mColor = RGB(NS_GET_R(aColor), NS_GET_G(aColor), NS_GET_B(aColor)); +} + +nscolor nsRenderingContextWin :: GetColor() const +{ + return mCurrentColor; +} + +void nsRenderingContextWin :: SetFont(const nsFont& aFont) +{ + NS_IF_RELEASE(mFontMetrics); + mFontMetrics = mFontCache->GetMetricsFor(aFont); +} + +const nsFont& nsRenderingContextWin :: GetFont() +{ + return mFontMetrics->GetFont(); +} + +nsIFontMetrics* nsRenderingContextWin :: GetFontMetrics() +{ + return mFontMetrics; +} + +// add the passed in translation to the current translation +void nsRenderingContextWin :: Translate(nscoord aX, nscoord aY) +{ + mTMatrix->AddTranslation((float)aX,(float)aY); +} + +// add the passed in scale to the current scale +void nsRenderingContextWin :: Scale(float aSx, float aSy) +{ + mTMatrix->AddScale(aSx, aSy); +} + +nsTransform2D * nsRenderingContextWin :: GetCurrentTransform() +{ + return mTMatrix; +} + +nsDrawingSurface nsRenderingContextWin :: CreateDrawingSurface(nsRect &aBounds) +{ + HDC hDC = ::CreateCompatibleDC(mDC); + HBITMAP hBits = ::CreateCompatibleBitmap(mDC, aBounds.width, aBounds.height); + ::SelectObject(hDC, hBits); + + return hDC; +} + +void nsRenderingContextWin :: DestroyDrawingSurface(nsDrawingSurface aDS) +{ + HDC hDC = (HDC)aDS; + + HBITMAP hTempBits = ::CreateCompatibleBitmap(hDC, 2, 2); + HBITMAP hBits = ::SelectObject(hDC, hTempBits); + + ::DeleteObject(hBits); + ::DeleteObject(hTempBits); + ::DeleteDC(hDC); +} + + +nsDrawingSurface nsRenderingContextWin::CreateOptimizeSurface() +{ + return(::CreateCompatibleDC(mDC)); +} + +nsDrawingSurface nsRenderingContextWin::getDrawingSurface() +{ + return(mDC); +} + +void nsRenderingContextWin :: DrawLine(nscoord aX0, nscoord aY0, nscoord aX1, nscoord aY1) +{ + mTMatrix->TransformCoord(&aX0,&aY0); + mTMatrix->TransformCoord(&aX1,&aY1); + + HPEN newPen = ::CreatePen(PS_SOLID, 0, mColor); + HPEN oldPen = ::SelectObject(mDC, newPen); + ::MoveToEx(mDC, (int)(aX0), (int)(aY0), NULL); + ::LineTo(mDC, (int)(aX1), (int)(aY1)); + ::SelectObject(mDC, oldPen); +} + +void nsRenderingContextWin :: DrawRect(const nsRect& aRect) +{ + RECT nr; + nsRect tr; + + tr = aRect; + mTMatrix->TransformCoord(&tr.x,&tr.y,&tr.width,&tr.height); + nr.left = tr.x; + nr.top = tr.y; + nr.right = tr.x+tr.width; + nr.bottom = tr.y+tr.height; + + HBRUSH brush = ::CreateSolidBrush(mColor); + ::FrameRect(mDC, &nr, brush); + ::DeleteObject(brush); +} + +void nsRenderingContextWin :: DrawRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) +{ + RECT nr; + + mTMatrix->TransformCoord(&aX,&aY,&aWidth,&aHeight); + nr.left = aX; + nr.top = aY; + nr.right = aX+aWidth; + nr.bottom = aY+aHeight; + + HBRUSH brush = ::CreateSolidBrush(mColor); + ::FrameRect(mDC, &nr, brush); + ::DeleteObject(brush); +} + +void nsRenderingContextWin :: FillRect(const nsRect& aRect) +{ + RECT nr; + nsRect tr; + + tr = aRect; + mTMatrix->TransformCoord(&tr.x,&tr.y,&tr.width,&tr.height); + nr.left = tr.x; + nr.top = tr.y; + nr.right = tr.x+tr.width; + nr.bottom = tr.y+tr.height; + + HBRUSH brush = ::CreateSolidBrush(mColor); + ::FillRect(mDC, &nr, brush); + ::DeleteObject(brush); +} + +void nsRenderingContextWin :: FillRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) +{ + RECT nr; + nsRect tr; + + mTMatrix->TransformCoord(&aX,&aY,&aWidth,&aHeight); + nr.left = aX; + nr.top = aY; + nr.right = aX+aWidth; + nr.bottom = aY+aHeight; + + HBRUSH brush = ::CreateSolidBrush(mColor); + ::FillRect(mDC, &nr, brush); + ::DeleteObject(brush); +} + +void nsRenderingContextWin::DrawPolygon(nsPoint aPoints[], PRInt32 aNumPoints) +{ + // First transform nsPoint's into POINT's; perform coordinate space + // transformation at the same time + POINT pts[20]; + POINT* pp0 = pts; + + if (aNumPoints > 20) + pp0 = new POINT[aNumPoints]; + + POINT* pp = pp0; + const nsPoint* np = &aPoints[0]; + + for (PRInt32 i = 0; i < aNumPoints; i++, pp++, np++) + { + pp->x = np->x; + pp->y = np->y; + mTMatrix->TransformCoord((int*)&pp->x,(int*)&pp->y); + } + + // Outline the polygon + int pfm = ::GetPolyFillMode(mDC); + ::SetPolyFillMode(mDC, WINDING); + LOGBRUSH lb; + lb.lbStyle = BS_NULL; + lb.lbColor = 0; + lb.lbHatch = 0; + HBRUSH brush = ::CreateBrushIndirect(&lb); + HPEN pen = ::CreatePen(PS_SOLID, 0, mColor); + HPEN oldPen = ::SelectObject(mDC, pen); + HBRUSH oldBrush = ::SelectObject(mDC, brush); + ::Polygon(mDC, pp0, int(aNumPoints)); + ::SelectObject(mDC, oldBrush); + ::SelectObject(mDC, oldPen); + ::DeleteObject(pen); + ::DeleteObject(brush); + ::SetPolyFillMode(mDC, pfm); + + // Release temporary storage if necessary + if (pp0 != pts) + delete pp0; +} + +void nsRenderingContextWin::FillPolygon(nsPoint aPoints[], PRInt32 aNumPoints) +{ + // First transform nsPoint's into POINT's; perform coordinate space + // transformation at the same time + + POINT pts[20]; + POINT* pp0 = pts; + + if (aNumPoints > 20) + pp0 = new POINT[aNumPoints]; + + POINT* pp = pp0; + const nsPoint* np = &aPoints[0]; + + for (PRInt32 i = 0; i < aNumPoints; i++, pp++, np++) + { + pp->x = np->x; + pp->y = np->y; + mTMatrix->TransformCoord((int*)&pp->x,(int*)&pp->y); + } + + // Fill the polygon + int pfm = ::GetPolyFillMode(mDC); + ::SetPolyFillMode(mDC, WINDING); + HBRUSH brush = ::CreateSolidBrush(mColor); + HPEN pen = ::CreatePen(PS_NULL, 0, 0); + HPEN oldPen = ::SelectObject(mDC, pen); + HBRUSH oldBrush = ::SelectObject(mDC, brush); + ::Polygon(mDC, pp0, int(aNumPoints)); + ::SelectObject(mDC, oldBrush); + ::SelectObject(mDC, oldPen); + ::DeleteObject(pen); + ::DeleteObject(brush); + ::SetPolyFillMode(mDC, pfm); + + // Release temporary storage if necessary + if (pp0 != pts) + delete pp0; +} + +void nsRenderingContextWin :: DrawEllipse(const nsRect& aRect) +{ + DrawEllipse(aRect.x, aRect.y, aRect.width, aRect.height); +} + +void nsRenderingContextWin :: DrawEllipse(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) +{ + mTMatrix->TransformCoord(&aX, &aY, &aWidth, &aHeight); + + HPEN newPen = ::CreatePen(PS_SOLID, 0, mColor); + HPEN oldPen = ::SelectObject(mDC, newPen); + HBRUSH oldBrush = ::SelectObject(mDC, ::GetStockObject(NULL_BRUSH)); + + ::Ellipse(mDC, aX, aY, aX + aWidth, aY + aHeight); + + ::SelectObject(mDC, oldBrush); + ::SelectObject(mDC, oldPen); + ::DeleteObject(newPen); +} + +void nsRenderingContextWin :: FillEllipse(const nsRect& aRect) +{ + FillEllipse(aRect.x, aRect.y, aRect.width, aRect.height); +} + +void nsRenderingContextWin :: FillEllipse(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) +{ + mTMatrix->TransformCoord(&aX, &aY, &aWidth, &aHeight); + + HPEN newPen = ::CreatePen(PS_SOLID, 0, mColor); + HPEN oldPen = ::SelectObject(mDC, newPen); + HBRUSH newBrush = ::CreateSolidBrush(mCurrentColor); + HBRUSH oldBrush = ::SelectObject(mDC, newBrush); + + ::Ellipse(mDC, aX, aY, aX + aWidth, aY + aHeight); + + ::SelectObject(mDC, oldBrush); + ::SelectObject(mDC, oldPen); + ::DeleteObject(newBrush); + ::DeleteObject(newPen); +} + +void nsRenderingContextWin :: DrawArc(const nsRect& aRect, + float aStartAngle, float aEndAngle) +{ + this->DrawArc(aRect.x,aRect.y,aRect.width,aRect.height,aStartAngle,aEndAngle); +} + +void nsRenderingContextWin :: DrawArc(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, + float aStartAngle, float aEndAngle) +{ +PRInt32 quad1,quad2,sx,sy,ex,ey,cx,cy; +float anglerad,distance; + + mTMatrix->TransformCoord(&aX, &aY, &aWidth, &aHeight); + + HPEN newPen = ::CreatePen(PS_SOLID, 0, mColor); + HPEN oldPen = ::SelectObject(mDC, newPen); + HBRUSH newBrush = ::CreateSolidBrush(mCurrentColor); + HBRUSH oldBrush = ::SelectObject(mDC, newBrush); + + // figure out the the coordinates of the arc from the angle + distance = (float)sqrt((float)(aWidth*aWidth + aHeight*aHeight)); + cx = aX+aWidth/2; + cy = aY+aHeight/2; + + anglerad = (float)(aStartAngle/(180.0/3.14159265358979323846)); + quad1 = (PRInt32)(aStartAngle/90.0); + sx = (PRInt32)(distance*cos(anglerad)+cx); + sy = (PRInt32)(cy-distance*sin(anglerad)); + + anglerad = (float)(aEndAngle/(180.0/3.14159265358979323846)); + quad2 = (PRInt32)(aEndAngle/90.0); + ex = (PRInt32)(distance*cos(anglerad)+cx); + ey = (PRInt32)(cy-distance*sin(anglerad)); + + // this just makes it consitent, on windows 95 arc will always draw CC, nt this sets direction + ::SetArcDirection (mDC,AD_COUNTERCLOCKWISE); + + ::Arc(mDC,aX,aY,aX+aWidth,aY+aHeight,sx,sy,ex,ey); + + ::SelectObject(mDC, oldBrush); + ::SelectObject(mDC, oldPen); + ::DeleteObject(newBrush); + ::DeleteObject(newPen); +} + +void nsRenderingContextWin :: FillArc(const nsRect& aRect, + float aStartAngle, float aEndAngle) +{ + this->FillArc(aRect.x,aRect.y,aRect.width,aRect.height,aStartAngle,aEndAngle); +} + +void nsRenderingContextWin :: FillArc(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, + float aStartAngle, float aEndAngle) +{ +PRInt32 quad1,quad2,sx,sy,ex,ey,cx,cy; +float anglerad,distance; + + mTMatrix->TransformCoord(&aX, &aY, &aWidth, &aHeight); + + HPEN newPen = ::CreatePen(PS_SOLID, 0, mColor); + HPEN oldPen = ::SelectObject(mDC, newPen); + HBRUSH newBrush = ::CreateSolidBrush(mCurrentColor); + HBRUSH oldBrush = ::SelectObject(mDC, newBrush); + + // figure out the the coordinates of the arc from the angle + distance = (float)sqrt((float)(aWidth*aWidth + aHeight*aHeight)); + cx = aX+aWidth/2; + cy = aY+aHeight/2; + + anglerad = (float)(aStartAngle/(180.0/3.14159265358979323846)); + quad1 = (PRInt32)(aStartAngle/90.0); + sx = (PRInt32)(distance*cos(anglerad)+cx); + sy = (PRInt32)(cy-distance*sin(anglerad)); + + anglerad = (float)(aEndAngle/(180.0/3.14159265358979323846)); + quad2 = (PRInt32)(aEndAngle/90.0); + ex = (PRInt32)(distance*cos(anglerad)+cx); + ey = (PRInt32)(cy-distance*sin(anglerad)); + + // this just makes it consitent, on windows 95 arc will always draw CC, nt this sets direction + ::SetArcDirection (mDC,AD_COUNTERCLOCKWISE); + + ::Pie(mDC,aX,aY,aX+aWidth,aY+aHeight,sx,sy,ex,ey); + + ::SelectObject(mDC, oldBrush); + ::SelectObject(mDC, oldPen); + ::DeleteObject(newBrush); + ::DeleteObject(newPen); + +} + +void nsRenderingContextWin :: DrawString(const char *aString, PRUint32 aLength, + nscoord aX, nscoord aY, + nscoord aWidth) +{ + HFONT oldfnt = ::SelectObject(mDC, (HGDIOBJ) mFontMetrics->GetFontHandle()); + int oldBkMode = ::SetBkMode(mDC, TRANSPARENT); + int x,y; + + COLORREF oldColor = ::SetTextColor(mDC, mColor); + x = aX; + y = aY; + mTMatrix->TransformCoord(&x,&y); + ::TextOut(mDC,x,y,aString,aLength); + + if (mFontMetrics->GetFont().decorations & NS_FONT_DECORATION_OVERLINE) + DrawLine(aX, aY, aX + aWidth, aY); + + ::SetBkMode(mDC, oldBkMode); + ::SetTextColor(mDC, oldColor); + ::SelectObject(mDC, oldfnt); +} + +void nsRenderingContextWin :: DrawString(const PRUnichar *aString, PRUint32 aLength, + nscoord aX, nscoord aY, + nscoord aWidth) +{ + int x,y; + HFONT oldfnt = ::SelectObject(mDC, (HGDIOBJ) mFontMetrics->GetFontHandle()); + int oldBkMode = ::SetBkMode(mDC, TRANSPARENT); + + COLORREF oldColor = ::SetTextColor(mDC, mColor); + x = aX; + y = aY; + mTMatrix->TransformCoord(&x,&y); + ::TextOutW(mDC,x,y,aString,aLength); + + if (mFontMetrics->GetFont().decorations & NS_FONT_DECORATION_OVERLINE) + DrawLine(aX, aY, aX + aWidth, aY); + + ::SetBkMode(mDC, oldBkMode); + ::SetTextColor(mDC, oldColor); + ::SelectObject(mDC, oldfnt); +} + +void nsRenderingContextWin :: DrawString(const nsString& aString, + nscoord aX, nscoord aY, + nscoord aWidth) +{ + DrawString(aString.GetUnicode(), aString.Length(), aX, aY, aWidth); +} + +void nsRenderingContextWin :: DrawImage(nsIImage *aImage, nscoord aX, nscoord aY) +{ + NS_PRECONDITION(PR_TRUE == mInitialized, "!initialized"); + + nscoord width, height; + + width = NS_TO_INT_ROUND(mP2T * aImage->GetWidth()); + height = NS_TO_INT_ROUND(mP2T * aImage->GetHeight()); + + this->DrawImage(aImage, aX, aY, width, height); +} + +void nsRenderingContextWin :: DrawImage(nsIImage *aImage, nscoord aX, nscoord aY, + nscoord aWidth, nscoord aHeight) +{ + nsRect tr; + + tr.x = aX; + tr.y = aY; + tr.width = aWidth; + tr.height = aHeight; + + this->DrawImage(aImage, tr); +} + +void nsRenderingContextWin :: DrawImage(nsIImage *aImage, const nsRect& aSRect, const nsRect& aDRect) +{ + nsRect sr,dr; + + sr = aSRect; + mTMatrix->TransformCoord(&sr.x, &sr.y, &sr.width, &sr.height); + + dr = aDRect; + mTMatrix->TransformCoord(&dr.x, &dr.y, &dr.width, &dr.height); + + ((nsImageWin *)aImage)->Draw(mDC,sr.x,sr.y,sr.width,sr.height,dr.x,dr.y,dr.width,dr.height); +} + +void nsRenderingContextWin :: DrawImage(nsIImage *aImage, const nsRect& aRect) +{ + nsRect tr; + + tr = aRect; + mTMatrix->TransformCoord(&tr.x, &tr.y, &tr.width, &tr.height); + + ((nsImageWin *)aImage)->Draw(mDC, tr.x, tr.y, tr.width, tr.height); +} + +nsresult nsRenderingContextWin :: CopyOffScreenBits(nsRect &aBounds) +{ + if ((nsnull != mDC) && (nsnull != mMainDC)) + { + GraphicsState *pstate = mStates; + + //look for a cliprect somewhere in the stack... + + while (nsnull == pstate->mClipRegion) + pstate = pstate->mNext; + + if (nsnull != pstate) + ::SelectClipRgn(mMainDC, pstate->mClipRegion); + + ::BitBlt(mMainDC, 0, 0, aBounds.width, aBounds.height, mDC, 0, 0, SRCCOPY); + } + else + NS_ASSERTION(0, "attempt to blit with bad DCs"); + + return NS_OK; +} diff --git a/mozilla/gfx/src/windows/nsRenderingContextWin.h b/mozilla/gfx/src/windows/nsRenderingContextWin.h new file mode 100644 index 00000000000..8003c298516 --- /dev/null +++ b/mozilla/gfx/src/windows/nsRenderingContextWin.h @@ -0,0 +1,149 @@ +/* -*- 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. + */ + +#ifndef nsRenderingContextWin_h___ +#define nsRenderingContextWin_h___ + +#include "nsIRenderingContext.h" +#include "nsUnitConversion.h" +#include "nsFont.h" +#include "nsIFontMetrics.h" +#include "nsPoint.h" +#include "nsString.h" +#include "nsCRT.h" +#include "nsTransform2D.h" +#include "nsIViewManager.h" +#include "nsIPresShell.h" +#include "nsIWidget.h" +#include "nsRect.h" +#include "nsIFontCache.h" +#include "nsImageWin.h" +#include "nsIDeviceContext.h" +#include "nsVoidArray.h" + +class GraphicsState; + +class nsRenderingContextWin : public nsIRenderingContext +{ +public: + nsRenderingContextWin(); + ~nsRenderingContextWin(); + + void* operator new(size_t sz) { + void* rv = new char[sz]; + nsCRT::zero(rv, sz); + return rv; + } + + NS_DECL_ISUPPORTS + + virtual nsresult Init(nsIDeviceContext* aContext, nsIWidget *aWindow); + virtual nsresult Init(nsIDeviceContext* aContext, nsDrawingSurface aSurface); + + virtual void Reset(); + + virtual nsresult SelectOffScreenDrawingSurface(nsDrawingSurface aSurface); + + virtual void PushState(); + virtual void PopState(); + + virtual PRBool IsVisibleRect(const nsRect& aRect); + + virtual void SetClipRect(const nsRect& aRect, PRBool aIntersect); + virtual const nsRect& GetClipRect(); + + virtual void SetColor(nscolor aColor); + virtual nscolor GetColor() const; + + virtual void SetFont(const nsFont& aFont); + virtual const nsFont& GetFont(); + + virtual nsIFontMetrics * GetFontMetrics(); + + virtual void Translate(nscoord aX, nscoord aY); + virtual void Scale(float aSx, float aSy); + virtual nsTransform2D * GetCurrentTransform(); + + virtual nsDrawingSurface CreateDrawingSurface(nsRect &aBounds); + virtual void DestroyDrawingSurface(nsDrawingSurface aDS); + + virtual nsDrawingSurface CreateOptimizeSurface(); + + virtual nsDrawingSurface getDrawingSurface(); + + virtual void DrawLine(nscoord aX0, nscoord aY0, nscoord aX1, nscoord aY1); + + virtual void DrawRect(const nsRect& aRect); + virtual void DrawRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight); + virtual void FillRect(const nsRect& aRect); + virtual void FillRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight); + + virtual void DrawPolygon(nsPoint aPoints[], PRInt32 aNumPoints); + virtual void FillPolygon(nsPoint aPoints[], PRInt32 aNumPoints); + + virtual void DrawEllipse(const nsRect& aRect); + virtual void DrawEllipse(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight); + virtual void FillEllipse(const nsRect& aRect); + virtual void FillEllipse(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight); + + virtual void DrawArc(const nsRect& aRect, + float aStartAngle, float aEndAngle); + virtual void DrawArc(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, + float aStartAngle, float aEndAngle); + virtual void FillArc(const nsRect& aRect, + float aStartAngle, float aEndAngle); + virtual void FillArc(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, + float aStartAngle, float aEndAngle); + + virtual void DrawString(const char *aString, PRUint32 aLength, + nscoord aX, nscoord aY, + nscoord aWidth); + virtual void DrawString(const PRUnichar *aString, PRUint32 aLength, nscoord aX, nscoord aY, + nscoord aWidth); + virtual void DrawString(const nsString& aString, nscoord aX, nscoord aY, + nscoord aWidth); + + virtual void DrawImage(nsIImage *aImage, nscoord aX, nscoord aY); + virtual void DrawImage(nsIImage *aImage, nscoord aX, nscoord aY, + nscoord aWidth, nscoord aHeight); + virtual void DrawImage(nsIImage *aImage, const nsRect& aRect); + virtual void DrawImage(nsIImage *aImage, const nsRect& aSRect, const nsRect& aDRect); + + virtual nsresult CopyOffScreenBits(nsRect &aBounds); + +protected: + + nscolor mCurrentColor; + nsTransform2D *mTMatrix; // transform that all the graphics drawn here will obey + nsIFontMetrics *mFontMetrics; + nsIFontCache *mFontCache; + HDC mDC; + COLORREF mColor; + nsIWidget *mDCOwner; +// int mOldMapMode; + float mP2T; + HDC mMainDC; + GraphicsState *mStates; + nsVoidArray *mStateCache; + +#ifdef NS_DEBUG + PRBool mInitialized; +#endif +}; + +#endif /* nsRenderingContextWin_h___ */ diff --git a/mozilla/gfx/tests/DumpColors.cpp b/mozilla/gfx/tests/DumpColors.cpp new file mode 100644 index 00000000000..12859f3a739 --- /dev/null +++ b/mozilla/gfx/tests/DumpColors.cpp @@ -0,0 +1,32 @@ +/* -*- 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 +#include "nsColor.h" +#include "nsColorNames.h" + +int main(int argc, char** argv) +{ + const nsColorNames::NameTableEntry* et = &nsColorNames::kNameTable[0]; + for (int i = 0; i < COLOR_MAX; i++, et++) { + nscolor rgba = nsColorNames::kColors[i]; + printf("%s: NS_RGB(%d,%d,%d,%d)\n", et->name, + NS_GET_R(rgba), NS_GET_G(rgba), NS_GET_B(rgba), NS_GET_A(rgba)); + } + return 0; +} diff --git a/mozilla/gfx/tests/Makefile b/mozilla/gfx/tests/Makefile new file mode 100644 index 00000000000..9ef4e6e0c46 --- /dev/null +++ b/mozilla/gfx/tests/Makefile @@ -0,0 +1,63 @@ +#!gmake +# +# 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. + +DEPTH=../.. + +DIRS = btest + +include $(DEPTH)/config/config.mk + +CPPSRCS = \ + DumpColors.cpp \ + TestColorNames.cpp \ + TestRect.cpp \ + $(NULL) + +INCLUDES+=-I../src -I$(PUBLIC)/raptor -I$(PUBLIC)/xpcom + +DIRS = + +OBJS = $(CPPSRCS:.cpp=.o) + +EX_LIBS = \ + $(DIST)/lib/libraptorgfx.a \ + $(DIST)/lib/libraptorbase.a \ + $(DIST)/lib/libxpcom.a \ + $(DIST)/lib/libplc21.a \ + $(DIST)/lib/libplds21.a \ + $(DIST)/lib/libnspr21.a \ + $(NULL) + +PROGS = $(addprefix $(OBJDIR)/, $(CPPSRCS:.cpp=)) + +TARGETS = $(PROGS) + +include $(DEPTH)/config/rules.mk + +$(OBJDIR)/%.o: %.cpp + @$(MAKE_OBJDIR) + $(CCC) -o $@ $(CFLAGS) -c $*.cpp + +$(PROGS):$(OBJDIR)/%: $(OBJDIR)/%.o $(EX_LIBS) + @$(MAKE_OBJDIR) + $(CCC) -o $@ $@.o $(LDFLAGS) $(EX_LIBS) $(OS_LIBS) + +export:: + +install:: $(TARGETS) + $(INSTALL) $(TARGETS) $(DIST)/bin + diff --git a/mozilla/gfx/tests/TestColorNames.cpp b/mozilla/gfx/tests/TestColorNames.cpp new file mode 100644 index 00000000000..3b439222635 --- /dev/null +++ b/mozilla/gfx/tests/TestColorNames.cpp @@ -0,0 +1,113 @@ +/* -*- 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 +#include "nsColorNames.h" +#include "prprf.h" + +static const char* kJunkNames[] = { + nsnull, + "", + "123", + "backgroundz", + "zzzzzz", + "#@$&@#*@*$@$#" +}; + +int main(int argc, char** argv) +{ + PRInt32 id; + int rv = 0; + + // First make sure we can find all of the tags that are supposed to + // be in the table. Futz with the case to make sure any case will + // work + const nsColorNames::NameTableEntry* et = &nsColorNames::kNameTable[0]; + const nsColorNames::NameTableEntry* end = &nsColorNames::kNameTable[COLOR_MAX]; + while (et < end) { + // Lookup color by name and make sure it has the right id + char tagName[100]; + id = nsColorNames::LookupName(et->name); + if (id < 0) { + printf("bug: can't find '%s'\n", et->name); + rv = -1; + } + if (et->id != id) { + printf("bug: name='%s' et->id=%d id=%d\n", et->name, et->id, id); + rv = -1; + } + + // fiddle with the case to make sure we can still find it + strcpy(tagName, et->name); + tagName[0] = tagName[0] - 32; + id = nsColorNames::LookupName(tagName); + if (id < 0) { + printf("bug: can't find '%s'\n", tagName); + rv = -1; + } + if (et->id != id) { + printf("bug: name='%s' et->id=%d id=%d\n", et->name, et->id, id); + rv = -1; + } + + // Check that color lookup by name gets the right rgb value + nscolor rgb; + if (!NS_ColorNameToRGB(et->name, &rgb)) { + printf("bug: name='%s' didn't NS_ColorNameToRGB\n", et->name); + rv = -1; + } + if (nsColorNames::kColors[et->id] != rgb) { + printf("bug: name='%s' ColorNameToRGB=%x kColors[%d]=%x\n", + et->name, rgb, nsColorNames::kColors[et->id]); + rv = -1; + } + + // Check that parsing an RGB value in hex gets the right values + PRUint8 r = NS_GET_R(rgb); + PRUint8 g = NS_GET_G(rgb); + PRUint8 b = NS_GET_B(rgb); + char cbuf[50]; + PR_snprintf(cbuf, sizeof(cbuf), "#%02x%02x%02x", r, g, b); + nscolor hexrgb; + if (!NS_HexToRGB(cbuf, &hexrgb)) { + printf("bug: hex conversion to color of '%s' failed\n", cbuf); + rv = -1; + } + if (!NS_HexToRGB(cbuf + 1, &hexrgb)) { + printf("bug: hex conversion to color of '%s' failed\n", cbuf); + rv = -1; + } + if (hexrgb != rgb) { + printf("bug: rgb=%x hexrgb=%x\n", rgb, hexrgb); + rv = -1; + } + et++; + } + + // Now make sure we don't find some garbage + for (int i = 0; i < sizeof(kJunkNames) / sizeof(const char*); i++) { + const char* tag = kJunkNames[i]; + id = nsColorNames::LookupName(tag); + if (id >= 0) { + printf("bug: found '%s'\n", tag ? tag : "(null)"); + rv = -1; + } + } + + return 0; +} diff --git a/mozilla/gfx/tests/TestRect.cpp b/mozilla/gfx/tests/TestRect.cpp new file mode 100644 index 00000000000..bdcacc3757b --- /dev/null +++ b/mozilla/gfx/tests/TestRect.cpp @@ -0,0 +1,403 @@ +/* -*- 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 "nsRect.h" +#include +#ifdef XP_PC +#include +#endif + +static PRBool +TestConstructors() +{ + // Create a rectangle + nsRect rect1(10, 20, 30, 40); + + // Make sure the rectangle was properly initialized + if ((rect1.x != 10) || (rect1.y != 20) || + (rect1.width != 30) || (rect1.height != 40)) { + printf("rect initialization failed!\n"); + return PR_FALSE; + } + + // Create a second rect using the copy constructor + nsRect rect2(rect1); + + // Make sure the rectangle was properly initialized + if ((rect2.x != rect1.x) || (rect2.y != rect1.y) || + (rect2.width != rect1.width) || (rect2.height != rect1.height)) { + printf("rect copy constructor failed!\n"); + return PR_FALSE; + } + + return PR_TRUE; +} + +static PRBool +TestEqualityOperator() +{ + nsRect rect1(10, 20, 30, 40); + nsRect rect2(rect1); + + // Test the equality operator + if (!(rect1 == rect2)) { + printf("rect equality operator failed!\n"); + return PR_FALSE; + } + + // Test the inequality operator + if (rect1 != rect2) { + printf("rect inequality operator failed!\n"); + return PR_FALSE; + } + + return PR_TRUE; +} + +static PRBool +TestContainment() +{ + nsRect rect1(10, 10, 50, 50); + + // Test the point containment methods + // + + // Basic test of a point in the middle of the rect + if (!rect1.Contains(rect1.x + rect1.width/2, rect1.y + rect1.height/2)) { + printf("point containment test #1 failed!\n"); + return PR_FALSE; + } + + // Test against a point at the left/top edges + if (!rect1.Contains(rect1.x, rect1.y)) { + printf("point containment test #2 failed!\n"); + return PR_FALSE; + } + + // Test against a point at the right/bottom extents + if (rect1.Contains(rect1.XMost(), rect1.YMost())) { + printf("point containment test #3 failed!\n"); + return PR_FALSE; + } + + // Test the rect containment methods + // + nsRect rect2(rect1); + + // Test against a rect that's the same as rect1 + if (!rect1.Contains(rect2)) { + printf("rect containment test #1 failed!\n"); + return PR_FALSE; + } + + // Test against a rect whose left edge (only) is outside of rect1 + rect2.x--; + if (rect1.Contains(rect2)) { + printf("rect containment test #2 failed!\n"); + return PR_FALSE; + } + rect2.x++; + + // Test against a rect whose top edge (only) is outside of rect1 + rect2.y--; + if (rect1.Contains(rect2)) { + printf("rect containment test #3 failed!\n"); + return PR_FALSE; + } + rect2.y++; + + // Test against a rect whose right edge (only) is outside of rect1 + rect2.x++; + if (rect1.Contains(rect2)) { + printf("rect containment test #2 failed!\n"); + return PR_FALSE; + } + rect2.x--; + + // Test against a rect whose bottom edge (only) is outside of rect1 + rect2.y++; + if (rect1.Contains(rect2)) { + printf("rect containment test #3 failed!\n"); + return PR_FALSE; + } + rect2.y--; + + return PR_TRUE; +} + +// Test the method that returns a boolean result but doesn't return a +// a rectangle +static PRBool +TestIntersects() +{ + nsRect rect1(10, 10, 50, 50); + nsRect rect2(rect1); + + // Test against a rect that's the same as rect1 + if (!rect1.Intersects(rect2)) { + printf("rect intersects test #1 failed!\n"); + return PR_FALSE; + } + + // Test against a rect that's enclosed by rect1 + rect2.Deflate(1, 1); + if (!rect1.Contains(rect2) || !rect1.Intersects(rect2)) { + printf("rect intersects test #2 failed!\n"); + return PR_FALSE; + } + rect2.Inflate(1, 1); + + // Make sure inflate and deflate worked correctly + if (rect1 != rect2) { + printf("rect inflate or deflate failed!\n"); + return PR_FALSE; + } + + // Test against a rect that overlaps the left edge of rect1 + rect2.x--; + if (!rect1.Intersects(rect2)) { + printf("rect containment test #3 failed!\n"); + return PR_FALSE; + } + rect2.x++; + + // Test against a rect that's outside of rect1 on the left + rect2.x -= rect2.width; + if (rect1.Intersects(rect2)) { + printf("rect containment test #4 failed!\n"); + return PR_FALSE; + } + rect2.x += rect2.width; + + // Test against a rect that overlaps the top edge of rect1 + rect2.y--; + if (!rect1.Intersects(rect2)) { + printf("rect containment test #5 failed!\n"); + return PR_FALSE; + } + rect2.y++; + + // Test against a rect that's outside of rect1 on the top + rect2.y -= rect2.height; + if (rect1.Intersects(rect2)) { + printf("rect containment test #6 failed!\n"); + return PR_FALSE; + } + rect2.y += rect2.height; + + // Test against a rect that overlaps the right edge of rect1 + rect2.x++; + if (!rect1.Intersects(rect2)) { + printf("rect containment test #7 failed!\n"); + return PR_FALSE; + } + rect2.x--; + + // Test against a rect that's outside of rect1 on the right + rect2.x += rect2.width; + if (rect1.Intersects(rect2)) { + printf("rect containment test #8 failed!\n"); + return PR_FALSE; + } + rect2.x -= rect2.width; + + // Test against a rect that overlaps the bottom edge of rect1 + rect2.y++; + if (!rect1.Intersects(rect2)) { + printf("rect containment test #9 failed!\n"); + return PR_FALSE; + } + rect2.y--; + + // Test against a rect that's outside of rect1 on the bottom + rect2.y += rect2.height; + if (rect1.Intersects(rect2)) { + printf("rect containment test #10 failed!\n"); + return PR_FALSE; + } + rect2.y -= rect2.height; + + return PR_TRUE; +} + +// Test the method that returns a boolean result and an intersection rect +static PRBool +TestIntersection() +{ + nsRect rect1(10, 10, 50, 50); + nsRect rect2(rect1); + nsRect dest; + + // Test against a rect that's the same as rect1 + if (!dest.IntersectRect(rect1, rect2) || (dest != rect1)) { + printf("rect intersection test #1 failed!\n"); + return PR_FALSE; + } + + // Test against a rect that's enclosed by rect1 + rect2.Deflate(1, 1); + if (!dest.IntersectRect(rect1, rect2) || (dest != rect2)) { + printf("rect intersection test #2 failed!\n"); + return PR_FALSE; + } + rect2.Inflate(1, 1); + + // Test against a rect that overlaps the left edge of rect1 + rect2.x--; + if (!dest.IntersectRect(rect1, rect2) || + (dest != nsRect(rect1.x, rect1.y, rect1.width - 1, rect1.height))) { + printf("rect intersection test #3 failed!\n"); + return PR_FALSE; + } + rect2.x++; + + // Test against a rect that's outside of rect1 on the left + rect2.x -= rect2.width; + if (dest.IntersectRect(rect1, rect2)) { + printf("rect intersection test #4 failed!\n"); + return PR_FALSE; + } + rect2.x += rect2.width; + + // Test against a rect that overlaps the top edge of rect1 + rect2.y--; + if (!dest.IntersectRect(rect1, rect2) || + (dest != nsRect(rect1.x, rect1.y, rect1.width, rect1.height - 1))) { + printf("rect intersection test #5 failed!\n"); + return PR_FALSE; + } + rect2.y++; + + // Test against a rect that's outside of rect1 on the top + rect2.y -= rect2.height; + if (dest.IntersectRect(rect1, rect2)) { + printf("rect intersection test #6 failed!\n"); + return PR_FALSE; + } + rect2.y += rect2.height; + + // Test against a rect that overlaps the right edge of rect1 + rect2.x++; + if (!dest.IntersectRect(rect1, rect2) || + (dest != nsRect(rect1.x + 1, rect1.y, rect1.width - 1, rect1.height))) { + printf("rect intersection test #7 failed!\n"); + return PR_FALSE; + } + rect2.x--; + + // Test against a rect that's outside of rect1 on the right + rect2.x += rect2.width; + if (dest.IntersectRect(rect1, rect2)) { + printf("rect intersection test #8 failed!\n"); + return PR_FALSE; + } + rect2.x -= rect2.width; + + // Test against a rect that overlaps the bottom edge of rect1 + rect2.y++; + if (!dest.IntersectRect(rect1, rect2) || + (dest != nsRect(rect1.x, rect1.y + 1, rect1.width, rect1.height - 1))) { + printf("rect intersection test #9 failed!\n"); + return PR_FALSE; + } + rect2.y--; + + // Test against a rect that's outside of rect1 on the bottom + rect2.y += rect2.height; + if (dest.IntersectRect(rect1, rect2)) { + printf("rect intersection test #10 failed!\n"); + return PR_FALSE; + } + rect2.y -= rect2.height; + + return PR_TRUE; +} + +static PRBool +TestUnion() +{ + nsRect rect1; + nsRect rect2(10, 10, 50, 50); + nsRect dest; + + // Check the case where the receiver is an empty rect + rect1.Empty(); + if (!dest.UnionRect(rect1, rect2) || (dest != rect2)) { + printf("rect union test #1 failed!\n"); + return PR_FALSE; + } + + // Check the case where the source rect is an empty rect + rect1 = rect2; + rect2.Empty(); + if (!dest.UnionRect(rect1, rect2) || (dest != rect1)) { + printf("rect union test #2 failed!\n"); + return PR_FALSE; + } + + // Test the case where both rects are empty. This should fail + rect1.Empty(); + rect2.Empty(); + if (dest.UnionRect(rect1, rect2)) { + printf("rect union test #3 failed!\n"); + return PR_FALSE; + } + + // Test union case where the two rects don't overlap at all + rect1.SetRect(10, 10, 50, 50); + rect2.SetRect(100, 100, 50, 50); + if (!dest.UnionRect(rect1, rect2) || + (dest != nsRect(rect1.x, rect1.y, rect2.XMost() - rect1.x, rect2.YMost() - rect1.y))) { + printf("rect union test #4 failed!\n"); + return PR_FALSE; + } + + // Test union case where the two rects overlap + rect1.SetRect(30, 30, 50, 50); + rect2.SetRect(10, 10, 50, 50); + if (!dest.UnionRect(rect1, rect2) || + (dest != nsRect(rect2.x, rect2.y, rect1.XMost() - rect2.x, rect1.YMost() - rect2.y))) { + printf("rect union test #5 failed!\n"); + return PR_FALSE; + } + + return PR_TRUE; +} + +int main(int argc, char** argv) +{ + if (!TestConstructors()) + return -1; + + if (!TestEqualityOperator()) + return -1; + + if (!TestContainment()) + return -1; + + if (!TestIntersects()) + return -1; + + if (!TestIntersection()) + return -1; + + if (!TestUnion()) + return -1; + + return 0; +} diff --git a/mozilla/gfx/tests/btest/BitTest.cpp b/mozilla/gfx/tests/btest/BitTest.cpp new file mode 100644 index 00000000000..17ad2777257 --- /dev/null +++ b/mozilla/gfx/tests/btest/BitTest.cpp @@ -0,0 +1,666 @@ +/* -*- 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. + */ + +//we need openfilename stuff... MMP +#ifdef WIN32_LEAN_AND_MEAN +#undef WIN32_LEAN_AND_MEAN +#endif + +#include "prtypes.h" +#include +#include "resources.h" +#include "nsIImageManager.h" +#include "nsIImageGroup.h" +#include "nsIImageRequest.h" +#include "nsIImageObserver.h" +#include "nsIRenderingContext.h" +#include "nsIImage.h" +#include "nsIWidget.h" +#include "nsGUIEvent.h" +#include "nsRect.h" +#include "nsWidgetsCID.h" +#include "nsGfxCIID.h" +#include "nsFont.h" + +static NS_DEFINE_IID(kIWidgetIID, NS_IWIDGET_IID); +static NS_DEFINE_IID(kIImageObserverIID, NS_IIMAGEREQUESTOBSERVER_IID); + +static NS_DEFINE_IID(kCWindowIID, NS_WINDOW_CID); +static NS_DEFINE_IID(kCChildWindowIID, NS_CHILD_CID); +static NS_DEFINE_IID(kCScrollbarIID, NS_VERTSCROLLBAR_CID); + +static char* class1Name = "ImageTest"; + +static HANDLE gInstance, gPrevInstance; +static nsIImageManager *gImageManager = nsnull; +static nsIImageGroup *gImageGroup = nsnull; +static nsIImageRequest *gImageReq = nsnull; +static HWND gHwnd; +static nsIWidget *gWindow = nsnull; +static nsIImage *gImage = nsnull; +static PRBool gInstalledColorMap = PR_FALSE; + +extern PRInt32 speedtest(nsIImage *aTheImage,nsIRenderingContext *aSurface, PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight); +extern PRInt32 drawtest(nsIRenderingContext *aSurface); +extern PRInt32 filltest(nsIRenderingContext *aSurface); +extern PRInt32 arctest(nsIRenderingContext *aSurface); + +class MyObserver : public nsIImageRequestObserver +{ +public: + MyObserver(); + ~MyObserver(); + + NS_DECL_ISUPPORTS + + virtual void Notify(nsIImageRequest *aImageRequest,nsIImage *aImage, + nsImageNotification aNotificationType, + PRInt32 aParam1, PRInt32 aParam2,void *aParam3); + + virtual void NotifyError(nsIImageRequest *aImageRequest,nsImageError aErrorType); + +}; + +//------------------------------------------------------------ + +MyObserver::MyObserver() +{ +} + +//------------------------------------------------------------ + +MyObserver::~MyObserver() +{ +} + +//------------------------------------------------------------ + +NS_IMPL_ISUPPORTS(MyObserver, kIImageObserverIID) + +void +MyObserver::Notify(nsIImageRequest *aImageRequest, + nsIImage *aImage, + nsImageNotification aNotificationType, + PRInt32 aParam1, PRInt32 aParam2, + void *aParam3) +{ + switch (aNotificationType) + { + case nsImageNotification_kDimensions: + { + char buffer[40]; + sprintf(buffer, "Image:%d x %d", aParam1, aParam2); + ::SetWindowText(gHwnd, buffer); + } + break; + + case nsImageNotification_kPixmapUpdate: + case nsImageNotification_kImageComplete: + case nsImageNotification_kFrameComplete: + { + if (gImage == nsnull && aImage) + { + gImage = aImage; + NS_ADDREF(aImage); + } + + if (!gInstalledColorMap && gImage) + { + nsColorMap *cmap = gImage->GetColorMap(); + + if (cmap != nsnull && cmap->NumColors > 0) + { + gWindow->SetColorMap(cmap); + } + gInstalledColorMap = PR_TRUE; + } + nsRect *rect = (nsRect *)aParam3; + nsIRenderingContext *drawCtx = gWindow->GetRenderingContext(); + + if (gImage) + { + drawCtx->DrawImage(gImage, 0, 0, gImage->GetWidth(), gImage->GetHeight()); + } + } + break; + } +} + +//------------------------------------------------------------ + +// This tests the speed for the bliting, +PRInt32 +speedtest(nsIImage *aTheImage,nsIRenderingContext *aSurface, PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight,PRBool aOptimize) +{ +PRUint32 min,seconds,milli,i; +SYSTEMTIME thetime; + + printf("\nSTARTING TIMING TEST\n"); + ::GetSystemTime(&thetime); + min = thetime.wMinute; + seconds = thetime.wSecond; + milli = thetime.wMilliseconds; + + if(aOptimize==PR_TRUE) + aTheImage->Optimize(aSurface); + + for(i=0;i<200;i++) + aSurface->DrawImage(aTheImage,aX,aY,aWidth,aHeight); + + ::GetSystemTime(&thetime); + min = thetime.wMinute-min; + if(min>0) + min = min*60; + seconds = min+thetime.wSecond-seconds; + if(seconds>0) + seconds = (seconds*1000)+thetime.wMilliseconds; + else + seconds = thetime.wMilliseconds; + milli=seconds-milli; + + if(aOptimize==PR_TRUE) + printf("The Optimized Blitting Time was %lu Milliseconds\n",milli); + else + printf("The Non-Optimized Blitting Time was %lu Milliseconds\n",milli); + + return(milli); +} +//------------------------------------------------------------ + +PRInt32 +arctest(nsIRenderingContext *aSurface) +{ +nsFont *font; +nscolor white,black; + + font = new nsFont("Times", NS_FONT_STYLE_NORMAL,NS_FONT_VARIANT_NORMAL,NS_FONT_WEIGHT_BOLD,0,12); + aSurface->SetFont(*font); + + // clear surface + NS_ColorNameToRGB("white", &white); + NS_ColorNameToRGB("red", &black); + aSurface->SetColor(white); + aSurface->FillRect(0,0,1000,1000); + aSurface->SetColor(black); + + aSurface->DrawArc(20, 20,50,100,(float)0.0,(float)90.0); + aSurface->FillArc(70, 20,50,100,(float)0.0,(float)90.0); + aSurface->DrawArc(150, 20,50,100,(float)90.0,(float)0.0); + aSurface->DrawString("0 to 90\0",20,8,30); + aSurface->DrawString("Reverse (eg 90 to 0)\0",120,8,30); + + aSurface->DrawArc(20, 140,100,50,(float)130.0,(float)180.0); + aSurface->FillArc(70, 140,100,50,(float)130.0,(float)180.0); + aSurface->DrawArc(150, 140,100,50,(float)180.0,(float)130.0); + aSurface->DrawString("130 to 180\0",20,130,30); + + aSurface->DrawArc(20, 200,50,100,(float)170.0,(float)300.0); + aSurface->FillArc(70, 200,50,100,(float)170.0,(float)300.0); + aSurface->DrawArc(150, 200,50,100,(float)300.0,(float)170.0); + aSurface->DrawString("170 to 300\0",20,190,30); + + + return(30); +} + +//------------------------------------------------------------ + +PRInt32 +drawtest(nsIRenderingContext *aSurface) +{ +nsFont *font; +nsPoint *pointlist; +nscolor white,black; + + font = new nsFont("Times", NS_FONT_STYLE_NORMAL,NS_FONT_VARIANT_NORMAL,NS_FONT_WEIGHT_BOLD,0,12); + aSurface->SetFont(*font); + + + // clear surface + NS_ColorNameToRGB("white", &white); + NS_ColorNameToRGB("black", &black); + aSurface->SetColor(white); + aSurface->FillRect(0,0,1000,1000); + aSurface->SetColor(black); + + aSurface->DrawRect(20, 20, 100, 100); + aSurface->DrawString("This is a Rectangle\0",20,5,30); + + aSurface->DrawLine(0,0,300,400); + + pointlist = new nsPoint[6]; + pointlist[0].x = 150;pointlist[0].y = 150; + pointlist[1].x = 200;pointlist[1].y = 150; + pointlist[2].x = 190;pointlist[2].y = 170; + pointlist[3].x = 210;pointlist[3].y = 190; + pointlist[4].x = 175;pointlist[4].y = 175; + pointlist[5].x = 150;pointlist[5].y = 150; + aSurface->DrawPolygon(pointlist,6); + aSurface->DrawString("This is a closed Polygon\0",210,150,30); + delete [] pointlist; + +#ifdef WINDOWSBROKEN + pointlist = new nsPoint[5]; + pointlist[0].x = 200;pointlist[0].y = 200; + pointlist[1].x = 250;pointlist[1].y = 200; + pointlist[2].x = 240;pointlist[2].y = 220; + pointlist[3].x = 260;pointlist[3].y = 240; + pointlist[4].x = 225;pointlist[4].y = 225; + aSurface->DrawPolygon(pointlist,6); + aSurface->DrawString("This is an open Polygon\0",250,200,30); + delete [] pointlist; +#endif + + aSurface->DrawEllipse(30, 150,50,100); + aSurface->DrawString("This is an Ellipse\0",30,140,30); + + + return(30); +} + +//------------------------------------------------------------ + +PRInt32 +filltest(nsIRenderingContext *aSurface) +{ +nsFont *font; +nsPoint *pointlist; +nscolor white,black; + + font = new nsFont("Times", NS_FONT_STYLE_NORMAL,NS_FONT_VARIANT_NORMAL,NS_FONT_WEIGHT_BOLD,0,12); + aSurface->SetFont(*font); + + // clear surface + NS_ColorNameToRGB("white", &white); + NS_ColorNameToRGB("black", &black); + aSurface->SetColor(white); + aSurface->FillRect(0,0,1000,1000); + aSurface->SetColor(black); + + aSurface->FillRect(20, 20, 100, 100); + aSurface->DrawString("This is a Rectangle\0",20,5,30); + + pointlist = new nsPoint[6]; + pointlist[0].x = 150;pointlist[0].y = 150; + pointlist[1].x = 200;pointlist[1].y = 150; + pointlist[2].x = 190;pointlist[2].y = 170; + pointlist[3].x = 210;pointlist[3].y = 190; + pointlist[4].x = 175;pointlist[4].y = 175; + pointlist[5].x = 150;pointlist[5].y = 150; + aSurface->FillPolygon(pointlist,6); + aSurface->DrawString("This is a closed Polygon\0",210,150,30); + delete [] pointlist; + + +#ifdef WINDOWSBROKEN + pointlist = new nsPoint[5]; + pointlist[0].x = 200;pointlist[0].y = 200; + pointlist[1].x = 250;pointlist[1].y = 200; + pointlist[2].x = 240;pointlist[2].y = 220; + pointlist[3].x = 260;pointlist[3].y = 240; + pointlist[4].x = 225;pointlist[4].y = 225; + aSurface->FillPolygon(pointlist,6); + aSurface->DrawString("This is an open Polygon\0",250,200,30); + delete [] pointlist; +#endif + + aSurface->FillEllipse(30, 150,50,100); + aSurface->DrawString("This is an Ellipse\0",30,140,30); + + return(30); +} + +//------------------------------------------------------------ + +void +MyObserver::NotifyError(nsIImageRequest *aImageRequest, + nsImageError aErrorType) +{ + ::MessageBox(NULL, "Image loading error!",class1Name, MB_OK); +} + +nsEventStatus PR_CALLBACK +MyHandleEvent(nsGUIEvent *aEvent) +{ + nsEventStatus result = nsEventStatus_eConsumeNoDefault; + switch(aEvent->message) + { + case NS_PAINT: + { + // paint the background + nsIRenderingContext *drawCtx = ((nsPaintEvent*)aEvent)->renderingContext; + drawCtx->SetColor(aEvent->widget->GetBackgroundColor()); + drawCtx->FillRect(*(((nsPaintEvent*)aEvent)->rect)); + if (gImage) + { + drawCtx->DrawImage(gImage, 0, 0, gImage->GetWidth(), gImage->GetHeight()); + } + return nsEventStatus_eConsumeNoDefault; + } + break; + } + + return nsEventStatus_eIgnore; +} + +//------------------------------------------------------------ + +void +MyReleaseImages() +{ + if (gImageReq) + { + NS_RELEASE(gImageReq); + gImageReq = NULL; + } + if (gImage) + { + NS_RELEASE(gImage); + gImage = NULL; + } + + gInstalledColorMap = PR_FALSE; +} + +//------------------------------------------------------------ + +void +MyInterrupt() +{ + if (gImageGroup) + { + gImageGroup->Interrupt(); + } +} + +//------------------------------------------------------------ + +#define FILE_URL_PREFIX "file://" + +void +MyLoadImage(char *aFileName) +{ + char fileURL[256]; + char *str; + + MyInterrupt(); + MyReleaseImages(); + + if (gImageGroup == NULL) + { + nsIRenderingContext *drawCtx = gWindow->GetRenderingContext(); + if (NS_NewImageGroup(&gImageGroup) != NS_OK || gImageGroup->Init(drawCtx) != NS_OK) + { + ::MessageBox(NULL, "Couldn't create image group",class1Name, MB_OK); + NS_RELEASE(drawCtx); + return; + } + NS_RELEASE(drawCtx); + } + + strcpy(fileURL, FILE_URL_PREFIX); + strcpy(fileURL + strlen(FILE_URL_PREFIX), aFileName); + + str = fileURL; + while ((str = strchr(str, '\\')) != NULL) + *str = '/'; + + nscolor white; + MyObserver *observer = new MyObserver(); + + NS_ColorNameToRGB("white", &white); + gImageReq = gImageGroup->GetImage(fileURL,observer,white, 0, 0, 0); + if (gImageReq == NULL) + { + ::MessageBox(NULL, "Couldn't create image request",class1Name, MB_OK); + } +} + +//------------------------------------------------------------ + +PRBool +OpenFileDialog(char *aBuffer, int32 aBufLen) +{ + BOOL result = FALSE; + OPENFILENAME ofn; + + // *.js is the standard File Name on the Save/Open Dialog + ::strcpy(aBuffer, "*.gif;*.png;*.jpg;*.jpeg"); + + // fill the OPENFILENAME sruct + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = gHwnd; + ofn.hInstance = gInstance; + ofn.lpstrFilter = "All Images (*.gif,*.png,*.jpg,*.jpeg)\0*.gif;*png;*.jpg;*.jpeg\0GIF Files (*.gif)\0*.gif\0PNG Files (*.png)\0*.png\0JPEG Files (*.jpg,*.jpeg)\0*.jpg;*.jpeg\0All Files\0*.*\0\0"; + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 1; // the first one in lpstrFilter + ofn.lpstrFile = aBuffer; // contains the file path name on return + ofn.nMaxFile = aBufLen; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; // use default + ofn.lpstrTitle = NULL; // use default + ofn.Flags = OFN_CREATEPROMPT | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST; + ofn.nFileOffset = 0; + ofn.nFileExtension = 0; + ofn.lpstrDefExt = "gif"; // default extension is .js + ofn.lCustData = NULL; + ofn.lpfnHook = NULL; + ofn.lpTemplateName = NULL; + + // call the open file dialog or the save file dialog according to aIsOpenDialog + result = ::GetOpenFileName(&ofn); + + return (PRBool)result; +} + +//------------------------------------------------------------ + +long PASCAL +WndProc(HWND hWnd, UINT msg, WPARAM param, LPARAM lparam) +{ + HMENU hMenu; + + switch (msg) + { + case WM_COMMAND: + hMenu = GetMenu(hWnd); + + switch (LOWORD(param)) + { + case TIMER_OPEN: + { + char szFile[256]; + + if (!OpenFileDialog(szFile, 256)) + return 0L; + MyLoadImage(szFile); + break; + } + case TIMER_EXIT: + ::DestroyWindow(hWnd); + exit(0); + break; + case BSTNOOPT: + case BSTOPT: + + if(gImageGroup == NULL) // go get an image + { + char szFile[256]; + + ::MessageBox(NULL, "Need To Open an Image",NULL, MB_OK); + + if (!OpenFileDialog(szFile, 256)) + return 0L; + MyLoadImage(szFile); + } + if(gImageGroup != NULL && gImage) + { + PRBool opt; + nsIRenderingContext *drawCtx = gWindow->GetRenderingContext(); + + if(LOWORD(param) == BSTNOOPT) + opt = PR_FALSE; + else + opt = PR_TRUE; + speedtest(gImage,drawCtx, 0, 0, gImage->GetWidth(), gImage->GetHeight(),opt); + } + break; + case DRAWTEST: + if(gWindow) + { + nsIRenderingContext *drawCtx = gWindow->GetRenderingContext(); + drawtest(drawCtx); + } + break; + case FILLTEST: + if(gWindow) + { + nsIRenderingContext *drawCtx = gWindow->GetRenderingContext(); + filltest(drawCtx); + } + break; + case ARCTEST: + if(gWindow) + { + nsIRenderingContext *drawCtx = gWindow->GetRenderingContext(); + arctest(drawCtx); + } + break; + default: + break; + } + break; + + case WM_CREATE: + // Initialize image library + if (NS_NewImageManager(&gImageManager) != NS_OK||gImageManager->Init() != NS_OK) + { + ::MessageBox(NULL, "Can't initialize the image library",class1Name, MB_OK); + } + gImageManager->SetCacheSize(1024*1024); + break; + + case WM_DESTROY: + MyInterrupt(); + MyReleaseImages(); + if (gImageGroup != nsnull) + { + NS_RELEASE(gImageGroup); + } + if (gImageManager != nsnull) + { + NS_RELEASE(gImageManager); + } + PostQuitMessage(0); + break; + + default: + break; + } + + return DefWindowProc(hWnd, msg, param, lparam); +} + +//------------------------------------------------------------ + +static HWND CreateTopLevel(const char* clazz, const char* title,int aWidth, int aHeight) +{ + // Create a simple top level window + HWND window = ::CreateWindowEx(WS_EX_CLIENTEDGE, + clazz, title, + WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN, + CW_USEDEFAULT, CW_USEDEFAULT, + aWidth, aHeight, + HWND_DESKTOP, + NULL, + gInstance, + NULL); + + nsRect rect(0, 0, aWidth, aHeight); + + nsresult rv = NSRepository::CreateInstance(kCChildWindowIID, NULL, kIWidgetIID, (void**)&gWindow); + + if (NS_OK == rv) + { + gWindow->Create((nsNativeWindow)window, rect, MyHandleEvent, NULL); + } + + ::ShowWindow(window, SW_SHOW); + ::UpdateWindow(window); + return window; +} + +#define WIDGET_DLL "raptorwidget.dll" +#define GFXWIN_DLL "raptorgfxwin.dll" + +//------------------------------------------------------------ + +int PASCAL +WinMain(HANDLE instance, HANDLE prevInstance, LPSTR cmdParam, int nCmdShow) +{ + gInstance = instance; + + NSRepository::RegisterFactory(kCWindowIID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCChildWindowIID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCScrollbarIID, WIDGET_DLL, PR_FALSE, PR_FALSE); + + static NS_DEFINE_IID(kCRenderingContextIID, NS_RENDERING_CONTEXT_CID); + static NS_DEFINE_IID(kCDeviceContextIID, NS_DEVICE_CONTEXT_CID); + static NS_DEFINE_IID(kCFontMetricsIID, NS_FONT_METRICS_CID); + static NS_DEFINE_IID(kCImageIID, NS_IMAGE_CID); + + NSRepository::RegisterFactory(kCRenderingContextIID, GFXWIN_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCDeviceContextIID, GFXWIN_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCFontMetricsIID, GFXWIN_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCImageIID, GFXWIN_DLL, PR_FALSE, PR_FALSE); + + if (!prevInstance) { + WNDCLASS wndClass; + wndClass.style = 0; + wndClass.lpfnWndProc = WndProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = 0; + wndClass.hInstance = gInstance; + wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); + wndClass.hbrBackground = (HBRUSH) GetStockObject(LTGRAY_BRUSH); + wndClass.lpszMenuName = class1Name; + wndClass.lpszClassName = class1Name; + RegisterClass(&wndClass); + } + + // Create our first top level window + HWND gHwnd = CreateTopLevel(class1Name, "Graphics tester", 620, 400); + + // Process messages + MSG msg; + while (GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return msg.wParam; +} + +//------------------------------------------------------------ + +void main(int argc, char **argv) +{ + WinMain(GetModuleHandle(NULL), NULL, 0, SW_SHOW); +} diff --git a/mozilla/gfx/tests/btest/image.rc b/mozilla/gfx/tests/btest/image.rc new file mode 100644 index 00000000000..3cdc2c203ce --- /dev/null +++ b/mozilla/gfx/tests/btest/image.rc @@ -0,0 +1,38 @@ +/* + * 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 "resources.h" + +IMAGETEST MENU DISCARDABLE +{ + POPUP "File" + { + MENUITEM "Open...", TIMER_OPEN + MENUITEM "Exit", TIMER_EXIT + } + + + POPUP "TEST" + { + MENUITEM "BST NO Opt.",BSTNOOPT + MENUITEM "BST Opt.",BSTOPT + MENUITEM "Draw Test",DRAWTEST + MENUITEM "Fill Test",FILLTEST + MENUITEM "Arc Test",ARCTEST + } + +} diff --git a/mozilla/gfx/tests/btest/makefile.win b/mozilla/gfx/tests/btest/makefile.win new file mode 100644 index 00000000000..a772c20c26d --- /dev/null +++ b/mozilla/gfx/tests/btest/makefile.win @@ -0,0 +1,62 @@ +#!nmake +# +# 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. + +DEPTH=..\..\.. + +MAKE_OBJ_TYPE = EXE +PROG0 = .\$(OBJDIR)\BitTest.exe +RESFILE = image.res +PROGRAMS = $(PROG0) + +LINCS=-I$(XPDIST)\public\raptor -I$(XPDIST)\public\xpcom -I..\src + +LLIBS= \ + $(DIST)\lib\raptorbase.lib \ + $(DIST)\lib\raptorgfx.lib \ + $(DIST)\lib\xpcom32.lib \ + $(LIBNSPR) \ + $(DIST)\lib\libplc21.lib \ + $(DIST)\lib\img3240.lib \ + $(DIST)\lib\util.lib \ + comdlg32.lib \ + $(RESFILE) + +include <$(DEPTH)\config\rules.mak> + +install:: $(PROGRAMS) + $(MAKE_INSTALL) $(PROG0) $(DIST)\bin + +clobber:: + rm -f $(DIST)\bin\BitTest.exe + +# Move this into config/obj.inc when it's allowed +.cpp{.\$(OBJDIR)\}.exe: + $(CC) @<<$(CFGFILE) + $(CFLAGS) + $(LCFLAGS) + $(LINCS) + $(LINCS_1) + $(INCS) + $(LLIBS) + $(OS_LIBS) + -Fd$(PBDFILE) + -Fe.\$(OBJDIR)\ + -Fo.\$(OBJDIR)\ + $(CURDIR)$(*B).cpp +<< + +$(PROG0): $(OBJDIR) BitTest.cpp $(RESFILE) diff --git a/mozilla/gfx/tests/btest/resource.h b/mozilla/gfx/tests/btest/resource.h new file mode 100644 index 00000000000..add8e1bc098 --- /dev/null +++ b/mozilla/gfx/tests/btest/resource.h @@ -0,0 +1,31 @@ +/* -*- 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. + */ + +#define ID_MENUITEM40001 40001 +#define ID_MENUITEM40002 40002 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40003 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/mozilla/gfx/tests/btest/resources.h b/mozilla/gfx/tests/btest/resources.h new file mode 100644 index 00000000000..531eb822aac --- /dev/null +++ b/mozilla/gfx/tests/btest/resources.h @@ -0,0 +1,31 @@ +/* -*- 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. + */ + +#ifndef resources_h___ +#define resources_h___ + +#define TIMER_OPEN 40010 +#define TIMER_EXIT 40011 + +#define BSTNOOPT 40012 +#define BSTOPT 40013 +#define DRAWTEST 40014 +#define FILLTEST 40015 +#define ARCTEST 40016 + +#endif /* resources_h___ */ diff --git a/mozilla/gfx/tests/makefile.win b/mozilla/gfx/tests/makefile.win new file mode 100644 index 00000000000..96ee7947d33 --- /dev/null +++ b/mozilla/gfx/tests/makefile.win @@ -0,0 +1,70 @@ +#!nmake +# +# 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. + +DEPTH=..\.. +IGNORE_MANIFEST=1 + +DIRS = btest + +MAKE_OBJ_TYPE = EXE +PROG1 = .\$(OBJDIR)\TestRect.exe +PROG2 = .\$(OBJDIR)\TestColorNames.exe +PROG3 = .\$(OBJDIR)\DumpColors.exe +PROGRAMS = $(PROG1) $(PROG2) $(PROG3) + +LINCS=-I$(XPDIST)\public\raptor -I$(XPDIST)\public\xpcom -I..\src + +LLIBS= \ + $(DIST)\lib\raptorbase.lib \ + $(DIST)\lib\raptorgfx.lib \ + $(DIST)\lib\xpcom32.lib \ + $(LIBNSPR) \ + $(DIST)\lib\libplc21.lib + +include <$(DEPTH)\config\rules.mak> + +install:: $(PROGRAMS) + $(MAKE_INSTALL) $(PROG1) $(DIST)\bin + $(MAKE_INSTALL) $(PROG2) $(DIST)\bin + $(MAKE_INSTALL) $(PROG3) $(DIST)\bin + +clobber:: + rm -f $(DIST)\bin\TestRect.exe + rm -f $(DIST)\bin\TestColorNames.exe + rm -f $(DIST)\bin\DumpColors.exe + +# Move this into config/obj.inc when it's allowed +.cpp{.\$(OBJDIR)\}.exe: + $(CC) @<<$(CFGFILE) + $(CFLAGS) + $(LCFLAGS) + $(LINCS) + $(LINCS_1) + $(INCS) + $(LLIBS) + $(OS_LIBS) + -Fd$(PBDFILE) + -Fe.\$(OBJDIR)\ + -Fo.\$(OBJDIR)\ + $(CURDIR)$(*B).cpp +<< + +$(PROG1): $(OBJDIR) TestRect.cpp + +$(PROG2): $(OBJDIR) TestColorNames.cpp + +$(PROG3): $(OBJDIR) DumpColors.cpp diff --git a/mozilla/htmlparser/Makefile b/mozilla/htmlparser/Makefile new file mode 100644 index 00000000000..831fd742c9a --- /dev/null +++ b/mozilla/htmlparser/Makefile @@ -0,0 +1,27 @@ +#!gmake +# +# 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. + +DEPTH = .. + +# Don't try to build robot just yet +# DIRS = src robot + +DIRS = src + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/htmlparser/makefile.win b/mozilla/htmlparser/makefile.win new file mode 100644 index 00000000000..78a595cef67 --- /dev/null +++ b/mozilla/htmlparser/makefile.win @@ -0,0 +1,23 @@ +#!nmake +# +# 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. + +DEPTH=.. +IGNORE_MANIFEST=1 + +DIRS = src + +include <$(DEPTH)\config\rules.mak> diff --git a/mozilla/htmlparser/robot/Makefile b/mozilla/htmlparser/robot/Makefile new file mode 100644 index 00000000000..c87a607607f --- /dev/null +++ b/mozilla/htmlparser/robot/Makefile @@ -0,0 +1,54 @@ +#!gmake +# +# 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. + +DEPTH = ../../.. + +include $(DEPTH)/config/config.mk + +CPPSRCS = \ + RobotMain.cpp \ + nsRobotSink.cpp \ + $(NULL) + +REQUIRES=xpcom raptor + +OBJS = $(CPPSRCS:.cpp=.o) + +EX_LIBS = \ + $(DIST)/lib/libraptorbase.a \ + $(DIST)/lib/libraptorhtmlpars.a \ + $(DIST)/lib/libnetlib.a \ + $(DIST)/lib/libpref.a \ + $(DIST)/lib/libxp.a \ + $(DIST)/lib/libjs.a \ + $(DIST)/lib/libxpcom.a \ + $(DIST)/lib/libplc21.a \ + $(DIST)/lib/libplds21.a \ + $(DIST)/lib/libnspr21.a \ + -lXm \ + -lm \ + $(NULL) + +PROG = htmlrobot + +$(PROG):$(OBJS) + @$(MAKE_OBJDIR) + $(CCC) -o $@ $(OBJS) $(LDFLAGS) $(EX_LIBS) $(OS_LIBS) + +TARGETS = $(PROG) + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/htmlparser/robot/RobotMain.cpp b/mozilla/htmlparser/robot/RobotMain.cpp new file mode 100644 index 00000000000..db3237ae05e --- /dev/null +++ b/mozilla/htmlparser/robot/RobotMain.cpp @@ -0,0 +1,111 @@ +/* -*- 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 "nsIRobotSink.h" +#include "nsIRobotSinkObserver.h" +#include "nsIParser.h" +#include "nsVoidArray.h" +#include "nsString.h" +#include "nsIURL.h" + +static nsVoidArray* gWorkList; + +static NS_DEFINE_IID(kIRobotSinkObserverIID, NS_IROBOTSINKOBSERVER_IID); + +class RobotSinkObserver : public nsIRobotSinkObserver { +public: + RobotSinkObserver() { + NS_INIT_REFCNT(); + } + + ~RobotSinkObserver() { + } + + NS_DECL_ISUPPORTS + + NS_IMETHOD ProcessLink(const nsString& aURLSpec); +}; + +NS_IMPL_ISUPPORTS(RobotSinkObserver, kIRobotSinkObserverIID); + +NS_IMETHODIMP RobotSinkObserver::ProcessLink(const nsString& aURLSpec) +{ + fputs(aURLSpec, stdout); + printf("\n"); + return NS_OK; +} + +//---------------------------------------------------------------------- + +int main(int argc, char **argv) +{ + gWorkList = new nsVoidArray(); + + int i; + for (i = 1; i < argc; i++) { + gWorkList->AppendElement(new nsString(argv[i])); + } + + RobotSinkObserver* myObserver = new RobotSinkObserver(); + NS_ADDREF(myObserver); + + for (;;) { + PRInt32 n = gWorkList->Count(); + if (0 == n) { + break; + } + nsString* urlName = (nsString*) gWorkList->ElementAt(n - 1); + gWorkList->RemoveElementAt(n - 1); + + // Create url + nsIURL* url; + nsresult rv = NS_NewURL(&url, *urlName); + if (NS_OK != rv) { + printf("invalid URL: '"); + fputs(*urlName, stdout); + printf("'\n"); + return -1; + } + delete urlName; + + nsIParser* parser; + rv = NS_NewHTMLParser(&parser); + if (NS_OK != rv) { + printf("can't make parser\n"); + return -1; + } + + nsIRobotSink* sink; + rv = NS_NewRobotSink(&sink); + if (NS_OK != rv) { + printf("can't make parser\n"); + return -1; + } + sink->Init(url); + sink->AddObserver(myObserver); + + parser->SetContentSink(sink); + parser->Parse(url); + NS_RELEASE(sink); + NS_RELEASE(parser); + NS_RELEASE(url); + } + + NS_RELEASE(myObserver); + + return 0; +} diff --git a/mozilla/htmlparser/robot/makefile.win b/mozilla/htmlparser/robot/makefile.win new file mode 100644 index 00000000000..c64ca35aaf8 --- /dev/null +++ b/mozilla/htmlparser/robot/makefile.win @@ -0,0 +1,62 @@ +#!nmake +# +# 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. + +DEPTH=..\..\.. +IGNORE_MANIFEST=1 + +MAKE_OBJ_TYPE = EXE +PROGRAM = .\$(OBJDIR)\htmlrobot.exe + +MISCDEP= \ + $(DIST)\lib\raptorhtmlpars.lib \ + $(DIST)\lib\xpcom32.lib \ + $(LIBNSPR) \ + $(DIST)\lib\libplc21.lib \ + $(NULL) + +MYLIBS= \ + $(DIST)\lib\raptorhtmlpars.lib \ + $(DIST)\lib\raptorbase.lib \ + $(DIST)\lib\xpcom32.lib \ + $(LIBNSPR) \ + $(DIST)\lib\libplc21.lib \ + $(NULL) + +LLIBS= $(MYLIBS) \ + shell32.lib \ + -SUBSYSTEM:CONSOLE + +DEFINES=-D_IMPL_NS_HTMLPARS + +CPPSRCS= \ + nsRobotSink.cpp \ + RobotMain.cpp \ + $(NULL) + +CPP_OBJS= \ + .\$(OBJDIR)\nsRobotSink.obj \ + .\$(OBJDIR)\RobotMain.obj + +LINCS=-I$(XPDIST)\public\xpcom -I$(XPDIST)\public\raptor -I..\src + +include <$(DEPTH)\config\rules.mak> + +install:: $(PROGRAM) + $(MAKE_INSTALL) $(PROGRAM) $(DIST)\bin + +clobber:: + rm -f $(DIST)\bin\htmlrobot.exe diff --git a/mozilla/htmlparser/robot/nsIRobotSink.h b/mozilla/htmlparser/robot/nsIRobotSink.h new file mode 100644 index 00000000000..0b53655ef08 --- /dev/null +++ b/mozilla/htmlparser/robot/nsIRobotSink.h @@ -0,0 +1,39 @@ +/* -*- 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. + */ +#ifndef nsIRobotSink_h___ +#define nsIRobotSink_h___ + +#include "nsIHTMLContentSink.h" +class nsIURL; +class nsIRobotSinkObserver; + +/* 61256800-cfd8-11d1-9328-00805f8add32 */ +#define NS_IROBOTSINK_IID \ +{ 0x61256800, 0xcfd8, 0x11d1, \ + {0x93, 0x28, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +class nsIRobotSink : public nsIHTMLContentSink { +public: + NS_IMETHOD Init(nsIURL* aDocumentURL) = 0; + NS_IMETHOD AddObserver(nsIRobotSinkObserver* aObserver) = 0; + NS_IMETHOD RemoveObserver(nsIRobotSinkObserver* aObserver) = 0; +}; + +extern nsresult NS_NewRobotSink(nsIRobotSink** aInstancePtrResult); + +#endif /* nsIRobotSink_h___ */ diff --git a/mozilla/htmlparser/robot/nsIRobotSinkObserver.h b/mozilla/htmlparser/robot/nsIRobotSinkObserver.h new file mode 100644 index 00000000000..da30b85edd6 --- /dev/null +++ b/mozilla/htmlparser/robot/nsIRobotSinkObserver.h @@ -0,0 +1,34 @@ +/* -*- 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. + */ +#ifndef nsIRobotSinkObserver_h___ +#define nsIRobotSinkObserver_h___ + +#include "nsISupports.h" +class nsString; + +/* fab1d970-cfda-11d1-9328-00805f8add32 */ +#define NS_IROBOTSINKOBSERVER_IID \ +{ 0xfab1d970, 0xcfda, 0x11d1, \ + {0x93, 0x28, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +class nsIRobotSinkObserver : public nsISupports { +public: + NS_IMETHOD ProcessLink(const nsString& aURLSpec) = 0; +}; + +#endif /* nsIRobotSinkObserver_h___ */ diff --git a/mozilla/htmlparser/robot/nsRobotSink.cpp b/mozilla/htmlparser/robot/nsRobotSink.cpp new file mode 100644 index 00000000000..e346c3d9bc0 --- /dev/null +++ b/mozilla/htmlparser/robot/nsRobotSink.cpp @@ -0,0 +1,285 @@ +/* -*- 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 "nsIRobotSink.h" +#include "nsIRobotSinkObserver.h" +#include "nsIParserNode.h" +#include "nsString.h" +#include "nsIURL.h" +#include "nsCRT.h" +#include "nsVoidArray.h" +class nsIDocument; + +// TODO +// - add in base tag support +// - get links from other sources: +// - LINK tag +// - STYLE SRC +// - IMG SRC +// - LAYER SRC + +static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); +static NS_DEFINE_IID(kIHTMLContentSinkIID, NS_IHTMLCONTENTSINK_IID); +static NS_DEFINE_IID(kIRobotSinkIID, NS_IROBOTSINK_IID); + +class RobotSink : public nsIRobotSink { +public: + RobotSink(); + ~RobotSink(); + + void* operator new(size_t size) { + void* rv = ::operator new(size); + nsCRT::zero(rv, size); + return (void*) rv; + } + + // nsISupports + NS_DECL_ISUPPORTS + + // nsIHTMLContentSink + virtual PRBool SetTitle(const nsString& aValue); + virtual PRBool OpenHTML(const nsIParserNode& aNode); + virtual PRBool CloseHTML(const nsIParserNode& aNode); + virtual PRBool OpenHead(const nsIParserNode& aNode); + virtual PRBool CloseHead(const nsIParserNode& aNode); + virtual PRBool OpenBody(const nsIParserNode& aNode); + virtual PRBool CloseBody(const nsIParserNode& aNode); + virtual PRBool OpenForm(const nsIParserNode& aNode); + virtual PRBool CloseForm(const nsIParserNode& aNode); + virtual PRBool OpenFrameset(const nsIParserNode& aNode); + virtual PRBool CloseFrameset(const nsIParserNode& aNode); + virtual PRBool OpenContainer(const nsIParserNode& aNode); + virtual PRBool CloseContainer(const nsIParserNode& aNode); + virtual PRBool CloseTopmostContainer(); + virtual PRBool AddLeaf(const nsIParserNode& aNode); + + // nsIRobotSink + NS_IMETHOD Init(nsIURL* aDocumentURL); + NS_IMETHOD AddObserver(nsIRobotSinkObserver* aObserver); + NS_IMETHOD RemoveObserver(nsIRobotSinkObserver* aObserver); + + void ProcessLink(const nsString& aLink); + +protected: + nsIURL* mDocumentURL; + nsVoidArray mObservers; +}; + +nsresult NS_NewRobotSink(nsIRobotSink** aInstancePtrResult) +{ + RobotSink* it = new RobotSink(); + return it->QueryInterface(kIRobotSinkIID, (void**) aInstancePtrResult); +} + +RobotSink::RobotSink() +{ +} + +RobotSink::~RobotSink() +{ + NS_IF_RELEASE(mDocumentURL); + PRInt32 i, n = mObservers.Count(); + for (i = 0; i < n; i++) { + nsIRobotSinkObserver* cop = (nsIRobotSinkObserver*)mObservers.ElementAt(i); + NS_RELEASE(cop); + } +} + +NS_IMPL_ADDREF(RobotSink); + +NS_IMPL_RELEASE(RobotSink); + +NS_IMETHODIMP RobotSink::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if (NULL == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kIRobotSinkIID)) { + *aInstancePtr = (void*) this; + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIHTMLContentSinkIID)) { + *aInstancePtr = (void*) this; + AddRef(); + return NS_OK; + } + if (aIID.Equals(kISupportsIID)) { + *aInstancePtr = (void*) ((nsISupports*)this); + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +PRBool RobotSink::SetTitle(const nsString& aValue) +{ + return PR_TRUE; +} + +PRBool RobotSink::OpenHTML(const nsIParserNode& aNode) +{ + return PR_TRUE; +} + +PRBool RobotSink::CloseHTML(const nsIParserNode& aNode) +{ + return PR_TRUE; +} + +PRBool RobotSink::OpenHead(const nsIParserNode& aNode) +{ + return PR_TRUE; +} + +PRBool RobotSink::CloseHead(const nsIParserNode& aNode) +{ + return PR_TRUE; +} + +PRBool RobotSink::OpenBody(const nsIParserNode& aNode) +{ + return PR_TRUE; +} + +PRBool RobotSink::CloseBody(const nsIParserNode& aNode) +{ + return PR_TRUE; +} + +PRBool RobotSink::OpenForm(const nsIParserNode& aNode) +{ + return PR_TRUE; +} + +PRBool RobotSink::CloseForm(const nsIParserNode& aNode) +{ + return PR_TRUE; +} + +PRBool RobotSink::OpenFrameset(const nsIParserNode& aNode) +{ + return PR_TRUE; +} + +PRBool RobotSink::CloseFrameset(const nsIParserNode& aNode) +{ + return PR_TRUE; +} + +PRBool RobotSink::OpenContainer(const nsIParserNode& aNode) +{ + nsAutoString tmp(aNode.GetText()); + tmp.ToUpperCase(); + if (tmp.Equals("A")) { + nsAutoString k, v; + PRInt32 ac = aNode.GetAttributeCount(); + for (PRInt32 i = 0; i < ac; i++) { + // Get upper-cased key + const nsString& key = aNode.GetKeyAt(i); + k.Truncate(); + k.Append(key); + k.ToUpperCase(); + if (k.Equals("HREF")) { + // Get value and remove mandatory quotes + v.Truncate(); + v.Append(aNode.GetValueAt(i)); + PRUnichar first = v.First(); + if ((first == '"') || (first == '\'')) { + if (v.Last() == first) { + v.Cut(0, 1); + PRInt32 pos = v.Length() - 1; + if (pos >= 0) { + v.Cut(pos, 1); + } + } else { + // Mismatched quotes - leave them in + } + } + ProcessLink(v); + } + } + } + return PR_TRUE; +} + +PRBool RobotSink::CloseContainer(const nsIParserNode& aNode) +{ + return PR_TRUE; +} + +PRBool RobotSink::CloseTopmostContainer() +{ + return PR_TRUE; +} + +PRBool RobotSink::AddLeaf(const nsIParserNode& aNode) +{ + return PR_TRUE; +} + +NS_IMETHODIMP RobotSink::Init(nsIURL* aDocumentURL) +{ + NS_IF_RELEASE(mDocumentURL); + mDocumentURL = aDocumentURL; + NS_IF_ADDREF(aDocumentURL); + return NS_OK; +} + +NS_IMETHODIMP RobotSink::AddObserver(nsIRobotSinkObserver* aObserver) +{ + if (mObservers.AppendElement(aObserver)) { + NS_ADDREF(aObserver); + return NS_OK; + } + return NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP RobotSink::RemoveObserver(nsIRobotSinkObserver* aObserver) +{ + if (mObservers.RemoveElement(aObserver)) { + NS_RELEASE(aObserver); + return NS_OK; + } + //XXX return NS_ERROR_NOT_FOUND; + return NS_OK; +} + +void RobotSink::ProcessLink(const nsString& aLink) +{ + nsAutoString absURLSpec(aLink); + + // Make link absolute + // XXX base tag handling + nsIURL* docURL = mDocumentURL; + if (nsnull != docURL) { + nsIURL* absurl; + nsresult rv = NS_NewURL(&absurl, docURL, aLink); + if (NS_OK == rv) { + absURLSpec.Truncate(); + absurl->ToString(absURLSpec); + NS_RELEASE(absurl); + } + } + + // Now give link to robot observers + PRInt32 i, n = mObservers.Count(); + for (i = 0; i < n; i++) { + nsIRobotSinkObserver* cop = (nsIRobotSinkObserver*)mObservers.ElementAt(i); + cop->ProcessLink(absURLSpec); + } +} diff --git a/mozilla/htmlparser/src/Makefile b/mozilla/htmlparser/src/Makefile new file mode 100644 index 00000000000..bc43cfbe641 --- /dev/null +++ b/mozilla/htmlparser/src/Makefile @@ -0,0 +1,54 @@ +#!gmake +# +# 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. + +DEPTH = ../.. + +LIBRARY_NAME = raptorhtmlpars + +DEFINES = -D_IMPL_NS_HTMLPARS + +CPPSRCS = \ + nsDeque.cpp \ + nsHTMLContentSink.cpp \ + nsHTMLDelegate.cpp \ + nsHTMLParser.cpp \ + nsHTMLTokens.cpp \ + nsParserNode.cpp \ + nsScanner.cpp \ + nsToken.cpp \ + nsTokenizer.cpp \ + nsDefaultTokenHandler.cpp \ + nsHTMLDTD.cpp \ + $(NULL) + +EXPORTS = \ + nshtmlpars.h \ + nsIContentSink.h \ + nsIHTMLContentSink.h \ + nsHTMLTokens.h \ + nsIParserNode.h \ + nsIParser.h \ + nsToken.h \ + $(NULL) + +MODULE = raptor + +REQUIRES = xpcom raptor + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/htmlparser/src/SelfTest.cpp b/mozilla/htmlparser/src/SelfTest.cpp new file mode 100644 index 00000000000..d0c5bcb47ae --- /dev/null +++ b/mozilla/htmlparser/src/SelfTest.cpp @@ -0,0 +1,188 @@ +/* -*- 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. + */ + + +//Testing stream crap... + +#include +#include +#include + +#include "nsISupports.h" +#include "nsTokenizer.h" +#include "nsHTMLDelegate.h" +#include "nsIParser.h" +#include "nsHTMLContentSink.h" + +ofstream filelist("filelist.out"); + +PRBool compareFiles(const char* file1,const char* file2,int& failpos) { + PRBool result=PR_TRUE; + PRBool done=PR_FALSE; + char ch1,ch2; + int eof1,eof2; + + ifstream input1(file1,ios::in && ios::binary,filebuf::openprot); + ifstream input2(file2,ios::in && ios::binary,filebuf::openprot); + input1.setmode(filebuf::binary); + input2.setmode(filebuf::binary); + failpos=-1; + + while(!done) { + + while(!(eof1=input1.eof())) { + input1.read(&ch1,1); + if(failpos>4225) { + int x=failpos; + } + failpos++; + char* p=strchr(" \t\r\n\b",ch1); + if(!p) + break; + } + + while(!(eof2=input2.eof())) { + input2.read(&ch2,1); + char* p=strchr(" \t\r\n\b",ch2); + if(!p) + break; + } + + if(eof1==eof2) { + if(eof1) + done=PR_TRUE; + else if(ch1!=ch2) { + done=PR_TRUE; + result=PR_FALSE; + + } + } + else done=PR_TRUE; + } + return result; +} + + +/**------------------------------------------------------- + * LAST MODS: gess + * + * @param + * @return + *------------------------------------------------------*/ +void parseFile (const char* aFilename,int size) +{ + //debug + //aFilename="s:\\ns\\raptor\\parser\\tests\\html\\home01.html"; + //aFilename="c:\\temp\\sun\\test00000.html"; + //aFilename="c:\\windows\\temp\\test.html"; + aFilename="s:\\readHTML-VC\\test.html"; + //aFilename="c:\\temp\\sun\\commentbug.html"; + + + char filename[_MAX_PATH]; + strcpy(filename,aFilename); + strcat(filename,".tokens"); + { + nsIParser* parser; + nsresult rv = NS_NewHTMLParser(&parser); + nsresult r=NS_NewHTMLParser(&parser); + CHTMLContentSink theSink; + parser->setContentSink(&theSink); + parser->parse(aFilename); + parser->Release(); + } + + int failpos=0; + + if(!compareFiles(aFilename,filename,failpos)) { + filelist << "FAILED: " << aFilename << "[" << failpos << "]" << endl; + } +} + + +/**------------------------------------------------------- + * LAST MODS: gess + * + * @param + * @return + *------------------------------------------------------*/ +int walkDirectoryTree(char* aPath) { + int result=0; + char fullPath[_MAX_PATH]; + struct _finddata_t c_file; + long hFile; + + strcpy(fullPath,aPath); + strcat(fullPath,"\\*.*"); + /* Find first .c file in current directory */ + if((hFile = _findfirst( fullPath, &c_file )) == -1L ) + printf( "No matching files in current directory!\n" ); + else { + + PRBool done=PR_FALSE; + while(!done) { + if(c_file.attrib & _A_SUBDIR) { + if(strlen(c_file.name)>2){ + char newPath[_MAX_PATH]; + strcpy(newPath,aPath); + strcat(newPath,"\\"); + strcat(newPath,c_file.name); + walkDirectoryTree(newPath); + } + } + else { + int len=strlen(c_file.name); + if(len>5) { + if(0==strnicmp(&c_file.name[len-5],".HTML",5)) { + char filepath[_MAX_PATH]; + strcpy(filepath,aPath); + strcat(filepath,"\\"); + strcat(filepath,c_file.name); + parseFile(filepath,c_file.size); + } + } + } + if(_findnext( hFile, &c_file )!=0) + done=PR_TRUE; + } + _findclose( hFile ); + } + return 0; +} + + +/**------------------------------------------------------- + * LAST MODS: gess + * + * @param + * @return + *------------------------------------------------------*/ +int main(int argc, char* argv []) +{ + int result=0; + char buffer[_MAX_PATH]; + + if(argc==2) + strcpy(buffer,argv[1]); + else _getcwd(buffer,_MAX_PATH); + walkDirectoryTree(buffer); + return 0; +} + + + diff --git a/mozilla/htmlparser/src/makefile.win b/mozilla/htmlparser/src/makefile.win new file mode 100644 index 00000000000..9b7637349c6 --- /dev/null +++ b/mozilla/htmlparser/src/makefile.win @@ -0,0 +1,66 @@ +#!nmake +# +# 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. + +DEPTH=..\.. +IGNORE_MANIFEST=1 + +LIBRARY_NAME=raptorhtmlpars +DEFINES=-D_IMPL_NS_HTMLPARS +MODULE=raptor +REQUIRES=xpcom raptor + +CPPSRCS=nsDeque.cpp nsHTMLContentSink.cpp nsHTMLDelegate.cpp nsHTMLDTD.cpp \ + nsHTMLParser.cpp nsHTMLTokens.cpp nsParserNode.cpp nsScanner.cpp \ + nsToken.cpp nsTokenizer.cpp nsDefaultTokenHandler.cpp + +EXPORTS=nshtmlpars.h nsIContentSink.h nsIHTMLContentSink.h \ + nsHTMLTokens.h nsIParserNode.h nsIParser.h nsToken.h + +CPP_OBJS=.\$(OBJDIR)\nsDeque.obj .\$(OBJDIR)\nsHTMLContentSink.obj \ + .\$(OBJDIR)\nsHTMLDelegate.obj .\$(OBJDIR)\nsHTMLParser.obj \ + .\$(OBJDIR)\nsHTMLDTD.obj \ + .\$(OBJDIR)\nsHTMLTokens.obj .\$(OBJDIR)\nsParserNode.obj \ + .\$(OBJDIR)\nsScanner.obj .\$(OBJDIR)\nsToken.obj \ + .\$(OBJDIR)\nsTokenizer.obj .\$(OBJDIR)\nsDefaultTokenHandler.obj + +LINCS=-I$(XPDIST)\public\xpcom -I$(XPDIST)\public\raptor + +MAKE_OBJ_TYPE = DLL +DLLNAME = raptorhtmlpars +DLL=.\$(OBJDIR)\$(DLLNAME).dll + +LCFLAGS = \ + $(LCFLAGS) \ + $(DEFINES) \ + $(NULL) + +# These are the libraries we need to link with to create the dll +LLIBS= \ + $(DIST)\lib\xpcom32.lib \ + $(DIST)\lib\raptorbase.lib \ + $(DIST)\lib\libplc21.lib \ + $(LIBNSPR) + +include <$(DEPTH)\config\rules.mak> + +libs:: $(DLL) + $(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).dll $(DIST)\bin + $(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).lib $(DIST)\lib + +clobber:: + rm -f $(DIST)\bin\$(DLLNAME).dll + rm -f $(DIST)\lib\$(DLLNAME).lib diff --git a/mozilla/htmlparser/src/nsDefaultTokenHandler.cpp b/mozilla/htmlparser/src/nsDefaultTokenHandler.cpp new file mode 100644 index 00000000000..c4460ea1f33 --- /dev/null +++ b/mozilla/htmlparser/src/nsDefaultTokenHandler.cpp @@ -0,0 +1,637 @@ +/* -*- 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. + */ + + +/** + * MODULE NOTES: + * @update gess 4/1/98 + * + */ + + +#include "nsDefaultTokenHandler.h" +#include "nsHTMLParser.h" +#include "nsHTMLTokens.h" +#include "nsDebug.h" + +static const char* kNullParserGiven = "Error: Null parser given as argument"; + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +CDefaultTokenHandler::CDefaultTokenHandler(eHTMLTokenTypes aType) { + mType=aType; +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +CDefaultTokenHandler::~CDefaultTokenHandler(){ +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +eHTMLTokenTypes CDefaultTokenHandler::GetTokenType(void){ + return mType; +} + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool CDefaultTokenHandler::CanHandle(eHTMLTokenTypes aType){ + PRBool result=PR_FALSE; + return result; +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool CDefaultTokenHandler::operator()(CToken* aToken,nsHTMLParser* aParser){ + NS_ASSERTION(0!=aParser,kNullParserGiven); + PRBool result=PR_FALSE; + if(aParser){ + result=PR_TRUE; + } + return result; +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +CStartTokenHandler::CStartTokenHandler() : CDefaultTokenHandler(eToken_start) { +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +CStartTokenHandler::~CStartTokenHandler(){ +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool CStartTokenHandler::operator()(CToken* aToken,nsHTMLParser* aParser){ + NS_ASSERTION(0!=aParser,kNullParserGiven); + if(aParser){ + return aParser->HandleStartToken(aToken); + } + return PR_FALSE; +} + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool CStartTokenHandler::CanHandle(eHTMLTokenTypes aType){ + PRBool result=PR_FALSE; + return result; +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +CEndTokenHandler::CEndTokenHandler(): CDefaultTokenHandler(eToken_end) { +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +CEndTokenHandler::~CEndTokenHandler(){ +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool CEndTokenHandler::operator()(CToken* aToken,nsHTMLParser* aParser){ + NS_ASSERTION(0!=aParser,kNullParserGiven); + if(aParser){ + return aParser->HandleEndToken(aToken); + } + return PR_FALSE; +} + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool CEndTokenHandler::CanHandle(eHTMLTokenTypes aType){ + PRBool result=PR_FALSE; + return result; +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +CCommentTokenHandler::CCommentTokenHandler() : CDefaultTokenHandler(eToken_comment) { +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +CCommentTokenHandler::~CCommentTokenHandler(){ +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool CCommentTokenHandler::operator()(CToken* aToken,nsHTMLParser* aParser){ + NS_ASSERTION(0!=aParser,kNullParserGiven); + if(aParser){ + return aParser->HandleCommentToken(aToken); + } + return PR_FALSE; +} + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool CCommentTokenHandler::CanHandle(eHTMLTokenTypes aType){ + PRBool result=PR_FALSE; + return result; +} + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +CEntityTokenHandler::CEntityTokenHandler() : CDefaultTokenHandler(eToken_entity) { +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +CEntityTokenHandler::~CEntityTokenHandler() { +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool CEntityTokenHandler::operator()(CToken* aToken,nsHTMLParser* aParser){ + NS_ASSERTION(0!=aParser,kNullParserGiven); + if(aParser){ + return aParser->HandleEntityToken(aToken); + } + return PR_FALSE; +} + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool CEntityTokenHandler::CanHandle(eHTMLTokenTypes aType){ + PRBool result=PR_FALSE; + return result; +} + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +CWhitespaceTokenHandler::CWhitespaceTokenHandler() : CDefaultTokenHandler(eToken_whitespace) { +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +CWhitespaceTokenHandler::~CWhitespaceTokenHandler(){ +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool CWhitespaceTokenHandler::operator()(CToken* aToken,nsHTMLParser* aParser){ + NS_ASSERTION(0!=aParser,kNullParserGiven); + if(aParser){ + return aParser->HandleWhitespaceToken(aToken); + } + return PR_FALSE; +} + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool CWhitespaceTokenHandler::CanHandle(eHTMLTokenTypes aType){ + PRBool result=PR_FALSE; + return result; +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +CNewlineTokenHandler::CNewlineTokenHandler() : CDefaultTokenHandler(eToken_newline) { +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +CNewlineTokenHandler::~CNewlineTokenHandler(){ +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool CNewlineTokenHandler::operator()(CToken* aToken,nsHTMLParser* aParser){ + NS_ASSERTION(0!=aParser,kNullParserGiven); + if(aParser){ + return aParser->HandleNewlineToken(aToken); + } + return PR_FALSE; +} + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool CNewlineTokenHandler::CanHandle(eHTMLTokenTypes aType){ + PRBool result=PR_FALSE; + return result; +} + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +CTextTokenHandler::CTextTokenHandler() : CDefaultTokenHandler(eToken_text) { +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +CTextTokenHandler::~CTextTokenHandler(){ +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool CTextTokenHandler::operator()(CToken* aToken,nsHTMLParser* aParser){ + NS_ASSERTION(0!=aParser,kNullParserGiven); + if(aParser){ + return aParser->HandleTextToken(aToken); + } + return PR_FALSE; +} + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool CTextTokenHandler::CanHandle(eHTMLTokenTypes aType){ + PRBool result=PR_FALSE; + return result; +} + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +CAttributeTokenHandler::CAttributeTokenHandler() : CDefaultTokenHandler(eToken_attribute) { +} + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +CAttributeTokenHandler::~CAttributeTokenHandler(){ +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool CAttributeTokenHandler::operator()(CToken* aToken,nsHTMLParser* aParser){ + NS_ASSERTION(0!=aParser,kNullParserGiven); + if(aParser){ + return aParser->HandleAttributeToken(aToken); + } + return PR_FALSE; +} + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool CAttributeTokenHandler::CanHandle(eHTMLTokenTypes aType){ + PRBool result=PR_FALSE; + return result; +} + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +CScriptTokenHandler::CScriptTokenHandler() : CDefaultTokenHandler(eToken_script) { +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +CScriptTokenHandler::~CScriptTokenHandler(){ +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool CScriptTokenHandler::operator()(CToken* aToken,nsHTMLParser* aParser){ + NS_ASSERTION(0!=aParser,kNullParserGiven); + if(aParser){ + return aParser->HandleScriptToken(aToken); + } + return PR_FALSE; +} + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool CScriptTokenHandler::CanHandle(eHTMLTokenTypes aType){ + PRBool result=PR_FALSE; + return result; +} + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +CStyleTokenHandler::CStyleTokenHandler() : CDefaultTokenHandler(eToken_style) { +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +CStyleTokenHandler::~CStyleTokenHandler(){ +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool CStyleTokenHandler::operator()(CToken* aToken,nsHTMLParser* aParser){ + NS_ASSERTION(0!=aParser,kNullParserGiven); + if(aParser){ + return aParser->HandleStyleToken(aToken); + } + return PR_FALSE; +} + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool CStyleTokenHandler::CanHandle(eHTMLTokenTypes aType){ + PRBool result=PR_FALSE; + return result; +} + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +CSkippedContentTokenHandler::CSkippedContentTokenHandler() : CDefaultTokenHandler(eToken_skippedcontent) { +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +CSkippedContentTokenHandler::~CSkippedContentTokenHandler(){ +} + + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool CSkippedContentTokenHandler::operator()(CToken* aToken,nsHTMLParser* aParser){ + NS_ASSERTION(0!=aParser,kNullParserGiven); + if(aParser){ + return aParser->HandleSkippedContentToken(aToken); + } + return PR_FALSE; +} + +/**------------------------------------------------------- + * + * + * @update gess 4/2/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool CSkippedContentTokenHandler::CanHandle(eHTMLTokenTypes aType){ + PRBool result=PR_FALSE; + return result; +} diff --git a/mozilla/htmlparser/src/nsDefaultTokenHandler.h b/mozilla/htmlparser/src/nsDefaultTokenHandler.h new file mode 100644 index 00000000000..71dc3a267d1 --- /dev/null +++ b/mozilla/htmlparser/src/nsDefaultTokenHandler.h @@ -0,0 +1,161 @@ +/* -*- 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. + */ + +/** + * MODULE NOTES: + * @update gess 4/1/98 + * + */ + +#ifndef CDEFAULTTOKENHANDLER__ +#define CDEFAULTTOKENHANDLER__ + +#include "prtypes.h" +#include "nsString.h" +#include "nsHTMLTokens.h" +#include "nsITokenHandler.h" + +class CToken; +class nsHTMLParser; + + +class CDefaultTokenHandler : public CITokenHandler { +public: + CDefaultTokenHandler(eHTMLTokenTypes aType=eToken_unknown); + virtual ~CDefaultTokenHandler(); + + virtual eHTMLTokenTypes GetTokenType(void); + virtual PRBool operator()(CToken* aToken,nsHTMLParser* aParser); + virtual PRBool CanHandle(eHTMLTokenTypes aType); + +protected: + eHTMLTokenTypes mType; +}; + + +class CStartTokenHandler : public CDefaultTokenHandler { +public: + CStartTokenHandler(); + virtual ~CStartTokenHandler(); + + virtual PRBool operator()(CToken* aToken,nsHTMLParser* aParser); + virtual PRBool CanHandle(eHTMLTokenTypes aType); +}; + + +class CEndTokenHandler : public CDefaultTokenHandler { +public: + CEndTokenHandler(); + virtual ~CEndTokenHandler(); + + virtual PRBool operator()(CToken* aToken,nsHTMLParser* aParser); + virtual PRBool CanHandle(eHTMLTokenTypes aType); +}; + + +class CCommentTokenHandler : public CDefaultTokenHandler { +public: + CCommentTokenHandler(); + virtual ~CCommentTokenHandler(); + + virtual PRBool operator()(CToken* aToken,nsHTMLParser* aParser); + virtual PRBool CanHandle(eHTMLTokenTypes aType); +}; + + +class CEntityTokenHandler : public CDefaultTokenHandler { +public: + CEntityTokenHandler(); + virtual ~CEntityTokenHandler(); + + virtual PRBool operator()(CToken* aToken,nsHTMLParser* aParser); + virtual PRBool CanHandle(eHTMLTokenTypes aType); +}; + + +class CWhitespaceTokenHandler : public CDefaultTokenHandler { +public: + CWhitespaceTokenHandler(); + virtual ~CWhitespaceTokenHandler(); + + virtual PRBool operator()(CToken* aToken,nsHTMLParser* aParser); + virtual PRBool CanHandle(eHTMLTokenTypes aType); +}; + + +class CNewlineTokenHandler : public CDefaultTokenHandler { +public: + CNewlineTokenHandler(); + virtual ~CNewlineTokenHandler(); + + virtual PRBool operator()(CToken* aToken,nsHTMLParser* aParser); + virtual PRBool CanHandle(eHTMLTokenTypes aType); +}; + + +class CTextTokenHandler : public CDefaultTokenHandler { +public: + CTextTokenHandler(); + virtual ~CTextTokenHandler(); + + virtual PRBool operator()(CToken* aToken,nsHTMLParser* aParser); + virtual PRBool CanHandle(eHTMLTokenTypes aType); +}; + + +class CAttributeTokenHandler : public CDefaultTokenHandler { +public: + CAttributeTokenHandler(); + virtual ~CAttributeTokenHandler(); + + virtual PRBool operator()(CToken* aToken,nsHTMLParser* aParser); + virtual PRBool CanHandle(eHTMLTokenTypes aType); +}; + + +class CScriptTokenHandler : public CDefaultTokenHandler { +public: + CScriptTokenHandler(); + virtual ~CScriptTokenHandler(); + + virtual PRBool operator()(CToken* aToken,nsHTMLParser* aParser); + virtual PRBool CanHandle(eHTMLTokenTypes aType); +}; + + +class CStyleTokenHandler : public CDefaultTokenHandler { +public: + CStyleTokenHandler(); + virtual ~CStyleTokenHandler(); + + virtual PRBool operator()(CToken* aToken,nsHTMLParser* aParser); + virtual PRBool CanHandle(eHTMLTokenTypes aType); +}; + + +class CSkippedContentTokenHandler : public CDefaultTokenHandler { +public: + CSkippedContentTokenHandler(); + virtual ~CSkippedContentTokenHandler(); + + virtual PRBool operator()(CToken* aToken,nsHTMLParser* aParser); + virtual PRBool CanHandle(eHTMLTokenTypes aType); +}; + + +#endif diff --git a/mozilla/htmlparser/src/nsDeque.cpp b/mozilla/htmlparser/src/nsDeque.cpp new file mode 100644 index 00000000000..22ce66777b2 --- /dev/null +++ b/mozilla/htmlparser/src/nsDeque.cpp @@ -0,0 +1,226 @@ +/* -*- 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 "nsDeque.h" +#include "nsToken.h" + +const PRInt32 kGrowthDelta = 10; + +/**------------------------------------------------------- + * Standard constructor + * + * @updated gess 28Feb98 + * @param + * @return + *------------------------------------------------------*/ +CDeque::CDeque() { + mCapacity=kGrowthDelta; + mOrigin=mSize=0; + mTokens=new CToken*[mCapacity]; +} + +/**------------------------------------------------------- + * Standard destructor + * + * @updated gess 28Feb98 + * @param + * @return + *------------------------------------------------------*/ +CDeque::~CDeque() { + Erase(); + delete [] mTokens; +} + +/*------------------------------------------------------- + * Remove all items from the queue without destroying them. + * @updated gess 28Feb98 + * @param + * @return + *------------------------------------------------------*/ +void CDeque::Empty() { + for(PRInt32 i=0;i0) { + result=mTokens[mOrigin]; + mTokens[mOrigin++]=0; //zero it out for debugging purposes. + mSize--; + if(0==mSize) + mOrigin=0; + } + return result; +} + +/*------------------------------------------------------- + * Get the ith element (in relative terms) not absolute + * index pos. Don't forget the origin may be anywhere. + * + * @updated gess 28Feb98 + * @param anIndex: 0 relative index + * @return CToken* or null. + *------------------------------------------------------*/ +CToken* CDeque::ObjectAt(PRInt32 anIndex) { + CToken* result=0; + if((anIndex>=0) && (anIndexSetOrdinal(10); + CToken* b=new CToken(nsAutoString("")); b->SetOrdinal(20); + CToken* c=new CToken(nsAutoString("")); c->SetOrdinal(30); + CToken* d=new CToken(nsAutoString("")); d->SetOrdinal(40); + CToken* e=new CToken(nsAutoString("")); e->SetOrdinal(50); + CToken* f=new CToken(nsAutoString("")); f->SetOrdinal(60); + theDeck->Push(a); + theDeck->Push(b); + theDeck->Push(c); + CToken* temp=theDeck->Pop(); //temp should == a + temp=theDeck->Pop(); //temp should == b + theDeck->Push(d); + theDeck->Push(e); + + CDequeIterator iter1=theDeck->Begin(); + CDequeIterator iter2=theDeck->End(); + while(iter1!=iter2) { + temp=(iter1++); + cout << temp->GetOrdinal(); + } + + theDeck->Push(f); //should cause queue to resize and resequence. + CDequeIterator iter3=theDeck->Begin(); + CDequeIterator iter4=theDeck->End(); + while(iter3!=iter4) { + temp=(iter3++); + cout << temp->GetOrdinal(); + } + delete a; + delete b; + delete c; + delete d; + delete e; + delete f; + delete theDeck; +#endif +} + diff --git a/mozilla/htmlparser/src/nsDeque.h b/mozilla/htmlparser/src/nsDeque.h new file mode 100644 index 00000000000..4c9dc9be628 --- /dev/null +++ b/mozilla/htmlparser/src/nsDeque.h @@ -0,0 +1,108 @@ +/* -*- 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. + */ + +/** + * MODULE NOTES: + * @update gess 4/1/98 + * + * The easy queue is a very small, very efficient ring- + * buffer than can hold elements of type CToken*, offering + * the following features: + * It's interface supports pushing and poping of children. + * It can iterate (via an interator class) it's children. + * When full, it can efficently resize dynamically. + * + * Note that the only bit of trickery here is that like + * all ring buffers, the first element may not be at index[0]. + * The mOrigin member determines where the first child is. + * This point is quietly hidden from customers of this class. + * + * If we have an existing general-purpose queue, then it + * should be trivial to substitute that implementation for + * this one. If not, this can easily be made into a general + * purpose container (substitue void* for CToken*). + */ + + +#ifndef QUEUE +#define QUEUE + +#include "nsParserTypes.h" +#include "prtypes.h" + +class CToken; +class CDequeIterator; + +class CDeque { + public: + CDeque(); + ~CDeque(); + + PRInt32 GetSize() const {return mSize;} + void Push(CToken* aToken); + CToken* Pop(void); + CToken* PopBack(void); + CToken* ObjectAt(int anIndex); + void Empty(); + void Erase(); + + CDequeIterator Begin(); + CDequeIterator End(); + + static void SelfTest(); + + protected: + PRInt32 mSize; + PRInt32 mCapacity; + PRInt32 mOrigin; + CToken** mTokens; + + + private: + CDeque(const CDeque& other); + CDeque& operator=(const CDeque& other); +}; + +class CDequeIterator { + public: + CDequeIterator(CDeque& aQueue,int anIndex=0) : mDeque(aQueue) {mIndex=anIndex; } + CDequeIterator(const CDequeIterator& aCopy) : mDeque(aCopy.mDeque), mIndex(aCopy.mIndex) { } + + CDequeIterator& operator=(CDequeIterator& aCopy) { + //queue's are already equal. + mIndex=aCopy.mIndex; + return *this; + } + + PRBool operator!=(CDequeIterator& anIter) {return PRBool(!this->operator==(anIter));} + PRBool operator==(CDequeIterator& anIter) {return PRBool(((mIndex==anIter.mIndex) && (&mDeque==&anIter.mDeque)));} + CToken* operator++() {return mDeque.ObjectAt(++mIndex);} + CToken* operator++(int) {return mDeque.ObjectAt(mIndex++);} + CToken* operator--() {return mDeque.ObjectAt(--mIndex);} + CToken* operator--(int) {return mDeque.ObjectAt(mIndex--);} + CToken* operator*() {return mDeque.ObjectAt(mIndex);} + operator CToken*() {return mDeque.ObjectAt(mIndex);} + + + protected: + PRInt32 mIndex; + CDeque& mDeque; +}; + + +#endif diff --git a/mozilla/htmlparser/src/nsHTMLContentSink.cpp b/mozilla/htmlparser/src/nsHTMLContentSink.cpp new file mode 100644 index 00000000000..d44be23f6c8 --- /dev/null +++ b/mozilla/htmlparser/src/nsHTMLContentSink.cpp @@ -0,0 +1,428 @@ +/* -*- 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 "nsHTMLContentSink.h" +#include "nsHTMLTokens.h" +#include "prtypes.h" +#include + +#define VERBOSE_DEBUG + +static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); +static NS_DEFINE_IID(kIContentSinkIID, NS_ICONTENTSINK_IID); +static NS_DEFINE_IID(kIHTMLContentSinkIID, NS_IHTMLCONTENTSINK_IID); +static NS_DEFINE_IID(kClassIID, NS_HTMLCONTENTSINK_IID); + + + +/**------------------------------------------------------- + * "Fakey" factory method used to create an instance of + * this class. + * + * @updated gess 3/25/98 + * @param + * @return + *------------------------------------------------------*/ +nsresult NS_NewHTMLContentSink(nsIContentSink** aInstancePtrResult) +{ + nsHTMLContentSink *it = new nsHTMLContentSink(); + + if (it == 0) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(kClassIID, (void **) aInstancePtrResult); +} + + +/**------------------------------------------------------- + * Default constructor + * + * @updated gess 3/25/98 + * @param + * @return + *------------------------------------------------------*/ +nsHTMLContentSink::nsHTMLContentSink() : nsIHTMLContentSink(), mTitle("") { + mNodeStackPos=0; + memset(mNodeStack,0,sizeof(mNodeStack)); +} + + +/**------------------------------------------------------- + * Default destructor. Probably not a good idea to call + * this if you created your instance via the factor method. + * + * @updated gess 3/25/98 + * @param + * @return + *------------------------------------------------------*/ +nsHTMLContentSink::~nsHTMLContentSink() { +} + +#ifdef VERBOSE_DEBUG +static void DebugDump(const char* str1,const nsString& str2,PRInt32 tabs) { + for(PRInt32 i=0;i" << endl; + delete cp; +} +#endif + + +/**------------------------------------------------------- + * This bit of magic creates the addref and release + * methods for this class. + * + * @updated gess 3/25/98 + * @param + * @return + *------------------------------------------------------*/ +NS_IMPL_ADDREF(nsHTMLContentSink) +NS_IMPL_RELEASE(nsHTMLContentSink) + + + +/**------------------------------------------------------- + * Standard XPCOM query interface implementation. I used + * my own version because this class is a subclass of both + * ISupports and IContentSink. Perhaps there's a macro for + * this, but I didn't see it. + * + * @updated gess 3/25/98 + * @param + * @return + *------------------------------------------------------*/ +nsresult nsHTMLContentSink::QueryInterface(const nsIID& aIID, void** aInstancePtr) +{ + if (NULL == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + + if(aIID.Equals(kISupportsIID)) { //do IUnknown... + *aInstancePtr = (nsIContentSink*)(this); + } + else if(aIID.Equals(kIContentSinkIID)) { //do nsIContentSink base class... + *aInstancePtr = (nsIContentSink*)(this); + } + else if(aIID.Equals(kIHTMLContentSinkIID)) { //do nsIHTMLContentSink base class... + *aInstancePtr = (nsIHTMLContentSink*)(this); + } + else if(aIID.Equals(kClassIID)) { //do this class... + *aInstancePtr = (nsHTMLContentSink*)(this); + } + else { + *aInstancePtr=0; + return NS_NOINTERFACE; + } + ((nsISupports*) *aInstancePtr)->AddRef(); + return NS_OK; +} + + +/**------------------------------------------------------- + * This method gets called by the parser when a + * tag has been consumed. + * + * @updated gess 3/25/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool nsHTMLContentSink::OpenHTML(const nsIParserNode& aNode) { + + PRBool result=PR_TRUE; + mNodeStack[mNodeStackPos++]=(eHTMLTags)aNode.GetNodeType(); + +#ifdef VERBOSE_DEBUG + DebugDump("<",aNode.GetText(),(mNodeStackPos-1)*2); +#endif + + return result; +} + +/**------------------------------------------------------- + * This method gets called by the parser when a + * tag has been consumed. + * @updated gess 3/25/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool nsHTMLContentSink::CloseHTML(const nsIParserNode& aNode){ + + NS_PRECONDITION(mNodeStackPos > 0, "node stack empty"); + + PRBool result=PR_TRUE; + mNodeStack[--mNodeStackPos]=eHTMLTag_unknown; + +#ifdef VERBOSE_DEBUG + DebugDump("any time + * head data gets consumed by the parser. Currently, that + * list includes , , , + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + +
+Welcome to Netscape - Navigation Banner + + + + + + + + + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + September 22, 1997 +
+ + + + + + + + +Publishing Suite Now Available + + + + + + + + +
  + + + + + + + Netscape Publishing Suite - the all-in-one solution for creating and publishing web sites - is now available in retail stores nationwide. + + +
+
+ ABC News +
+ + + + + +Netscape delivers the new CommerceXpert family of Internet commerce products developed by Actra - including PublishingXpert 2.0, SellerXpert, and ECXpert. + + + +
+ + + + + + +Netscape launches a preview of Industry Watch by Individual, a personalized service providing in-depth business news and information. + + + + +
+ + + + + + + + + +Download Netscape French Communicator 4.03 for Windows 95 and NT - and take advantage of dynamic web content. + + + + +
+ + + + + + + + +Netscape works with leading sales force automation vendors to deliver next-generation tools that will automate and manage sales environments. + + +
+ + + + + More news... + + Go to a non-layers version of this page. + + + +
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
  +
+ + +Jim Barksdale + +
+
Netscape
Columns

+ +In this week's The Main Thing column, Jim Barksdale talks about directory services. Read all the Netscape Columns to keep up with Internet issues and trends.

+ +
+ + +

+  + + +Tune Up to Communicator +
+
+Netscape
Products

+ +Tune Up to Communicator
+Get Any Netscape Product
+For Subscribers Only

+

+And tune up your Internet connection with ISP Select. + +
+

+  + + +
+
Netscape
Store Special

+ + + + +Looking for a rich Internet experience? Purchase Netscape Communicator Deluxe Edition and get a $30 rebate. Plus save $10 on the Official Netscape Communicator 4.0 Professional Edition book. + + + +

+

+  +
+ + + + + + + +
+  + +

+ + + +
+ + + + +
+
Corporate Sales: 650/937-2555 Personal Sales: 650/937-3777
+Government Sales: 650/937-3678
If you have any questions please visit +Customer Service or contact your nearest +sales office. • Copyright © 1997 +Netscape Communications +Corporation. • This site powered by Netscape SuiteSpot servers.
+ +

+
+

+ + + + + + + + +
+ +New to the Web? + + + + + + + + + + + + +Turn Your In-Box Into a News Center + + +Netcenter + + + + + + + +In-Box Direct Delivers The New York Times + + + + +

+Get the best information on the Web without searching. Netscape In-Box Direct offers rich HTML content from USA Today, the Wall Street Journal, Sports Illustrated, ELLE International, and dozens more delivered directly to your email in-box. Choose the publications you want, and Netscape In-Box Direct will take care of the rest. +

+ + + + +Win a BMW Z3 1.9 Roadster + +
+ +Sign up for Netcenter today and register to win a BMW Z3 1.9 Roadster, PC workstations from Hewlett-Packard, trips from Travelocity and Continental Airlines, and music from CDnow. +

+ + +Software Store + +
+ +Looking for new collaboration software? Web development tools? Netscape's Software Store has all your business solutions software. + +

+ +Netscape Guide by Yahoo! + +
+ +Want a hot stock tip? Head over to the finance section of Netscape Guide by Yahoo! for a rich assortment of money management and investment resources. + + + + + + + + + +Tune in to Netcenter, the Best of the Net for: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + Community + +
+ + + + + Virtual Office + +

+

+ +
+ Software +
+
+ + + + SmartUpdate + +
+ + + + Software Store +

+ +

+ +
+ Content +
+
+ + + +Industry Watch + +
+ + + Channel Finder + +
+ + + In-Box Direct + +
+ + + + Internet Guide + +
+ + + + Net Search +

+ +

+ +
+ + Available Soon + +
+
+ + + + Professional Community + +
+ +
+ + + + + +

Netcenter
+ + + + +
+ + + + + + + + diff --git a/mozilla/htmlparser/tests/html/html001.html b/mozilla/htmlparser/tests/html/html001.html new file mode 100644 index 00000000000..db589d3920b --- /dev/null +++ b/mozilla/htmlparser/tests/html/html001.html @@ -0,0 +1,8 @@ + + + HTML-html04 + + +html tag has attributes. + + \ No newline at end of file diff --git a/mozilla/htmlparser/tests/html/imgmap001.html b/mozilla/htmlparser/tests/html/imgmap001.html new file mode 100644 index 00000000000..b826c9a4e96 --- /dev/null +++ b/mozilla/htmlparser/tests/html/imgmap001.html @@ -0,0 +1,13 @@ + + + + +

area element with attributes set for circular shape of 80,80,60.

+ image for imagemap + + imagemap + + + diff --git a/mozilla/htmlparser/tests/html/ins001.html b/mozilla/htmlparser/tests/html/ins001.html new file mode 100644 index 00000000000..b7be3a2edd3 --- /dev/null +++ b/mozilla/htmlparser/tests/html/ins001.html @@ -0,0 +1,14 @@ + + +test INS tag + + +test INS, bi directional override
+1normal text in body line 1. + +A This text is in INS +
B line 2 in INS +
+2normal text in body line 2. + + diff --git a/mozilla/htmlparser/tests/html/ins002.html b/mozilla/htmlparser/tests/html/ins002.html new file mode 100644 index 00000000000..c759228945c --- /dev/null +++ b/mozilla/htmlparser/tests/html/ins002.html @@ -0,0 +1,18 @@ + + +test INS tag + + +test INS, bi directional override
+1normal text in body line 1. + +A This text is in INS + + C This text is in INS2 +
D line 2 in INS2 +
+
B line 2 in INS +
+2normal text in body line 2. + + diff --git a/mozilla/htmlparser/tests/html/ins003.html b/mozilla/htmlparser/tests/html/ins003.html new file mode 100644 index 00000000000..8574eaef4b5 --- /dev/null +++ b/mozilla/htmlparser/tests/html/ins003.html @@ -0,0 +1,13 @@ + + + + + + del strikeover text + + +Normal text1 +
text with underline +
Normal text2 + + diff --git a/mozilla/htmlparser/tests/html/insdel01.html b/mozilla/htmlparser/tests/html/insdel01.html new file mode 100644 index 00000000000..9aa6ba964ea --- /dev/null +++ b/mozilla/htmlparser/tests/html/insdel01.html @@ -0,0 +1,16 @@ + + +test INS tag + + +test INS
+1normal text in body line 1. + +A This text is in INS + +
B line 2 in INS +
+
+2normal text in body line 2. + + diff --git a/mozilla/htmlparser/tests/html/insdel02.html b/mozilla/htmlparser/tests/html/insdel02.html new file mode 100644 index 00000000000..4e21163812e --- /dev/null +++ b/mozilla/htmlparser/tests/html/insdel02.html @@ -0,0 +1,16 @@ + + +INS DEL /INS /DEL crossing scope + + +test INS
+1normal text in body line 1. + +A This text is in INS + +
B line 2 in INS +
+2normal text in body line 2. + + + diff --git a/mozilla/htmlparser/tests/html/layer001.html b/mozilla/htmlparser/tests/html/layer001.html new file mode 100644 index 00000000000..dc9790698fb --- /dev/null +++ b/mozilla/htmlparser/tests/html/layer001.html @@ -0,0 +1,20 @@ + + + + +Test Layer + + + + +Layers do NOT imply new paragraph, nor line break. + + +Note, no line break here. Text-2 + + + +After layer, text-3 + + + diff --git a/mozilla/htmlparser/tests/html/layer002.html b/mozilla/htmlparser/tests/html/layer002.html new file mode 100644 index 00000000000..012d84451a9 --- /dev/null +++ b/mozilla/htmlparser/tests/html/layer002.html @@ -0,0 +1,28 @@ + + + + +Test Layer002 + + + + +In Vav4.0, SPAN tags go thour layers. +
It remain in effect in its whole scope, including layer. + +Text in color=red SPAN. + + + +Text between 2 LAYERs. + + + + +

+Text not in layer, but still in SPAN +

+
+Text after closing font tag. + + diff --git a/mozilla/htmlparser/tests/html/layer003.html b/mozilla/htmlparser/tests/html/layer003.html new file mode 100644 index 00000000000..846a4def75e --- /dev/null +++ b/mozilla/htmlparser/tests/html/layer003.html @@ -0,0 +1,29 @@ + + + + +Test Layer003 + + + + +In Vav4.0, layers are in the same "span space" as their parents. +
That means spans can be closed inside layer, and affect layers' parents. + + +Text in color=red SPAN. + + + +Text between 2 LAYERs. + + + + +

+Text not in layer +

+ + + + diff --git a/mozilla/htmlparser/tests/html/layer01.html b/mozilla/htmlparser/tests/html/layer01.html new file mode 100644 index 00000000000..0a503a7eb4c --- /dev/null +++ b/mozilla/htmlparser/tests/html/layer01.html @@ -0,0 +1,22 @@ + + + + +Welcome to Netscape + + + + +Text-1 + + + +
Text-2 + + + +

+no-layer-text-3 + + + diff --git a/mozilla/htmlparser/tests/html/list001.html b/mozilla/htmlparser/tests/html/list001.html new file mode 100644 index 00000000000..e2d549c797a --- /dev/null +++ b/mozilla/htmlparser/tests/html/list001.html @@ -0,0 +1,33 @@ + +Welcome to Hewlett-Packard + + + +This file was created on 9/16/97 for bug #85117, assert in parser +when closing dd tag. + +
This is from the end of the page www.hp.com +
Note, an optional closing dd tag is missing. + + + + + +

+ +
[Search HP] + +[Top] +[Contact HP] +[Copyright] + + +
+ + + + + + + + diff --git a/mozilla/htmlparser/tests/html/list002.html b/mozilla/htmlparser/tests/html/list002.html new file mode 100644 index 00000000000..f5c31fb4079 --- /dev/null +++ b/mozilla/htmlparser/tests/html/list002.html @@ -0,0 +1,15 @@ + +Welcome to Hewlett-Packard + + + +This file was created on 9/16/97 for bug #85117, assert in parser +when closing dd tag. + + +abcd efg + + + + + diff --git a/mozilla/htmlparser/tests/html/list003.html b/mozilla/htmlparser/tests/html/list003.html new file mode 100644 index 00000000000..c47e5ab5094 --- /dev/null +++ b/mozilla/htmlparser/tests/html/list003.html @@ -0,0 +1,19 @@ + + + +text line 1 + +Text after font color=red +
    +
  • first list item +

    still in list item. +

  • . second list item. + ... +
+ +Text after list, still in font color=red +
+Text after font color=red. +text at tend. + + \ No newline at end of file diff --git a/mozilla/htmlparser/tests/html/newlines.html b/mozilla/htmlparser/tests/html/newlines.html new file mode 100644 index 00000000000..a949cc70e90 --- /dev/null +++ b/mozilla/htmlparser/tests/html/newlines.html @@ -0,0 +1,3 @@ +#1: This is a line of input terminated by a \n +#2: This is another line of input terminated by a \r\n +#3: This is a line of input terminated by a \r #4: This is the last line diff --git a/mozilla/htmlparser/tests/html/obj001.html b/mozilla/htmlparser/tests/html/obj001.html new file mode 100644 index 00000000000..823b1939d43 --- /dev/null +++ b/mozilla/htmlparser/tests/html/obj001.html @@ -0,0 +1,12 @@ + + + + + + + Java applet that plays a welcoming sound. + + + diff --git a/mozilla/htmlparser/tests/html/obj002.html b/mozilla/htmlparser/tests/html/obj002.html new file mode 100644 index 00000000000..b0805ba8eae --- /dev/null +++ b/mozilla/htmlparser/tests/html/obj002.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/mozilla/htmlparser/tests/html/obj003.html b/mozilla/htmlparser/tests/html/obj003.html new file mode 100644 index 00000000000..e7cb0f03ee2 --- /dev/null +++ b/mozilla/htmlparser/tests/html/obj003.html @@ -0,0 +1,17 @@ + + + + + object element with no attributes. + object element with lang attribute set to en. + object element with dir attribute set to ltr. + + param element with no attributes:
+ +
+ + param element with the name attribute and an end tag:
+ +
+ + diff --git a/mozilla/htmlparser/tests/html/param001.html b/mozilla/htmlparser/tests/html/param001.html new file mode 100644 index 00000000000..5085d70b008 --- /dev/null +++ b/mozilla/htmlparser/tests/html/param001.html @@ -0,0 +1,10 @@ + + + + + + param element with no attributes:
+ +
+ + diff --git a/mozilla/htmlparser/tests/html/param002.html b/mozilla/htmlparser/tests/html/param002.html new file mode 100644 index 00000000000..84658e60664 --- /dev/null +++ b/mozilla/htmlparser/tests/html/param002.html @@ -0,0 +1,14 @@ + + + + + test case for Object and Param tags. + + param element with + the name attribute, and an illeagal end tag:
+ +
+ PARAM element out side OBJECT, ignored. + + + diff --git a/mozilla/htmlparser/tests/html/pre001.html b/mozilla/htmlparser/tests/html/pre001.html new file mode 100644 index 00000000000..a64eef6fe27 --- /dev/null +++ b/mozilla/htmlparser/tests/html/pre001.html @@ -0,0 +1,9 @@ + + +Hi +
+  text line in    pre    tag.
+
+There + + \ No newline at end of file diff --git a/mozilla/htmlparser/tests/html/pre002.html b/mozilla/htmlparser/tests/html/pre002.html new file mode 100644 index 00000000000..e7bca5ab929 --- /dev/null +++ b/mozilla/htmlparser/tests/html/pre002.html @@ -0,0 +1,11 @@ + + +Only new lines in PRE block. +
+
+
+
+
+There + + \ No newline at end of file diff --git a/mozilla/htmlparser/tests/html/pre003.html b/mozilla/htmlparser/tests/html/pre003.html new file mode 100644 index 00000000000..e7f4647dc94 --- /dev/null +++ b/mozilla/htmlparser/tests/html/pre003.html @@ -0,0 +1,8 @@ + + +Empty PRE block. +
+
+There + + \ No newline at end of file diff --git a/mozilla/htmlparser/tests/html/pre004.html b/mozilla/htmlparser/tests/html/pre004.html new file mode 100644 index 00000000000..360c3dce93b --- /dev/null +++ b/mozilla/htmlparser/tests/html/pre004.html @@ -0,0 +1,18 @@ + + +Pre tag can contain many things, inclusing P tag. + +
+First   text line in PRE block. You     can see
+the     spaces       between words      not compressed.
+

+ Text line after P tag. + bold text and italic text. + and many more. There is a empty line at the end + of PRE block. + +

+Text outside PRE block. + + + \ No newline at end of file diff --git a/mozilla/htmlparser/tests/html/pre005.html b/mozilla/htmlparser/tests/html/pre005.html new file mode 100644 index 00000000000..5568d8e2769 --- /dev/null +++ b/mozilla/htmlparser/tests/html/pre005.html @@ -0,0 +1,53 @@ + + +use a PRE tag for C or JAVA source code. +
The lt and gt signes are problematic. + + +
+  cc = 123;
+  // test lt
+  if( cc < hhh ) {
+    if(cc gh) {
+        //do womthing here;
+    }
+  }
+  if( cc <= iii ) {
+    if(cc<=yyy) {
+    if(cc<-yyy) {
+    if(cc<+yyy) {
+    if(cc<3) {
+    if(cc<33) {
+    if(cc<_abc) {
+        //do womthing here;
+    }
+  }
+  // test gt
+  if( cc > rrr ) {
+    if(cc>eee) {
+        //do womthing here;
+    }
+  }
+  if( cc >= www ) {
+    if(cc>=qqq) {
+        //do womthing here;
+    }
+  }
+  // what if the variable name is a valid tag name.
+  if( cc < B && cc > kk ) {
+    if(cc gg) {
+        //do womthing here;
+    }
+  }
+  cc = aa<>3;
+  gt = true;
+  for(a=0,gt=true; (a>0)&> a++) {
+  }
+  a = 0x0004;
+  lt = 0x0002;
+  for(; a< ) {
+  }
+
+ + \ No newline at end of file diff --git a/mozilla/htmlparser/tests/html/pre006.html b/mozilla/htmlparser/tests/html/pre006.html new file mode 100644 index 00000000000..a6f0d605cab --- /dev/null +++ b/mozilla/htmlparser/tests/html/pre006.html @@ -0,0 +1,28 @@ +Test of PRE tag + + + +
+This      is some preformatted text.
+
+ +

Before PRE +

some        preformatted text.
+    
+ After PRE. +

+ +

Before PRE +

some     preformatted text.
+        
This     is nested preformatted (In Nav4.0, green and formatted)
+        
+ This is still preformatted? (Not in Nav4.0) +
+ After PRE. +

+ +

End of test

diff --git a/mozilla/htmlparser/tests/html/pre007.html b/mozilla/htmlparser/tests/html/pre007.html new file mode 100644 index 00000000000..ec0698a2232 --- /dev/null +++ b/mozilla/htmlparser/tests/html/pre007.html @@ -0,0 +1,12 @@ +

Here is a paragraph where the image that is +floated left is the first piece of content of the paragraph... +

+
+This is a     pre section
+Boldis    a nice thing.
+
+ +
+This is      some pre text
+la de da

More text

And more text - what is the vertical space look like? +

diff --git a/mozilla/htmlparser/tests/html/pre012.html b/mozilla/htmlparser/tests/html/pre012.html new file mode 100644 index 00000000000..a05f2d11f15 --- /dev/null +++ b/mozilla/htmlparser/tests/html/pre012.html @@ -0,0 +1,22 @@ +The following is copied from test tag002.html
+Broken tags are shown, only if no gt sign can be found. + + +ccccccc +Now wrapped with a PRE tag. +
+Broken tags are shown, only if no gt sign can be found.
+
+
+ccccccc
+
\ No newline at end of file
diff --git a/mozilla/htmlparser/tests/html/pre015.html b/mozilla/htmlparser/tests/html/pre015.html
new file mode 100644
index 00000000000..f07de01c753
--- /dev/null
+++ b/mozilla/htmlparser/tests/html/pre015.html
@@ -0,0 +1,18 @@
+The following is copied from test tag005.html
+first line +
empty brakets are displayed as text +This +and this eat next br tag. +and another one. +Last text. +
Now wrapped with a PRE tag. +
+first line
+
empty brakets are displayed as text +This +and this eat next br tag. +and another one. +Last text. +
\ No newline at end of file diff --git a/mozilla/htmlparser/tests/html/pre016.html b/mozilla/htmlparser/tests/html/pre016.html new file mode 100644 index 00000000000..cfd595dce40 --- /dev/null +++ b/mozilla/htmlparser/tests/html/pre016.html @@ -0,0 +1,17 @@ +The following is copied from test tag006.html
+first line +
invalide tags are ignored by 4.0 + + + +Note: no line break here. + +
Now wrapped with a PRE tag. +
+first line
+
invalide tags are ignored by 4.0 +
+ + +Note: no line break here. + \ No newline at end of file diff --git a/mozilla/htmlparser/tests/html/q001.html b/mozilla/htmlparser/tests/html/q001.html new file mode 100644 index 00000000000..e7cd998188b --- /dev/null +++ b/mozilla/htmlparser/tests/html/q001.html @@ -0,0 +1,18 @@ + + +test BLOCKQUOTE and Q tag + + +test BLOCKQUOTE and Q tag
+1normal text in body line 1. +
+A This text is in blockquote +
B line 2 +
+2normal text in body line 2. + +this text is in Q tag + +3normal text in body line 3. + + diff --git a/mozilla/htmlparser/tests/html/quote001.html b/mozilla/htmlparser/tests/html/quote001.html new file mode 100644 index 00000000000..6b591b9193c --- /dev/null +++ b/mozilla/htmlparser/tests/html/quote001.html @@ -0,0 +1,51 @@ + + + HTML test for quoted string + + + + This was created on 9/12/97, for Xena bug # 85121 +
Testing the quoted value string. +
tag A is used so you can check the string by moving mouse on the link. +
use view source or text editor to compare with browser display. + +
The goal is to be compatible with Navigator 4.0 +
Test results are compared with Nav4.0 display. Relavent Nav4.0 source + files are ns\lib\libparse\pa_parse.c and others. +
Differences between 4.0 and xena are indecated. Search for XENA60 + to find all the defferences. + +

comments from ns\xena\lego\src\lego\html\scanner\HTMLScanner.java: +
// For quoted value string : +
// Double/single quote only take effect as the first char +
// of the value string, +
// Quoted string is terminated by the second double/single quote +
// respectively. +
// In other places, double/single quote is treated literally. +
// Entity & quot; is always treated literally, enven it is the +
// first char. +
// +
// Unquoted value string is terminated by while space, or '>' sign. +

+ + Test lines: + +
10(quote / quote ) good syntax: both quotes striped from string +
20( / ) value not quoted, not recommented, but still good syntax. +
30 + Navigator 4.0 value string trunketed at 82 characters XENA60 limit is MAX_STRING_LENGTH = 2000. + +
40 The following are illegal HTML, but handled by Nav4.0 in different ways. +
50( / ) string not quoted, whight space terminates the value +
60( / ) string not quoted, CR terminates the string +
70(escaped-quote / quote ) both quotes remain in string +
80(quote / ) + move mouse on this. If we didn't have a quote in the text, the value string would + run through the end of the A tag. +
90(quote / escaped-quote ) same as above, escaped quote does NOT terminate quote +
100( / quote) if no opening quote, quotes are included in string +
110( / quote) no opening quote, value terminated at right brack + + + diff --git a/mozilla/htmlparser/tests/html/quote002.html b/mozilla/htmlparser/tests/html/quote002.html new file mode 100644 index 00000000000..2873a8c8fe8 --- /dev/null +++ b/mozilla/htmlparser/tests/html/quote002.html @@ -0,0 +1,33 @@ + + + HTML test for quoted string + + + + This was created on 9/15/97, for Xena bug # 85121 +
Testing the quoted value string. +
tag A is used so you can check the string by moving mouse on the link. +
use view source or text editor to compare with browser display. +
10 2 quoted string stick together +
20 2 quoted string seperated by space +
30 Navigator doesn't support nested quote. +
40 quoted string can have escaped quote. +
50 unquoted string can have escaped quote. +
60 unquoted string can have other entities. +
70 entity missing ';', ended by > +
80 entity missing ';', not treated as entity inside a value word. +
90 ending entity with a space, missing ';', value terminated. +
100 ending entity with a '=', missing ';', value not terminated. +
110 unquoted script is treated as text. +
120 Navigator 4.0 does not support script + entity in quoted string. + + +
130 this is fisrt quote " and second quote " in text area. +
140 this is fisrt escaped-quote " and second escaped-quote " in text area. + +
+
In the following test line, quote is the last char in the html file. +
Navigator 4.0 displace the line as text. +
XENA60 appends a closing quote and display it as link with empty href="". +
150 + + + +Test SPAN001 + + + + +

+In HTML standard, SPANs are not allowed to cross Paragraphs. +
In Vav4.0, SPAN tags go thour paragraphs and other block-level elements, +except tbles. +
It be compatable with Nav4.0 and HTML standard, HTMLParser +close all SPANs before open a new paragraph, and reopen SPANs +inside the new paragraph +
+ + + Text ater the color=red SPAN is opend. +

+ Text in a new paragraph. +

+

+ Text after the new paragrapg is closed, still in color=red SPAN. + +
+Text ater the color=red SPAN is closed. + + diff --git a/mozilla/htmlparser/tests/html/span002.html b/mozilla/htmlparser/tests/html/span002.html new file mode 100644 index 00000000000..5f3c497ff84 --- /dev/null +++ b/mozilla/htmlparser/tests/html/span002.html @@ -0,0 +1,21 @@ + + + + +Test SPAN001 + + + + +Normal text + +Text after the color=red SPAN is opend. +

+ Text in a new paragraph. +

+ Text after the new paragrapg is closed, still in color=red SPAN. + +Text ater the color=red SPAN is closed. +
another line. + + diff --git a/mozilla/htmlparser/tests/html/span003.html b/mozilla/htmlparser/tests/html/span003.html new file mode 100644 index 00000000000..c4ea303d8c9 --- /dev/null +++ b/mozilla/htmlparser/tests/html/span003.html @@ -0,0 +1,17 @@ + + + + +Test SPAN001 + + + + +

+ + bold + italic + B closed(but actualy it closed the last span tag, which is I tag. + I closed + + diff --git a/mozilla/htmlparser/tests/html/strike002.html b/mozilla/htmlparser/tests/html/strike002.html new file mode 100644 index 00000000000..65d505d595a --- /dev/null +++ b/mozilla/htmlparser/tests/html/strike002.html @@ -0,0 +1,17 @@ + + +Nested STRIKE + + +nested STRIKE
+1normal text in body line 1. + +A This text is in STRIKE + +
B line 2 in STRIKE +
+C line 3 in STRIKE +
+2normal text in body line 2. + + diff --git a/mozilla/htmlparser/tests/html/strike005.html b/mozilla/htmlparser/tests/html/strike005.html new file mode 100644 index 00000000000..4040627aca8 --- /dev/null +++ b/mozilla/htmlparser/tests/html/strike005.html @@ -0,0 +1,22 @@ + + +strikeover a whole TABLE + + +strikeover a whole TABLE, no visual effect, no strikeover on text in table
+1normal text in body line 1. + +text with strikeover +

+ + +
This is the first cell in the table + This is the second cell in the table +
This is the third cell in the table + This is the fourth cell in the table +
+text still inside strikeover. + +2normal text in body line 2. + + diff --git a/mozilla/htmlparser/tests/html/strike006.html b/mozilla/htmlparser/tests/html/strike006.html new file mode 100644 index 00000000000..979198c12b3 --- /dev/null +++ b/mozilla/htmlparser/tests/html/strike006.html @@ -0,0 +1,18 @@ + + +strikeover in a table cell TD + + +strikeover in a table cell TD
+1normal text in body line 1. + + + +
This is the first cell in the table + This is strikeover +
This is the third cell in the table + This is the fourth cell in the table +
+2normal text in body line 2. + + diff --git a/mozilla/htmlparser/tests/html/strike007.html b/mozilla/htmlparser/tests/html/strike007.html new file mode 100644 index 00000000000..eaa80db9961 --- /dev/null +++ b/mozilla/htmlparser/tests/html/strike007.html @@ -0,0 +1,20 @@ + + +strikeover a whole table cell TD + + +strikeover a whole table cell TD +1normal text in body line 1. + + + + + +
This is the first cell in the table + + This cell is in strikeover
This is the third cell in the table + This is the fourth cell in the table +
+2normal text in body line 2. + + diff --git a/mozilla/htmlparser/tests/html/strike008.html b/mozilla/htmlparser/tests/html/strike008.html new file mode 100644 index 00000000000..cc95b6ebf47 --- /dev/null +++ b/mozilla/htmlparser/tests/html/strike008.html @@ -0,0 +1,26 @@ + + +strikeover cross scope with a table + + +

strikeover cross scope with a table
+It starts before table, but ends inside table. +
It does not effect the table, but the strikeover is terminated after the table. +
1normal text in body line 1. + +text in strikeover. + + + + + +
This is the first cell in the table + This cell 2
This is the third cell in the table + This is the fourth cell in the table +
+

+text not in strikeover + +
2normal text in body line 2. + + diff --git a/mozilla/htmlparser/tests/html/table05a.html b/mozilla/htmlparser/tests/html/table05a.html new file mode 100644 index 00000000000..a6df8ca395e --- /dev/null +++ b/mozilla/htmlparser/tests/html/table05a.html @@ -0,0 +1,14 @@ +Caption before end of table +
Nav 4.0: caption is accepted. (terminate tr) +
Xena6.0: ignore misplaced caption tag. + + + + + +
cell 1-1 + cell 1-2 +
cell 2-1 + cell 2-2
caption1
+ +last text diff --git a/mozilla/htmlparser/tests/html/table05b.html b/mozilla/htmlparser/tests/html/table05b.html new file mode 100644 index 00000000000..e05836f3ee2 --- /dev/null +++ b/mozilla/htmlparser/tests/html/table05b.html @@ -0,0 +1,14 @@ +Caption after tr. +
Nav 4.0: caption is accepted, terminate an empty tr, +
Xena6.0: ignore misplaced caption tag. + + + taxeA + +
caption1
cell 1-1 + cell 1-2 +
cell 2-1 + cell 2-2 +
+ +last text diff --git a/mozilla/htmlparser/tests/html/table05c.html b/mozilla/htmlparser/tests/html/table05c.html new file mode 100644 index 00000000000..1b55afcc3a5 --- /dev/null +++ b/mozilla/htmlparser/tests/html/table05c.html @@ -0,0 +1,14 @@ +Caption between table cell +
Nav 4.0: caption is accepted, terminate tr, +
Xena6.0: ignore misplaced caption tag. + + + + textA + +
cell 1-1
caption1
cell 1-2 +
cell 2-1 + cell2-2 +
+ +last text diff --git a/mozilla/htmlparser/tests/html/table05d.html b/mozilla/htmlparser/tests/html/table05d.html new file mode 100644 index 00000000000..3144e70f146 --- /dev/null +++ b/mozilla/htmlparser/tests/html/table05d.html @@ -0,0 +1,13 @@ +Caption inside cell +
Nav 4.0: caption is accepted, terminates both td and tr. +
Xena6.0: ignore misplaced caption tag. + + + textA + +
cell 1-1
caption1
cell 1-2 +
cell 2-1 + cell 2-2 +
+ +last text diff --git a/mozilla/htmlparser/tests/html/table05k.html b/mozilla/htmlparser/tests/html/table05k.html new file mode 100644 index 00000000000..d05228d0811 --- /dev/null +++ b/mozilla/htmlparser/tests/html/table05k.html @@ -0,0 +1,19 @@ +Table in caption works. + + + +
caption1
text1 text2 + + + +
cell 1-1 + cell 1-2 +
still in + caption +
+
cell 2-1-1 + cell 2-1-2 +
cell 2-2-1 +
+ +last text diff --git a/mozilla/htmlparser/tests/html/table05l.html b/mozilla/htmlparser/tests/html/table05l.html new file mode 100644 index 00000000000..c7dbd30c4e9 --- /dev/null +++ b/mozilla/htmlparser/tests/html/table05l.html @@ -0,0 +1,14 @@ +Table in caption, and Nav4.0 show blank page if the window is wide. +Table in caption is part of the caption, leave the table body empty. + + + +
caption1
text1 text2 + + + +
cell 1-1 + cell 1-2 +
cell 2-1 + cell 2-2 +
+ +Nev. 4.0 ignore empty tables. \ No newline at end of file diff --git a/mozilla/htmlparser/tests/html/table05m.html b/mozilla/htmlparser/tests/html/table05m.html new file mode 100644 index 00000000000..18c01e22dfa --- /dev/null +++ b/mozilla/htmlparser/tests/html/table05m.html @@ -0,0 +1,5 @@ +Start table tag alone is ignored. + + + +last text diff --git a/mozilla/htmlparser/tests/html/table05n.html b/mozilla/htmlparser/tests/html/table05n.html new file mode 100644 index 00000000000..83aede59060 --- /dev/null +++ b/mozilla/htmlparser/tests/html/table05n.html @@ -0,0 +1,11 @@ +End table tag terminates caption and table. +
+
caption1
text1 text2 +
+
cell1 +
cell2 +
+ +last text diff --git a/mozilla/htmlparser/tests/html/table05o.html b/mozilla/htmlparser/tests/html/table05o.html new file mode 100644 index 00000000000..34fa22e5fd1 --- /dev/null +++ b/mozilla/htmlparser/tests/html/table05o.html @@ -0,0 +1,6 @@ +caption is not shown for empty table. + + +
caption1
text1 text2
+ +last text diff --git a/mozilla/htmlparser/tests/html/table07.html b/mozilla/htmlparser/tests/html/table07.html new file mode 100644 index 00000000000..64a0edfbe9c --- /dev/null +++ b/mozilla/htmlparser/tests/html/table07.html @@ -0,0 +1,13 @@ +text1 + text2 + + + +
cell 1-1 + cell 1-2 +
still in + caption +
+text3 +
+last text diff --git a/mozilla/htmlparser/tests/html/table200.html b/mozilla/htmlparser/tests/html/table200.html new file mode 100644 index 00000000000..e43c788bf7b --- /dev/null +++ b/mozilla/htmlparser/tests/html/table200.html @@ -0,0 +1,21 @@ +Table in table, but not in tr-td. +
the outter table is ignored. + + +
+ + + +
caption of table1.
first cell in table1 + second cell in table1 +
third cell in table1 + fourth cell in table1 +
+ +This is the first cell in table2. + + +NOTE, even no line break here! +
+Caption of outer table is ignored. +Data of outer table is treated as text. \ No newline at end of file diff --git a/mozilla/htmlparser/tests/html/table201.html b/mozilla/htmlparser/tests/html/table201.html new file mode 100644 index 00000000000..62e9665d5e8 --- /dev/null +++ b/mozilla/htmlparser/tests/html/table201.html @@ -0,0 +1,22 @@ +Table in table, but not in tr-td. +
the outter table is ignored. + + + +
caption of table2.
+ + + +
caption of table1.
first cell in table1 + second cell in table1 +
third cell in table1 + fourth cell in table1 +
+ +This is the first cell in table2. + + +NOTE, even no line break here! +
+Caption of outer table is ignored. +Data of outer table is treated as text. \ No newline at end of file diff --git a/mozilla/htmlparser/tests/html/table202.html b/mozilla/htmlparser/tests/html/table202.html new file mode 100644 index 00000000000..5f5c81afdcf --- /dev/null +++ b/mozilla/htmlparser/tests/html/table202.html @@ -0,0 +1,23 @@ +Table in table, after tr, but not td. +
the outter table and tr are ignored. + + + + +
caption of table2.
+ + + +
caption of table1.
first cell in table1 + second cell in table1 +
third cell in table1 + fourth cell in table1 +
+ +This is the first cell in table2. + + +NOTE, even no line break here! +
+Caption of outer table is ignored. +Data of outer table is treated as text. \ No newline at end of file diff --git a/mozilla/htmlparser/tests/html/table203.html b/mozilla/htmlparser/tests/html/table203.html new file mode 100644 index 00000000000..8d0075d53ef --- /dev/null +++ b/mozilla/htmlparser/tests/html/table203.html @@ -0,0 +1,29 @@ +Table nested 3 levels, table3 be the out most. +
Table 1 is not in table2's tr-td. That makes table2 invalid. +
Table3 is still valid, and table2's tr and td are used for +table3. + + + + + +
caption of table3.
+ + + Text after table2, not in tr-td, but in table3's tr-td. +
caption of table2.
+ + + +
caption of table1.
first cell in table1 + second cell in table1 +
third cell in the table1 + fourth cell in the table1 +
+
first cell in table2, but displayed in table 3. +
+ + second cell in table3. but table2's end tag closed table3. + So, this will be displayed out of table3. + + diff --git a/mozilla/htmlparser/tests/html/table204.html b/mozilla/htmlparser/tests/html/table204.html new file mode 100644 index 00000000000..0842245cc02 --- /dev/null +++ b/mozilla/htmlparser/tests/html/table204.html @@ -0,0 +1,23 @@ +nested table missing end td. +
Nav. 4.0(bug): For inner table td does NOT terminate previous td. +
Xena 6.0: end td is always optional. + + + + + +
caption of table1.
cell 1-1 + cell 1-2 +
cell 1-3 + cell 1-4 + + + + +
caption of table2.
cell1 in table2 + cell2 in table2 +
cell3 in table2 + cell4 in table2 +
+
+
Last text. \ No newline at end of file diff --git a/mozilla/htmlparser/tests/html/table205.html b/mozilla/htmlparser/tests/html/table205.html new file mode 100644 index 00000000000..905659196c3 --- /dev/null +++ b/mozilla/htmlparser/tests/html/table205.html @@ -0,0 +1,28 @@ +Table in table, but not in tr-td. +
The only thing missing is the end tag of the +first table! +Nav. 4.0: the outter table is ignored. +Xena 6.0: second table start tag is ignored. Contents put in 1 table. + + + + + + + + +
caption of table1.
first cell in table1 + second cell in table1 +
third cell in table1 + fourth cell in table1 +
+ + + +
caption of table2.
cell1 in table2 + cell2 in table2 +
cell3 in table2 + cell4 in table2 +
+ +
Last text. \ No newline at end of file diff --git a/mozilla/htmlparser/tests/html/tableall.html b/mozilla/htmlparser/tests/html/tableall.html new file mode 100644 index 00000000000..0381ca289ca --- /dev/null +++ b/mozilla/htmlparser/tests/html/tableall.html @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
table test cases
Test case description +
good syntax
+
table01.html <table> <tr> <td> +
table02.html <table> <tr> <td> <table> nested +
table03.html <table border align=left> +
table04.html <table> mixed with list. + +
table05 The correct position for Caption is after table start tag. + + +
bad syntax
+
*table05a Caption before </table>. 4.0: Accepted, 6.0: ignored. +
*table05b Caption after tr. 4.0: Accepted, 6.0: ignored. +
*table05c Caption between table cell. 4.0: Accepted, 6.0: ignored. +
*table05d Caption inside cell. 4.0: terminates both td and tr. 6.0: Ignored. +
table05e Multiple caption outside cells. 4.0 takes first as Caption, others as text. +
*table05f Captions inside cells, 4.0 takes last one, terminate td tr, 6.0 Ignore misplaced tag. +
table05g Captions outside of table are treated as text. +
table05h tr terminates caption +
table05i tr terminates Caption, and close open(font) tags in caption. +
table05j TD does NOT terminate Caption. TD's contents are used in caption. +
table05k Table in caption works. +
table05l Table in caption, table empty. 4.0(bug): shows blank page. +
table05m <table> alone is ignored. +
table05n </table> terminates caption and table. +
table05o caption is not shown for empty table.
table110.htm <tr> <td> missing <table> +
table115.htm <table> text1 <tr> test2 <td> test3 +
table120.htm <table> </table> table totally empty . +
table125.htm <table> text </table>, no tr, td +
table130.htm <table> <td> , missing tr +
table135.htm <table> <tr> <tr> <td> , empty tr. +
table140.htm <table> <tr> text <tr> <td> , empty tr. +
table150.htm <table> <tr> <td> <td> , empty td. + +
table201.html <table> <table> +
table202.html <table> <tr> <table> +
table203.html Table nested 3 levels, T1 not in T2's td +
*table204.htm nested table missing end td. 4.0(bug) inner table need </td> +
*table205.htm table in table. 4.0: discard outer, 6.0: put into 1 table. +
+ + diff --git a/mozilla/htmlparser/tests/html/tag001.html b/mozilla/htmlparser/tests/html/tag001.html new file mode 100644 index 00000000000..dd2b5698dca --- /dev/null +++ b/mozilla/htmlparser/tests/html/tag001.html @@ -0,0 +1,3 @@ +first line +second line +third line < \ No newline at end of file diff --git a/mozilla/htmlparser/tests/html/tag002.html b/mozilla/htmlparser/tests/html/tag002.html new file mode 100644 index 00000000000..5083bee2948 --- /dev/null +++ b/mozilla/htmlparser/tests/html/tag002.html @@ -0,0 +1,23 @@ +Broken tags are shown, only if no gt sign can be found. + + +aaaaaaaaaaaa + + +bbbbbbbb + +< + +open tag without name, stat with space, treated as text. +
+KKKKKKKKKK + +< open tag has no tag name, stat with space, treated as text. +
+ccccccc + +second line +

Here is next paragraph. +
+They ignored by 4,0. +Everything between the brakets is consummed. \ No newline at end of file diff --git a/mozilla/htmlparser/tests/html/tag004.html b/mozilla/htmlparser/tests/html/tag004.html new file mode 100644 index 00000000000..00b6cc77073 --- /dev/null +++ b/mozilla/htmlparser/tests/html/tag004.html @@ -0,0 +1,4 @@ +first line +
empty brakets are displayed as text +<> +more text. diff --git a/mozilla/htmlparser/tests/html/tag005.html b/mozilla/htmlparser/tests/html/tag005.html new file mode 100644 index 00000000000..cb46e427796 --- /dev/null +++ b/mozilla/htmlparser/tests/html/tag005.html @@ -0,0 +1,7 @@ +first line +
empty brakets are displayed as text +This +and this eat next br tag. +and another one. +Last text. diff --git a/mozilla/htmlparser/tests/html/tag006.html b/mozilla/htmlparser/tests/html/tag006.html new file mode 100644 index 00000000000..36d3dcc0d02 --- /dev/null +++ b/mozilla/htmlparser/tests/html/tag006.html @@ -0,0 +1,6 @@ +first line +
invalide tags are ignored by 4.0 + + + +Note: no line break here. diff --git a/mozilla/htmlparser/tests/html/tag007.html b/mozilla/htmlparser/tests/html/tag007.html new file mode 100644 index 00000000000..596b5484dc5 --- /dev/null +++ b/mozilla/htmlparser/tests/html/tag007.html @@ -0,0 +1,5 @@ +first line +
Unmacthed opening tag in next line is ignored by 4.0 + +
+Note: no line break inserted here. diff --git a/mozilla/htmlparser/tests/html/tag008.html b/mozilla/htmlparser/tests/html/tag008.html new file mode 100644 index 00000000000..6b67931e732 --- /dev/null +++ b/mozilla/htmlparser/tests/html/tag008.html @@ -0,0 +1,4 @@ +first line +
Unmacthed end tag in next line is ignored by 4.0 +
+Note: no line break inserted here. diff --git a/mozilla/htmlparser/tests/html/target01.html b/mozilla/htmlparser/tests/html/target01.html new file mode 100644 index 00000000000..44c34fdbb29 --- /dev/null +++ b/mozilla/htmlparser/tests/html/target01.html @@ -0,0 +1,7 @@ + +Target outside of quoted HREF. +
example: +
+two days + + \ No newline at end of file diff --git a/mozilla/htmlparser/tests/html/tbody001.html b/mozilla/htmlparser/tests/html/tbody001.html new file mode 100644 index 00000000000..d639a01c606 --- /dev/null +++ b/mozilla/htmlparser/tests/html/tbody001.html @@ -0,0 +1,17 @@ + + +Welcome to Netscape + + +
+ + + + + +
+ table element with no attributes. The required embedded + elements are used - TBODY-TR-TD. +
+ + diff --git a/mozilla/htmlparser/tests/html/text001.html b/mozilla/htmlparser/tests/html/text001.html new file mode 100644 index 00000000000..55c4e5ee38e --- /dev/null +++ b/mozilla/htmlparser/tests/html/text001.html @@ -0,0 +1,8 @@ + + +Welcome to Netscape + + +Text-001 + + diff --git a/mozilla/htmlparser/tests/html/text002.html b/mozilla/htmlparser/tests/html/text002.html new file mode 100644 index 00000000000..68b070ca308 --- /dev/null +++ b/mozilla/htmlparser/tests/html/text002.html @@ -0,0 +1,8 @@ + + +Welcome to Netscape + + +Text-002 + + diff --git a/mozilla/htmlparser/tests/html/text003.html b/mozilla/htmlparser/tests/html/text003.html new file mode 100644 index 00000000000..aa1f7ae9ccc --- /dev/null +++ b/mozilla/htmlparser/tests/html/text003.html @@ -0,0 +1,12 @@ + + + +Welcome to Netscape + + +Text-001 +
+
+Text after closing font tag. + + diff --git a/mozilla/htmlparser/tests/html/thead001.html b/mozilla/htmlparser/tests/html/thead001.html new file mode 100644 index 00000000000..b517ea769be --- /dev/null +++ b/mozilla/htmlparser/tests/html/thead001.html @@ -0,0 +1,25 @@ +Normal case for thead, tfoot, tbody + + + + + + + + + + + + + + + + + +
caption of table2.
text in thead
text in tfoot
first cell in table1 + second cell in table1 +
third cell in table1 + fourth cell in table1 +
+ +last text. \ No newline at end of file diff --git a/mozilla/htmlparser/tests/html/title01.html b/mozilla/htmlparser/tests/html/title01.html new file mode 100644 index 00000000000..c6404098244 --- /dev/null +++ b/mozilla/htmlparser/tests/html/title01.html @@ -0,0 +1,6 @@ + + +<!-- still in comment --> + +some text + diff --git a/mozilla/htmlparser/tests/html/usascii.html b/mozilla/htmlparser/tests/html/usascii.html new file mode 100644 index 00000000000..834856339d0 --- /dev/null +++ b/mozilla/htmlparser/tests/html/usascii.html @@ -0,0 +1,26 @@ + + + + Juan Gotoh's Visual Workshop + + + + + + + + + + + + +<BODY> + +<P>If your brouser can not display frame, please click +<A HREF="home_E.html">here.</A> it has same contents as frame +version.</P> + +</BODY> + + diff --git a/mozilla/htmlparser/tests/html/utf8001.html b/mozilla/htmlparser/tests/html/utf8001.html new file mode 100644 index 00000000000..017a3d7c652 --- /dev/null +++ b/mozilla/htmlparser/tests/html/utf8001.html @@ -0,0 +1,9 @@ + + + +Welcome to Netscape + + +Text-001 + + diff --git a/mozilla/htmlparser/tests/html/value001.html b/mozilla/htmlparser/tests/html/value001.html new file mode 100644 index 00000000000..55c926e7eb7 --- /dev/null +++ b/mozilla/htmlparser/tests/html/value001.html @@ -0,0 +1,14 @@ + + + + +Welcome to Netscape + + + + + + + + + diff --git a/mozilla/htmlparser/tests/html/xmp005.html b/mozilla/htmlparser/tests/html/xmp005.html new file mode 100644 index 00000000000..ac952f5b849 --- /dev/null +++ b/mozilla/htmlparser/tests/html/xmp005.html @@ -0,0 +1,48 @@ + + +use a XMP tag for C or JAVA source code. +
The lt and gt signes are problematic. + + + + cc = 123; + // test lt + if( cc < hhh ) { + if(cc<xxx || as > gh) { + //do womthing here; + } + } + if( cc <= iii ) { + if(cc<=yyy) { + //do womthing here; + } + } + // test gt + if( cc > rrr ) { + if(cc>eee) { + //do womthing here; + } + } + if( cc >= www ) { + if(cc>=qqq) { + //do womthing here; + } + } + // what if the variable name is a valid tag name. + if( cc < B && cc > kk ) { + if(cc<B && cc > gg) { + //do womthing here; + } + } + cc = aa<<I; + cc = B>>3; + gt = true; + for(a=0,gt=true; (a>0)&&gt; a++) { + } + a = 0x0004; + lt = 0x0002; + for(; a&lt; ) { + } + + + \ No newline at end of file diff --git a/mozilla/htmlparser/tests/windows/Selftest.cpp b/mozilla/htmlparser/tests/windows/Selftest.cpp new file mode 100644 index 00000000000..0660fc576ba --- /dev/null +++ b/mozilla/htmlparser/tests/windows/Selftest.cpp @@ -0,0 +1,148 @@ +/* -*- Mode: C++; tab-width: 4; 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 +#include +#include +#include +#include +#include + +#include "nsScanner.h" +#include "nsTokenizer.h" +#include "nsHTMLDelegate.h" + + +bool compareFiles(const char* file1,const char* file2) { + bool result=true; + bool done=false; + char ch1,ch2; + int eof1,eof2; + + ifstream input1(file1,ios::in && ios::binary,filebuf::openprot); + ifstream input2(file2,ios::in && ios::binary,filebuf::openprot); + + while(!done) { + + while(!(eof1=input1.eof())) { + input1.read(&ch1,1); + if(('\n'!=ch1) && (' '!=ch1)) + break; + } + + while(!(eof2=input2.eof())) { + input2.read(&ch2,1); + if(('\n'!=ch2) && (' '!=ch2)) + break; + } + + if(eof1==eof2) { + if(eof1) + done=true; + else if(ch1!=ch2) { + done=true; + result=false; + } + } + else done=true; + } + return result; +} + +void parseFile (const char* aFilename,int size) +{ + //debug + aFilename="s:\\ns\\raptor\\parser\\tests\\html\\tag001.html"; + //aFilename="c:\\temp\\temp.html"; + + char filename[_MAX_PATH]; + strcpy(filename,aFilename); + strcat(filename,".tokens"); + { + ofstream out(filename); + ifstream input(aFilename); + CScanner scanner(input); + CHTMLTokenizerDelegate delegate; + CTokenizer tokenizer(scanner,delegate); + tokenizer.tokenize(); + tokenizer.debugDumpSource(out); + } + cout << aFilename; + if(compareFiles(aFilename,filename)) + cout << " PASS " << endl; + else cout << " FAIL" << endl; +} + +int walkDirectoryTree(char* aPath) { + int result=0; + char fullPath[_MAX_PATH]; + struct _finddata_t c_file; + long hFile; + + strcpy(fullPath,aPath); + strcat(fullPath,"\\*.*"); + /* Find first .c file in current directory */ + if((hFile = _findfirst( fullPath, &c_file )) == -1L ) + printf( "No matching files in current directory!\n" ); + else { + + bool done=false; + while(!done) { + if(c_file.attrib & _A_SUBDIR) { + if(strlen(c_file.name)>2){ + char newPath[_MAX_PATH]; + strcpy(newPath,aPath); + strcat(newPath,"\\"); + strcat(newPath,c_file.name); + walkDirectoryTree(newPath); + } + } + else { + int len=strlen(c_file.name); + if(len>5) { + if(0==strnicmp(&c_file.name[len-5],".HTML",5)) { + char filepath[_MAX_PATH]; + strcpy(filepath,aPath); + strcat(filepath,"\\"); + strcat(filepath,c_file.name); + parseFile(filepath,c_file.size); + } + } + } + if(_findnext( hFile, &c_file )!=0) + done=true; + } + _findclose( hFile ); + } + return 0; +} + +int main(int argc, char* argv []) +{ + int result=0; + char buffer[_MAX_PATH]; + + if(argc==2) + strcpy(buffer,argv[1]); + else _getcwd(buffer,_MAX_PATH); + walkDirectoryTree(buffer); + return 0; +} + + + diff --git a/mozilla/layout/Makefile b/mozilla/layout/Makefile new file mode 100644 index 00000000000..58defa2a298 --- /dev/null +++ b/mozilla/layout/Makefile @@ -0,0 +1,24 @@ +#!gmake +# +# 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. + +DEPTH = .. + +DIRS = base html build + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/layout/base/Makefile b/mozilla/layout/base/Makefile new file mode 100644 index 00000000000..4135f9605a8 --- /dev/null +++ b/mozilla/layout/base/Makefile @@ -0,0 +1,24 @@ +#!gmake +# +# 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. + +DEPTH = ../.. + +DIRS = public src tests + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/layout/base/makefile.win b/mozilla/layout/base/makefile.win new file mode 100644 index 00000000000..c08fab64fd1 --- /dev/null +++ b/mozilla/layout/base/makefile.win @@ -0,0 +1,23 @@ +#!nmake +# +# 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. + +DEPTH=..\.. +IGNORE_MANIFEST=1 + +DIRS=public src tests + +include <$(DEPTH)\config\rules.mak> diff --git a/mozilla/layout/base/nsCSSRendering.cpp b/mozilla/layout/base/nsCSSRendering.cpp new file mode 100644 index 00000000000..0657a084095 --- /dev/null +++ b/mozilla/layout/base/nsCSSRendering.cpp @@ -0,0 +1,785 @@ +/* -*- 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 "nsCSSRendering.h" +#include "nsStyleConsts.h" +#include "nsIPresContext.h" +#include "nsIImage.h" +#include "nsIFrame.h" +#include "nsPoint.h" +#include "nsRect.h" +#include "nsIViewManager.h" +#include "nsIPresShell.h" + +#define BORDER_FULL 0 //entire side +#define BORDER_INSIDE 1 //inside half +#define BORDER_OUTSIDE 2 //outside half + +//thickness of dashed line relative to dotted line +#define DOT_LENGTH 1 //square +#define DASH_LENGTH 3 //3 times longer than dot + +/** + * Special method to brighten a Color and have it shift to white when + * fully saturated. + */ +nscolor nsCSSRendering::Brighten(nscolor inColor) +{ + PRIntn r, g, b, max, over; + + r = NS_GET_R(inColor); + g = NS_GET_G(inColor); + b = NS_GET_B(inColor); + + //10% of max color increase across the board + r += 25; + g += 25; + b += 25; + + //figure out which color is largest + if (r > g) + { + if (b > r) + max = b; + else + max = r; + } + else + { + if (b > g) + max = b; + else + max = g; + } + + //if we overflowed on this max color, increase + //other components by the overflow amount + if (max > 255) + { + over = max - 255; + + if (max == r) + { + g += over; + b += over; + } + else if (max == g) + { + r += over; + b += over; + } + else + { + r += over; + g += over; + } + } + + //clamp + if (r > 255) + r = 255; + if (g > 255) + g = 255; + if (b > 255) + b = 255; + + return NS_RGBA(r, g, b, NS_GET_A(inColor)); +} + +/** + * Special method to darken a Color and have it shift to black when + * darkest component underflows + */ +nscolor nsCSSRendering::Darken(nscolor inColor) +{ + PRIntn r, g, b, max; + + r = NS_GET_R(inColor); + g = NS_GET_G(inColor); + b = NS_GET_B(inColor); + + //10% of max color decrease across the board + r -= 25; + g -= 25; + b -= 25; + + //figure out which color is largest + if (r > g) + { + if (b > r) + max = b; + else + max = r; + } + else + { + if (b > g) + max = b; + else + max = g; + } + + //if we underflowed on this max color, decrease + //other components by the underflow amount + if (max < 0) + { + if (max == r) + { + g += max; + b += max; + } + else if (max == g) + { + r += max; + b += max; + } + else + { + r += max; + g += max; + } + } + + //clamp + if (r < 0) + r = 0; + if (g < 0) + g = 0; + if (b < 0) + b = 0; + + return NS_RGBA(r, g, b, NS_GET_A(inColor)); +} + +/** + * Make a bevel color + */ +nscolor nsCSSRendering::MakeBevelColor(PRIntn whichSide, PRUint8 style, + nscolor baseColor) +{ + nscolor theColor = baseColor; + + if ((style == NS_STYLE_BORDER_STYLE_OUTSET) || + (style == NS_STYLE_BORDER_STYLE_RIDGE)) { + // Flip colors for these two border style + switch (whichSide) { + case NS_SIDE_BOTTOM: whichSide = NS_SIDE_TOP; break; + case NS_SIDE_RIGHT: whichSide = NS_SIDE_LEFT; break; + case NS_SIDE_TOP: whichSide = NS_SIDE_BOTTOM; break; + case NS_SIDE_LEFT: whichSide = NS_SIDE_RIGHT; break; + } + } + + switch (whichSide) { + case NS_SIDE_BOTTOM: + theColor = Brighten(Brighten(baseColor)); + break; + case NS_SIDE_RIGHT: + theColor = Brighten(baseColor); + break; + case NS_SIDE_TOP: + theColor = Darken(Darken(baseColor)); + break; + case NS_SIDE_LEFT: + theColor = Darken(baseColor); + break; + } + return theColor; +} + +// Maximum poly points in any of the polygons we generate below +#define MAX_POLY_POINTS 4 + +// a nifty helper function to create a polygon representing a +// particular side of a border. This helps localize code for figuring +// mitered edges. It is mainly used by the solid, inset, and outset +// styles... +PRIntn nsCSSRendering::MakeSide(nsPoint aPoints[], + nsIRenderingContext& aContext, + PRIntn whichSide, + const nsRect& inside, const nsRect& outside, + PRIntn borderPart, float borderFrac) +{ + float borderRest = 1.0f - borderFrac; + + // XXX QQQ We really should decide to do a bevel based on whether there + // is a side adjacent or not. This could let you join borders across + // block elements (paragraphs). + + PRIntn np = 0; + switch (whichSide) { + case NS_SIDE_TOP: + if (borderPart == BORDER_FULL) { + aPoints[np++].MoveTo(outside.x, outside.y); + aPoints[np++].MoveTo(outside.XMost(), outside.y); + aPoints[np++].MoveTo(inside.XMost(), inside.y); + aPoints[np++].MoveTo(inside.x, inside.y); + } else if (borderPart == BORDER_INSIDE) { + aPoints[np++].MoveTo(nscoord(outside.x * borderFrac + + inside.x * borderRest), + nscoord(outside.y * borderFrac + + inside.y * borderRest)); + aPoints[np++].MoveTo(nscoord(outside.XMost() * borderFrac + + inside.XMost() * borderRest), + nscoord(outside.y * borderFrac + + inside.y * borderRest)); + aPoints[np++].MoveTo(inside.XMost(), inside.y); + aPoints[np++].MoveTo(inside.x, inside.y); + } else { + aPoints[np++].MoveTo(outside.x, outside.y); + aPoints[np++].MoveTo(outside.XMost(), outside.y); + aPoints[np++].MoveTo(nscoord(inside.XMost() * borderFrac + + outside.XMost() * borderRest), + nscoord(inside.y * borderFrac + + outside.y * borderRest)); + aPoints[np++].MoveTo(nscoord(inside.x * borderFrac + + outside.x * borderRest), + nscoord(inside.y * borderFrac + + outside.y * borderRest)); + } + break; + + case NS_SIDE_LEFT: + if (borderPart == BORDER_FULL) { + aPoints[np++].MoveTo(outside.x, outside.y); + aPoints[np++].MoveTo(inside.x, inside.y); + aPoints[np++].MoveTo(inside.x, inside.YMost()); + aPoints[np++].MoveTo(outside.x, outside.YMost()); + } else if (borderPart == BORDER_INSIDE) { + aPoints[np++].MoveTo(nscoord(outside.x * borderFrac + + inside.x * borderRest), + nscoord(outside.y * borderFrac + + inside.y * borderRest)); + aPoints[np++].MoveTo(inside.x, inside.y); + aPoints[np++].MoveTo(inside.x, inside.YMost()); + aPoints[np++].MoveTo(nscoord(outside.x * borderFrac + + inside.x * borderRest), + nscoord(outside.YMost() * borderFrac + + inside.YMost() * borderRest)); + } else { + aPoints[np++].MoveTo(outside.x, outside.y); + aPoints[np++].MoveTo(nscoord(inside.x * borderFrac + + outside.x * borderRest), + nscoord(inside.y * borderFrac + + outside.y * borderRest)); + aPoints[np++].MoveTo(nscoord(inside.x * borderFrac + + outside.x * borderRest), + nscoord(inside.YMost() * borderFrac + + outside.YMost() * borderRest)); + aPoints[np++].MoveTo(outside.x, outside.YMost()); + } + break; + + case NS_SIDE_BOTTOM: + if (borderPart == BORDER_FULL) { + aPoints[np++].MoveTo(outside.x, outside.YMost()); + aPoints[np++].MoveTo(inside.x, inside.YMost()); + aPoints[np++].MoveTo(inside.XMost(), inside.YMost()); + aPoints[np++].MoveTo(outside.XMost(), outside.YMost()); + } else if (borderPart == BORDER_INSIDE) { + aPoints[np++].MoveTo(nscoord(outside.x * borderFrac + + inside.x * borderRest), + nscoord(outside.YMost() * borderFrac + + inside.YMost() * borderRest)); + aPoints[np++].MoveTo(inside.x, inside.YMost()); + aPoints[np++].MoveTo(inside.XMost(), inside.YMost()); + aPoints[np++].MoveTo(nscoord(outside.XMost() * borderFrac + + inside.XMost() * borderRest), + nscoord(outside.YMost() * borderFrac + + inside.YMost() * borderRest)); + } else { + aPoints[np++].MoveTo(outside.x, outside.YMost()); + aPoints[np++].MoveTo(nscoord(inside.x * borderFrac + + outside.x * borderRest), + nscoord(inside.YMost() * borderFrac + + outside.YMost() * borderRest)); + aPoints[np++].MoveTo(nscoord(inside.XMost() * borderFrac + + outside.XMost() * borderRest), + nscoord(inside.YMost() * borderFrac + + outside.YMost() * borderRest)); + aPoints[np++].MoveTo(outside.XMost(), outside.YMost()); + } + break; + + case NS_SIDE_RIGHT: + if (borderPart == BORDER_FULL) { + aPoints[np++].MoveTo(inside.XMost(), inside.y); + aPoints[np++].MoveTo(outside.XMost(), outside.y); + aPoints[np++].MoveTo(outside.XMost(), outside.YMost()); + aPoints[np++].MoveTo(inside.XMost(), inside.YMost()); + } else if (borderPart == BORDER_INSIDE) { + aPoints[np++].MoveTo(inside.XMost(), inside.y); + aPoints[np++].MoveTo(nscoord(outside.XMost() * borderFrac + + inside.XMost() * borderRest), + nscoord(outside.y * borderFrac + + inside.y * borderRest)); + aPoints[np++].MoveTo(nscoord(outside.XMost() * borderFrac + + inside.XMost() * borderRest), + nscoord(outside.YMost() * borderFrac + + inside.YMost() * borderRest)); + aPoints[np++].MoveTo(inside.XMost(), inside.YMost()); + } else { + aPoints[np++].MoveTo(nscoord(inside.XMost() * borderFrac + + outside.XMost() * borderRest), + nscoord(inside.y * borderFrac + + outside.y * borderRest)); + aPoints[np++].MoveTo(outside.XMost(), outside.y); + aPoints[np++].MoveTo(outside.XMost(), outside.YMost()); + aPoints[np++].MoveTo(nscoord(inside.XMost() * borderFrac + + outside.XMost() * borderRest), + nscoord(inside.YMost() * borderFrac + + outside.YMost() * borderRest)); + } + break; + } + return np; +} + +void nsCSSRendering::DrawSide(nsIRenderingContext& aContext, + PRIntn whichSide, + const PRUint8 borderStyles[], + const nscolor borderColors[], + const nsRect& borderOutside, + const nsRect& borderInside) +{ + nsPoint theSide[MAX_POLY_POINTS]; + nscolor theColor = borderColors[whichSide]; + PRUint8 theStyle = borderStyles[whichSide]; + PRInt32 np; + switch (theStyle) { + case NS_STYLE_BORDER_STYLE_NONE: + case NS_STYLE_BORDER_STYLE_BLANK: + return; + + case NS_STYLE_BORDER_STYLE_DOTTED: //handled a special case elsewhere + case NS_STYLE_BORDER_STYLE_DASHED: //handled a special case elsewhere + break; // That was easy... + + case NS_STYLE_BORDER_STYLE_GROOVE: + case NS_STYLE_BORDER_STYLE_RIDGE: + np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside, + BORDER_INSIDE, 0.5f); + aContext.SetColor ( MakeBevelColor (whichSide, theStyle, theColor)); + aContext.FillPolygon (theSide, np); + np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside, + BORDER_OUTSIDE, 0.5f); + aContext.SetColor ( MakeBevelColor (whichSide, + (theStyle == NS_STYLE_BORDER_STYLE_RIDGE) + ? NS_STYLE_BORDER_STYLE_GROOVE + : NS_STYLE_BORDER_STYLE_RIDGE, theColor)); + aContext.FillPolygon (theSide, np); + break; + + case NS_STYLE_BORDER_STYLE_SOLID: + np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside, + BORDER_FULL, 1.0f); + aContext.SetColor (borderColors[whichSide]); + aContext.FillPolygon (theSide, np); + break; + + case NS_STYLE_BORDER_STYLE_DOUBLE: + np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside, + BORDER_INSIDE, 0.333333f); + aContext.SetColor (borderColors[whichSide]); + aContext.FillPolygon (theSide, np); + np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside, + BORDER_OUTSIDE, 0.333333f); + aContext.FillPolygon (theSide, np); + break; + + case NS_STYLE_BORDER_STYLE_OUTSET: + case NS_STYLE_BORDER_STYLE_INSET: + np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside, + BORDER_FULL, 1.0f); + aContext.SetColor ( MakeBevelColor (whichSide, theStyle, theColor)); + aContext.FillPolygon (theSide, np); + break; + } +} + +/** + * Draw a dotted/dashed sides of a box + */ +//XXX dashes which span more than two edges are not handled properly MMP +void nsCSSRendering::DrawDashedSides(PRIntn startSide, + nsIRenderingContext& aContext, + const PRUint8 borderStyles[], + const nscolor borderColors[], + const nsRect& borderOutside, + const nsRect& borderInside, + PRIntn aSkipSides) +{ + PRIntn dashLength; + nsRect dashRect, firstRect, currRect; + + PRBool bSolid = PR_TRUE; + float over = 0.0f; + PRUint8 style = borderStyles[startSide]; + PRBool skippedSide = PR_FALSE; + for (PRIntn whichSide = startSide; whichSide < 4; whichSide++) { + PRUint8 prevStyle = style; + style = borderStyles[whichSide]; + if ((1< 0.0f) { + firstRect.x = dashRect.x; + firstRect.width = dashRect.width; + firstRect.height = nscoord(dashRect.height * over); + firstRect.y = dashRect.y + (dashRect.height - firstRect.height); + over = 0.0f; + currRect = firstRect; + } else { + currRect = dashRect; + } + + while (currRect.YMost() > borderInside.y) { + //clip if necessary + if (currRect.y < borderInside.y) { + over = float(borderInside.y - dashRect.y) / + float(dashRect.height); + currRect.height = currRect.height - (borderInside.y - currRect.y); + currRect.y = borderInside.y; + } + + //draw if necessary + if (bSolid) { + aContext.FillRect(currRect); + } + + //setup for next iteration + if (over == 0.0f) { + bSolid = PRBool(!bSolid); + } + dashRect.y = dashRect.y - currRect.height; + currRect = dashRect; + } + break; + + case NS_SIDE_TOP: + //if we are continuing a solid rect, fill in the corner first + if (bSolid) { + aContext.FillRect(borderOutside.x, borderOutside.y, + borderInside.x - borderOutside.x, + borderInside.y - borderOutside.y); + } + + dashRect.height = borderInside.y - borderOutside.y; + dashRect.width = dashRect.height * dashLength; + dashRect.x = borderInside.x; + dashRect.y = borderOutside.y; + + if (over > 0.0f) { + firstRect.x = dashRect.x; + firstRect.y = dashRect.y; + firstRect.width = nscoord(dashRect.width * over); + firstRect.height = dashRect.height; + over = 0.0f; + currRect = firstRect; + } else { + currRect = dashRect; + } + + while (currRect.x < borderInside.XMost()) { + //clip if necessary + if (currRect.XMost() > borderInside.XMost()) { + over = float(dashRect.XMost() - borderInside.XMost()) / + float(dashRect.width); + currRect.width = currRect.width - + (currRect.XMost() - borderInside.XMost()); + } + + //draw if necessary + if (bSolid) { + aContext.FillRect(currRect); + } + + //setup for next iteration + if (over == 0.0f) { + bSolid = PRBool(!bSolid); + } + dashRect.x = dashRect.x + currRect.width; + currRect = dashRect; + } + break; + + case NS_SIDE_RIGHT: + //if we are continuing a solid rect, fill in the corner first + if (bSolid) { + aContext.FillRect(borderInside.XMost(), borderOutside.y, + borderOutside.XMost() - borderInside.XMost(), + borderInside.y - borderOutside.y); + } + + dashRect.width = borderOutside.XMost() - borderInside.XMost(); + dashRect.height = nscoord(dashRect.width * dashLength); + dashRect.x = borderInside.XMost(); + dashRect.y = borderInside.y; + + if (over > 0.0f) { + firstRect.x = dashRect.x; + firstRect.y = dashRect.y; + firstRect.width = dashRect.width; + firstRect.height = nscoord(dashRect.height * over); + over = 0.0f; + currRect = firstRect; + } else { + currRect = dashRect; + } + + while (currRect.y < borderInside.YMost()) { + //clip if necessary + if (currRect.YMost() > borderInside.YMost()) { + over = float(dashRect.YMost() - borderInside.YMost()) / + float(dashRect.height); + currRect.height = currRect.height - + (currRect.YMost() - borderInside.YMost()); + } + + //draw if necessary + if (bSolid) { + aContext.FillRect(currRect); + } + + //setup for next iteration + if (over == 0.0f) { + bSolid = PRBool(!bSolid); + } + dashRect.y = dashRect.y + currRect.height; + currRect = dashRect; + } + break; + + case NS_SIDE_BOTTOM: + //if we are continuing a solid rect, fill in the corner first + if (bSolid) { + aContext.FillRect(borderInside.XMost(), borderInside.YMost(), + borderOutside.XMost() - borderInside.XMost(), + borderOutside.YMost() - borderInside.YMost()); + } + + dashRect.height = borderOutside.YMost() - borderInside.YMost(); + dashRect.width = nscoord(dashRect.height * dashLength); + dashRect.x = borderInside.XMost() - dashRect.width; + dashRect.y = borderInside.YMost(); + + if (over > 0.0f) { + firstRect.y = dashRect.y; + firstRect.width = nscoord(dashRect.width * over); + firstRect.height = dashRect.height; + firstRect.x = dashRect.x + (dashRect.width - firstRect.width); + over = 0.0f; + currRect = firstRect; + } else { + currRect = dashRect; + } + + while (currRect.XMost() > borderInside.x) { + //clip if necessary + if (currRect.x < borderInside.x) { + over = float(borderInside.x - dashRect.x) / float(dashRect.width); + currRect.width = currRect.width - (borderInside.x - currRect.x); + currRect.x = borderInside.x; + } + + //draw if necessary + if (bSolid) { + aContext.FillRect(currRect); + } + + //setup for next iteration + if (over == 0.0f) { + bSolid = PRBool(!bSolid); + } + dashRect.x = dashRect.x - currRect.width; + currRect = dashRect; + } + break; + } + } + skippedSide = PR_FALSE; + } +} + +// XXX improve this to constrain rendering to the damaged area +void nsCSSRendering::PaintBorder(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + nsIFrame* aForFrame, + const nsRect& aDirtyRect, + const nsRect& aBounds, + const nsStyleMolecule& aMolecule, + PRIntn aSkipSides) +{ + const nsMargin& border = aMolecule.border; + if ((0 == border.left) && (0 == border.right) && + (0 == border.top) && (0 == border.bottom)) { + // Empty border area + return; + } + + nsRect inside(0, 0, aBounds.width, aBounds.height); + nsRect outside(inside); + outside.Deflate(border); + + //see if any sides are dotted or dashed + for (PRIntn cnt = 0; cnt < 4; cnt++) { + if ((aMolecule.borderStyle[cnt] == NS_STYLE_BORDER_STYLE_DOTTED) || + (aMolecule.borderStyle[cnt] == NS_STYLE_BORDER_STYLE_DASHED)) { + break; + } + } + if (cnt < 4) { + // Draw the dashed/dotted lines first + DrawDashedSides(cnt, aRenderingContext, aMolecule.borderStyle, + aMolecule.borderColor, inside, outside, + aSkipSides); + } + + // Draw all the other sides + if (0 == (aSkipSides & (1<NeedsBlend()) { + if (0 == (aColor.mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT)) { + aRenderingContext.SetColor(aColor.mBackgroundColor); + aRenderingContext.FillRect(0, 0, aBounds.width, aBounds.height); + } + } +#endif + + // Convert image dimensions into nscoord's + float p2t = aPresContext.GetPixelsToTwips(); + nscoord tileWidth = nscoord(p2t * image->GetWidth()); + nscoord tileHeight = nscoord(p2t * image->GetHeight()); + + PRIntn repeat = aColor.mBackgroundRepeat; + PRIntn xcount, ycount; + switch (aColor.mBackgroundRepeat) { + case NS_STYLE_BG_REPEAT_OFF: + default: + xcount = 0; + ycount = 0; + break; + case NS_STYLE_BG_REPEAT_X: + xcount = (PRIntn) (aBounds.width / tileWidth); + ycount = 0; + break; + case NS_STYLE_BG_REPEAT_Y: + xcount = 0; + ycount = (PRIntn) (aBounds.height / tileHeight); + break; + case NS_STYLE_BG_REPEAT_XY: + xcount = (PRIntn) (aBounds.width / tileWidth); + ycount = (PRIntn) (aBounds.height / tileHeight); + break; + } + + // Tile the background + nscoord xpos = 0, ypos = 0; + nscoord xpos0 = 0; +#if XXX + // XXX support offset positioning + PRIntn xPos = aColor.mBackgroundXPosition; + PRIntn yPos = aColor.mBackgroundXPosition; +#endif + aRenderingContext.PushState(); + aRenderingContext.SetClipRect(aDirtyRect, PR_TRUE); + PRIntn x, y; + for (y = 0; y <= ycount; ++y, ypos += tileHeight) { + for (x = 0, xpos = xpos0; x <= xcount; ++x, xpos += tileWidth) { + aRenderingContext.DrawImage(image, xpos, ypos); + } + } + aRenderingContext.PopState(); + } else { + if (0 == (aColor.mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT)) { + // XXX This step can be avoided if we have an image and it doesn't + // have any transparent pixels and the image is tiled in both + // the x and the y + aRenderingContext.SetColor(aColor.mBackgroundColor); + aRenderingContext.FillRect(0, 0, aBounds.width, aBounds.height); + } + } +} diff --git a/mozilla/layout/base/nsCSSRendering.h b/mozilla/layout/base/nsCSSRendering.h new file mode 100644 index 00000000000..e1b80fa7b17 --- /dev/null +++ b/mozilla/layout/base/nsCSSRendering.h @@ -0,0 +1,89 @@ +/* -*- 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. + */ +#ifndef nsCSSRendering_h___ +#define nsCSSRendering_h___ + +#include "nsIRenderingContext.h" +#include "nsIStyleContext.h" +struct nsPoint; + +class nsCSSRendering { +public: + /** + * Render the border for an element using css rendering rules + * for borders. aSkipSides is a bitmask of the sides to skip + * when rendering. If 0 then no sides are skipped. + */ + static void PaintBorder(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + nsIFrame* aForFrame, + const nsRect& aDirtyRect, + const nsRect& aBounds, + const nsStyleMolecule& aMolecule, + PRIntn aSkipSides); + + /** + * Render the background for an element using css rendering rules + * for backgrounds. + */ + static void PaintBackground(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + nsIFrame* aForFrame, + const nsRect& aDirtyRect, + const nsRect& aBounds, + const nsStyleColor& aColor); + + /** + * Special method to brighten a Color and have it shift to white when + * fully saturated. + */ + static nscolor Brighten(nscolor inColor); + + /** + * Special method to darken a Color and have it shift to black when + * darkest component underflows + */ + static nscolor Darken(nscolor inColor); + +protected: + static nscolor MakeBevelColor(PRIntn whichSide, PRUint8 style, + nscolor baseColor); + + static PRIntn MakeSide(nsPoint aPoints[], + nsIRenderingContext& aContext, + PRIntn whichSide, + const nsRect& inside, const nsRect& outside, + PRIntn borderPart, float borderFrac); + + static void DrawSide(nsIRenderingContext& aContext, + PRIntn whichSide, + const PRUint8 borderStyles[], + const nscolor borderColors[], + const nsRect& borderOutside, + const nsRect& borderInside); + + static void DrawDashedSides(PRIntn startSide, + nsIRenderingContext& aContext, + const PRUint8 borderStyles[], + const nscolor borderColors[], + const nsRect& borderOutside, + const nsRect& borderInside, + PRIntn aSkipSides); +}; + +#endif /* nsCSSRendering_h___ */ diff --git a/mozilla/layout/base/nsIPresShell.h b/mozilla/layout/base/nsIPresShell.h new file mode 100644 index 00000000000..7a88f3d12c6 --- /dev/null +++ b/mozilla/layout/base/nsIPresShell.h @@ -0,0 +1,103 @@ +/* -*- 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. + */ +#ifndef nsIPresShell_h___ +#define nsIPresShell_h___ + +#include "nslayout.h" +#include "nsIDocumentObserver.h" +#include "nsCoord.h" +class nsIContent; +class nsIDocument; +class nsIFrame; +class nsIPresContext; +class nsIStyleSet; +class nsIViewManager; +class nsReflowCommand; + +#define NS_IPRESSHELL_IID \ +{ 0x76e79c60, 0x944e, 0x11d1, \ + {0x93, 0x23, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +/** + * Presentation shell interface. Presentation shells are the + * controlling point for managing the presentation of a document. The + * presentation shell holds a live reference to the document, the + * presentation context, the style manager, the style set and the root + * frame.

+ * + * When this object is Release'd, it will release the document, the + * presentation context, the style manager, the style set and the root + * frame. + */ +class nsIPresShell : public nsIDocumentObserver { +public: + virtual nsresult Init(nsIDocument* aDocument, + nsIPresContext* aPresContext, + nsIViewManager* aViewManager, + nsIStyleSet* aStyleSet) = 0; + + virtual nsIDocument* GetDocument() = 0; + + virtual nsIPresContext* GetPresContext() = 0; + + virtual nsIViewManager * GetViewManager() = 0; + + virtual nsIStyleSet* GetStyleSet() = 0; + + // Make shell be a document observer + virtual void BeginObservingDocument() = 0; + + // Make shell stop being a document observer + virtual void EndObservingDocument() = 0; + + /** + * Reflow the frame model into a new width and height. The + * coordinates for aWidth and aHeight must be in standard nscoord's. + */ + virtual void ResizeReflow(nscoord aWidth, nscoord aHeight) = 0; + + virtual nsIFrame* GetRootFrame() = 0; + + virtual nsIFrame* FindFrameWithContent(nsIContent* aContent) = 0; + + virtual void AppendReflowCommand(nsReflowCommand* aReflowCommand) = 0; + + virtual void ProcessReflowCommands() = 0; + + /** + * Place some cached data into the shell's cache. The key for + * the cache is the given frame. + */ + virtual void PutCachedData(nsIFrame* aKeyFrame, void* aData) = 0; + + virtual void* GetCachedData(nsIFrame* aKeyFrame) = 0; + + virtual void* RemoveCachedData(nsIFrame* aKeyFrame) = 0; + + // XXX events + // XXX selection +}; + +/** + * Create a new empty presentation shell. Upon success, call Init + * before attempting to use the shell. + */ +extern NS_LAYOUT nsresult + NS_NewPresShell(nsIPresShell** aInstancePtrResult); + +#endif /* nsIPresShell_h___ */ diff --git a/mozilla/layout/base/nsPresContext.cpp b/mozilla/layout/base/nsPresContext.cpp new file mode 100644 index 00000000000..36784d930b1 --- /dev/null +++ b/mozilla/layout/base/nsPresContext.cpp @@ -0,0 +1,463 @@ +/* -*- 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 "nsPresContext.h" +#include "nsIPresShell.h" +#include "nsILinkHandler.h" +#include "nsIStyleContext.h" +#include "nsIStyleSet.h" +#include "nsIFontMetrics.h" +#include "nsIImageManager.h" +#include "nsIImageGroup.h" +#include "nsIImageRequest.h" +#include "nsIImageObserver.h" +#include "nsIView.h" +#include "nsIViewManager.h" +#include "nsIFrame.h" +#include "nsIRenderingContext.h" +#include "nsTransform2D.h" +#include "nsIDocument.h" +#include "nsIURL.h" +#include "nsString.h" + +static NS_DEFINE_IID(kIPresContextIID, NS_IPRESCONTEXT_IID); + +// XXX this code needs to move far away from here +static nsIImageManager* gImageManager = nsnull; +static void InitImageLibrary() +{ + // Initialize image library + if (NS_OK == NS_NewImageManager(&gImageManager)) { + if (NS_OK == gImageManager->Init()) { + gImageManager->SetCacheSize(1024*1024); + return; + } + } + printf("can't initialize image library\n"); +} +// XXX end code with no home... + +class ImageLoader : nsIImageRequestObserver { +public: + ImageLoader(nsPresContext* aCX, nsIImageGroup* aGroup, nsIFrame* aFrame); + ~ImageLoader(); + + NS_DECL_ISUPPORTS + + void LoadImage(const nsString& aURL); + + const nsString& GetURL() const { + return mURL; + } + + nsIImage* GetImage() { + return mImage; + } + + PRInt32 FrameCount(); + + PRBool RemoveFrame(nsIFrame* aFrame); + + void AddFrame(nsIFrame* aFrame); + + void UpdateFrames(); + + virtual void Notify(nsIImageRequest *aImageRequest, + nsIImage *aImage, + nsImageNotification aNotificationType, + PRInt32 aParam1, PRInt32 aParam2, + void *aParam3); + + virtual void NotifyError(nsIImageRequest *aImageRequest, + nsImageError aErrorType); + + nsVoidArray mFrames; + nsString mURL; + nsPresContext* mCX; + nsIImage* mImage; + nsIImageRequest* mImageRequest; + nsIImageGroup* mImageGroup; + + PRInt32 mWidth, mHeight; // in pixels +}; + +ImageLoader::ImageLoader(nsPresContext* aCX, nsIImageGroup* aGroup, + nsIFrame* aFrame) +{ + mCX = aCX; + AddFrame(aFrame); + mImage = nsnull; + mImageRequest = nsnull; + mImageGroup = aGroup; NS_ADDREF(aGroup); + mWidth = -1; + mHeight = -1; +} + +ImageLoader::~ImageLoader() +{ + if (nsnull != mImageRequest) { + mImageRequest->Interrupt(); + mImageRequest->RemoveObserver(this); + } +} + +void ImageLoader::LoadImage(const nsString& aURL) +{ + if (nsnull == mImage) { + // Save url + mURL.SetLength(0); + mURL.Append(aURL); + + // Start image load + char* cp = aURL.ToNewCString(); + mImageRequest = mImageGroup->GetImage(cp, this, NS_RGB(255,255,255), + 0, 0, 0); + delete cp; + } +} + +static NS_DEFINE_IID(kIImageRequestObserver, NS_IIMAGEREQUESTOBSERVER_IID); + +NS_IMPL_ISUPPORTS(ImageLoader, kIImageRequestObserver); + +static PRBool gXXXInstalledColorMap; +void ImageLoader::Notify(nsIImageRequest *aImageRequest, + nsIImage *aImage, + nsImageNotification aNotificationType, + PRInt32 aParam1, PRInt32 aParam2, + void *aParam3) +{ + switch (aNotificationType) { + case nsImageNotification_kDimensions: +#ifdef NOISY + printf("Image:%d x %d\n", aParam1, aParam2); +#endif + mWidth = aParam1; + mHeight = aParam2; + break; + + case nsImageNotification_kPixmapUpdate: + case nsImageNotification_kImageComplete: + case nsImageNotification_kFrameComplete: + if ((mImage == nsnull) && (nsnull != aImage)) { + mImage = aImage; + NS_ADDREF(aImage); + } + UpdateFrames(); + } +} + +PRInt32 ImageLoader::FrameCount() +{ + return mFrames.Count(); +} + +PRBool ImageLoader::RemoveFrame(nsIFrame* aFrame) +{ + return mFrames.RemoveElement(aFrame); +} + +void ImageLoader::AddFrame(nsIFrame* aFrame) +{ + PRInt32 i, n = mFrames.Count(); + for (i = 0; i < n; i++) { + nsIFrame* frame = (nsIFrame*) mFrames.ElementAt(i); + if (frame == aFrame) { + return; + } + } + mFrames.AppendElement(aFrame); +} + +void ImageLoader::UpdateFrames() +{ + PRInt32 i, n = mFrames.Count(); + for (i = 0; i < n; i++) { + nsIFrame* frame = (nsIFrame*) mFrames.ElementAt(i); + + // XXX installed colormap should be presentation-context/window state + nsIWidget* window = frame->GetWindow(); + if (!gXXXInstalledColorMap && mImage) { + nsColorMap* cmap = mImage->GetColorMap(); + if ((nsnull != cmap) && (cmap->NumColors > 0)) { + window->SetColorMap(cmap); + } + gXXXInstalledColorMap = PR_TRUE; + } + + // Determine damaged area and tell view manager to redraw it + nsPoint offset; + nsRect bounds; + frame->GetRect(bounds); + nsIView* view = frame->GetOffsetFromView(offset); + nsIViewManager* vm = view->GetViewManager(); + bounds.x = offset.x; + bounds.y = offset.y; + vm->UpdateView(view, &bounds, 0); + NS_RELEASE(vm); + NS_RELEASE(view); + } +} + +void ImageLoader::NotifyError(nsIImageRequest *aImageRequest, + nsImageError aErrorType) +{ + printf("XXX image error: %d\n", aErrorType); +} + +//---------------------------------------------------------------------- + +nsPresContext::nsPresContext() + : mVisibleArea(0, 0, 0, 0), + mDefaultFont("Times", NS_FONT_STYLE_NORMAL, + NS_FONT_VARIANT_NORMAL, + NS_FONT_WEIGHT_NORMAL, + 0, + NS_POINTS_TO_TWIPS_INT(12)) +{ + NS_INIT_REFCNT(); + mShell = nsnull; + mDeviceContext = nsnull; + mImageGroup = nsnull; + mLinkHandler = nsnull; + mContainer = nsnull; +} + +nsPresContext::~nsPresContext() +{ + mShell = nsnull; + + // XXX there is a race between an async notify and this code because + // the presentation shell code deletes the frame tree first and then + // deletes us. We need an "Deactivation" hook for this code too + + // Release all the image loaders + PRInt32 n = mImageLoaders.Count(); + for (PRInt32 i = 0; i < n; i++) { + ImageLoader* loader = (ImageLoader*) mImageLoaders.ElementAt(i); + delete loader; + } + + // XXX Release all the cached images + + if (nsnull != mImageGroup) { + mImageGroup->Interrupt(); + NS_RELEASE(mImageGroup); + } + + NS_IF_RELEASE(mLinkHandler); + NS_IF_RELEASE(mContainer); +} + +nsrefcnt nsPresContext::AddRef(void) +{ + return ++mRefCnt; +} + +nsrefcnt nsPresContext::Release(void) +{ + NS_PRECONDITION(0 != mRefCnt, "bad refcnt"); + if (--mRefCnt == 0) { + delete this; + return 0; + } + return mRefCnt; +} + +NS_IMPL_QUERY_INTERFACE(nsPresContext, kIPresContextIID); + +// Note: We don't hold a reference on the shell; it has a reference to +// us +void nsPresContext::SetShell(nsIPresShell* aShell) +{ + mShell = aShell; +} + +nsIPresShell* nsPresContext::GetShell() +{ + if (nsnull != mShell) { + NS_ADDREF(mShell); + } + return mShell; +} + +nsIStyleContext* +nsPresContext::ResolveStyleContextFor(nsIContent* aContent, + nsIFrame* aParentFrame) +{ + nsIStyleContext* result = nsnull; + + nsIStyleSet* set = mShell->GetStyleSet(); + if (nsnull != set) { + result = set->ResolveStyleFor(this, aContent, aParentFrame); + NS_RELEASE(set); + } + + return result; +} + +nsIFontMetrics* nsPresContext::GetMetricsFor(const nsFont& aFont) +{ + if (nsnull != mDeviceContext) + return mDeviceContext->GetMetricsFor(aFont); + + return nsnull; +} + +const nsFont& nsPresContext::GetDefaultFont(void) +{ + return mDefaultFont; +} + +nsRect nsPresContext::GetVisibleArea() +{ + return mVisibleArea; +} + +void nsPresContext::SetVisibleArea(const nsRect& r) +{ + mVisibleArea = r; +} + +float nsPresContext::GetPixelsToTwips() const +{ + if (nsnull != mDeviceContext) + return mDeviceContext->GetDevUnitsToAppUnits(); + + return 1.0f; +} + +float nsPresContext::GetTwipsToPixels() const +{ + if (nsnull != mDeviceContext) + return mDeviceContext->GetAppUnitsToDevUnits(); + + return 1.0f; +} + +nsIDeviceContext * nsPresContext::GetDeviceContext() const +{ + NS_IF_ADDREF(mDeviceContext); + return mDeviceContext; +} + +nsIImage* nsPresContext::LoadImage(const nsString& aURL, nsIFrame* aForFrame) +{ + if (nsnull == mImageGroup) { + // XXX this is bad; if we allow for subwindows that have different + // rendering context's this won't work + nsIWidget* window = aForFrame->GetWindow(); + nsIRenderingContext* drawCtx = window->GetRenderingContext(); + drawCtx->Scale(mDeviceContext->GetAppUnitsToDevUnits(), + mDeviceContext->GetAppUnitsToDevUnits()); + if ((NS_OK != NS_NewImageGroup(&mImageGroup)) || + (NS_OK != mImageGroup->Init(drawCtx))) { + // XXX what to do? + printf("XXX: can't get image group created\n"); + NS_RELEASE(drawCtx); + return nsnull; + } + NS_RELEASE(drawCtx); + } + + // Get absolute version of the url + nsIDocument* doc = mShell->GetDocument(); + nsIURL* docURL = doc->GetDocumentURL(); + char* spec = aURL.ToNewCString(); + nsIURL* url; + nsresult rv = NS_NewURL(&url, docURL, spec); + delete spec; + NS_RELEASE(docURL); + NS_RELEASE(doc); + if (NS_OK != rv) { + // XXX lost error + return nsnull; + } + nsAutoString absURL; + url->ToString(absURL); + NS_RELEASE(url); + + PRInt32 n = mImageLoaders.Count(); + for (PRInt32 i = 0; i < n; i++) { + ImageLoader* loader = (ImageLoader*) mImageLoaders.ElementAt(i); + if (absURL.Equals(loader->GetURL())) { + loader->AddFrame(aForFrame); + return loader->GetImage(); + } + } + + ImageLoader* loader = new ImageLoader(this, mImageGroup, aForFrame); + mImageLoaders.AppendElement(loader); + + loader->LoadImage(absURL); + return loader->GetImage(); +} + +void nsPresContext::StopLoadImage(nsIFrame* aForFrame) +{ + PRInt32 n = mImageLoaders.Count(); + for (PRInt32 i = 0; i < n;) { + ImageLoader* loader = (ImageLoader*) mImageLoaders.ElementAt(i); + if (loader->RemoveFrame(aForFrame)) { + if (0 == loader->FrameCount()) { + delete loader; + mImageLoaders.RemoveElementAt(i); + n--; + continue; + } + } + i++; + } +} + +NS_IMETHODIMP nsPresContext::SetLinkHandler(nsILinkHandler* aHandler) +{ + NS_IF_RELEASE(mLinkHandler); + mLinkHandler = aHandler; + NS_IF_ADDREF(aHandler); + return NS_OK; +} + +NS_IMETHODIMP nsPresContext::GetLinkHandler(nsILinkHandler** aResult) +{ + NS_PRECONDITION(nsnull != aResult, "null ptr"); + if (nsnull == aResult) { + return NS_ERROR_NULL_POINTER; + } + *aResult = mLinkHandler; + NS_IF_ADDREF(mLinkHandler); + return NS_OK; +} + +NS_IMETHODIMP nsPresContext::SetContainer(nsISupports* aHandler) +{ + NS_IF_RELEASE(mContainer); + mContainer = aHandler; + NS_IF_ADDREF(aHandler); + return NS_OK; +} + +NS_IMETHODIMP nsPresContext::GetContainer(nsISupports** aResult) +{ + NS_PRECONDITION(nsnull != aResult, "null ptr"); + if (nsnull == aResult) { + return NS_ERROR_NULL_POINTER; + } + *aResult = mContainer; + NS_IF_ADDREF(mContainer); + return NS_OK; +} diff --git a/mozilla/layout/base/nsPresContext.h b/mozilla/layout/base/nsPresContext.h new file mode 100644 index 00000000000..916ea9538b5 --- /dev/null +++ b/mozilla/layout/base/nsPresContext.h @@ -0,0 +1,150 @@ +/* -*- 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. + */ +#ifndef nsIPresContext_h___ +#define nsIPresContext_h___ + +#include "nslayout.h" +#include "nsISupports.h" +#include "nsRect.h" + +class nsIImage; +class nsILinkHandler; +class nsIPresShell; +class nsIRenderingContext; +class nsIFrame; +class nsIStyleContext; +class nsIFontMetrics; +class nsIContent; +class nsViewManager; +class nsIView; +class nsIFontCache; +class nsIDeviceContext; +class nsString; +struct nsFont; + +#define NS_IPRESCONTEXT_IID \ +{ 0x0a5d12e0, 0x944e, 0x11d1, \ + {0x93, 0x23, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + + +// An interface for presentation contexts. Presentation contexts are +// objects that provide an outer context for a presentation shell. +class nsIPresContext : public nsISupports { +public: + /** + * Set the presentation shell that this context is bound to. + * A presentation context may only be bound to a single shell. + */ + virtual void SetShell(nsIPresShell* aShell) = 0; + + /** + * Get the PresentationShell that this context is bound to. + */ + virtual nsIPresShell* GetShell() = 0; + + /** + * Resolve style for the given piece of content that will be a child + * of the aParentFrame frame. + */ + virtual nsIStyleContext* ResolveStyleContextFor(nsIContent* aContent, + nsIFrame* aParentFrame) = 0; + + /** + * Get the font metrics for a given font. + */ + virtual nsIFontMetrics* GetMetricsFor(const nsFont& aFont) = 0; + + /** + * Get the default font + */ + virtual const nsFont& GetDefaultFont(void) = 0; + + /** + * Load an image for the given url name for the given frame. When + * the image is ready for rendering the frame will be repainted. + * + * If the image is ready then this method will return the image, + * otherwise it will return nsnull and guarantee that the frame + * is repained when the image is ready. + * + * XXX this api needs work; the frame can't find out the size when + * it arrives nor can it find out any error information, etc. + */ + virtual nsIImage* LoadImage(const nsString& aURL, nsIFrame* aForFrame) = 0; + + /** + * Stop any image loading being done on behalf of the argument frame. + */ + virtual void StopLoadImage(nsIFrame* aForFrame) = 0; + + NS_IMETHOD SetContainer(nsISupports* aContainer) = 0; + + NS_IMETHOD GetContainer(nsISupports** aResult) = 0; + + NS_IMETHOD SetLinkHandler(nsILinkHandler* aHandler) = 0; + + NS_IMETHOD GetLinkHandler(nsILinkHandler** aResult) = 0; + + /** + * Get the currently visible portion of the RootContent ILayoutable. + * The units returned are in pixels. An acceptable answer is "null" + * which means "I don't know". + *

Speculative

+ */ + virtual nsRect GetVisibleArea() = 0; + + /** + * Set the currently visible area. This is the size and location + * of the visible portion of the RootContent ILayoutable. + */ + virtual void SetVisibleArea(const nsRect& r) = 0; + + /** + * Return true if this presentation context is a paginated + * context. + */ + virtual PRBool IsPaginated() = 0; + + /** + * Return the page width if this is a paginated context. + */ + virtual nscoord GetPageWidth() = 0; + + /** + * Return the page height if this is a paginated context + */ + virtual nscoord GetPageHeight() = 0; + + virtual float GetPixelsToTwips() const = 0; + virtual float GetTwipsToPixels() const = 0; + + //be sure to Relase() after you are done with the Get() + virtual nsIDeviceContext * GetDeviceContext() const = 0; +}; + +// Factory method to create a "galley" presentation context (galley is +// a kind of view that has no limit to the size of a page) +extern NS_LAYOUT nsresult + NS_NewGalleyContext(nsIPresContext** aInstancePtrResult); + +// Factory method to create a "paginated" presentation context for +// the screen. +extern NS_LAYOUT nsresult + NS_NewPrintPreviewContext(nsIPresContext** aInstancePtrResult); + +#endif /* nsIPresContext_h___ */ diff --git a/mozilla/layout/base/public/Makefile b/mozilla/layout/base/public/Makefile new file mode 100644 index 00000000000..6ff66f67d9d --- /dev/null +++ b/mozilla/layout/base/public/Makefile @@ -0,0 +1,40 @@ +#!gmake +# +# 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. + +DEPTH = ../../.. + +EXPORTS = \ + nsIContent.h \ + nsIContentDelegate.h \ + nsIDocument.h \ + nsIDocumentContainer.h \ + nsIDocumentObserver.h \ + nsIFrame.h \ + nsIPresContext.h \ + nsIPresShell.h \ + nsIRunaround.h \ + nsISpaceManager.h \ + nsIStyleContext.h \ + nsIStyleRule.h \ + nsIStyleSet.h \ + nsIStyleSheet.h \ + nsITextContent.h \ + $(NULL) + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/layout/base/public/makefile.win b/mozilla/layout/base/public/makefile.win new file mode 100644 index 00000000000..fa8a4f91739 --- /dev/null +++ b/mozilla/layout/base/public/makefile.win @@ -0,0 +1,43 @@ +#!nmake +# +# 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. + +DEPTH=..\..\.. +IGNORE_MANIFEST=1 + +EXPORTS = \ + nslayout.h \ + nsIContent.h \ + nsIContentDelegate.h \ + nsIDocument.h \ + nsIDocumentContainer.h \ + nsIDocumentObserver.h \ + nsIFrame.h \ + nsIPresContext.h \ + nsIPresShell.h \ + nsIRunaround.h \ + nsISpaceManager.h \ + nsIStyleContext.h \ + nsIStyleRule.h \ + nsIStyleSet.h \ + nsIStyleSheet.h \ + nsITextContent.h \ + $(NULL) + +MODULE=raptor + +include <$(DEPTH)\config\rules.mak> + diff --git a/mozilla/layout/base/public/nsIContent.h b/mozilla/layout/base/public/nsIContent.h new file mode 100644 index 00000000000..70a8b75779d --- /dev/null +++ b/mozilla/layout/base/public/nsIContent.h @@ -0,0 +1,116 @@ +/* -*- 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. + */ +#ifndef nsIContent_h___ +#define nsIContent_h___ + +#include +#include "nslayout.h" +#include "nsISupports.h" +class nsIAtom; +class nsIContentDelegate; +class nsIDocument; +class nsIPresContext; +class nsISizeofHandler; +class nsString; +class nsString; +class nsVoidArray; + +// IID for the nsIContent interface +#define NS_ICONTENT_IID \ +{ 0x78030220, 0x9447, 0x11d1, \ + {0x93, 0x23, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +/** + * Content attribute states + */ +enum nsContentAttr { + // Attribute does not exist on the piece of content + eContentAttr_NotThere, + + // Attribute exists, but has no value, e.g. "BORDER" in + eContentAttr_NoValue, + + // Attribute exists and has a value. However, value may be the + // empty string. e.g.
or
+ eContentAttr_HasValue, +}; + +// A node of content in a documents content model. This interface +// is supported by all content objects. +class nsIContent : public nsISupports +{ +public: + virtual nsIDocument* GetDocument() const = 0; + virtual void SetDocument(nsIDocument* aDocument) = 0; + + virtual nsIContent* GetParent() const = 0; + virtual void SetParent(nsIContent* aParent) = 0; + + virtual PRBool CanContainChildren() const = 0; + virtual PRInt32 ChildCount() const = 0; + virtual nsIContent* ChildAt(PRInt32 aIndex) const = 0; + virtual PRInt32 IndexOf(nsIContent* aPossibleChild) const = 0; + virtual PRBool InsertChildAt(nsIContent* aKid, PRInt32 aIndex) = 0; + virtual PRBool ReplaceChildAt(nsIContent* aKid, PRInt32 aIndex) = 0; + virtual PRBool AppendChild(nsIContent* aKid) = 0; + virtual PRBool RemoveChildAt(PRInt32 aIndex) = 0; + + virtual nsIAtom* GetTag() const = 0; + + /** + * Set attribute values. All attribute values are assumed to have a + * canonical String representation that can be used for these + * methods. The setAttribute method is assumed to perform a translation + * of the canonical form into the underlying content specific + * form. + * + * aValue may legitimately be the empty string. + */ + virtual void SetAttribute(const nsString& aName, const nsString& aValue) = 0; + + /** + * Get the current value of the attribute. This returns a form that is + * suitable for passing back into setAttribute. + * + *
    + * + *
  • If the attribute is not set and has no default value, return + * eContentAttr_NotThere. + * + *
  • If the attribute exists, but has no value, return + * eContentAttr_NoValue. + * + *
  • If the attribute has a value, empty or otherwise, set ret to + * be the value, and return eContentAttr_HasValue. + * + *
*/ + virtual nsContentAttr GetAttribute(const nsString& aName, + nsString& aResult) const = 0; + + virtual nsIContentDelegate* GetDelegate(nsIPresContext* aCX) = 0; + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const = 0; + + /** + * Return the number of bytes consumed by this node of content and + * anything that it can reach. + */ + virtual PRUint32 SizeOf(nsISizeofHandler* aHandler) const = 0; +}; + +#endif /* nsIContent_h___ */ diff --git a/mozilla/layout/base/public/nsIContentDelegate.h b/mozilla/layout/base/public/nsIContentDelegate.h new file mode 100644 index 00000000000..e2d50297c60 --- /dev/null +++ b/mozilla/layout/base/public/nsIContentDelegate.h @@ -0,0 +1,45 @@ +/* -*- 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. + */ +#ifndef nsIContentDelegate_h___ +#define nsIContentDelegate_h___ + +#include "nslayout.h" +class nsIFrame; +class nsIPresContext; + +#define NS_ICONTENTDELEGATE_IID \ + { 0x0f135ce0, 0xa286, 0x11d1, \ + {0x89, 0x73, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } + +/** + * API for content delegation. Content objects create these objects to + * provide hooks to creating their visual presentation. + */ +class nsIContentDelegate : public nsISupports { +public: + /** + * Create a new frame object that will be responsible for the layout + * and presentation of the content. + */ + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) = 0; +}; + +#endif /* nsIContentDelegate_h___ */ diff --git a/mozilla/layout/base/public/nsIDocument.h b/mozilla/layout/base/public/nsIDocument.h new file mode 100644 index 00000000000..a5cc20bb98e --- /dev/null +++ b/mozilla/layout/base/public/nsIDocument.h @@ -0,0 +1,163 @@ +/* -*- 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. + */ +#ifndef nsIDocument_h___ +#define nsIDocument_h___ + +#include "nslayout.h" +#include "nsISupports.h" +#include "nsIUnicharInputStream.h" +class nsIArena; +class nsIContent; +class nsIDocumentContainer; +class nsIDocumentObserver; +class nsIPresContext; +class nsIPresShell; +class nsISubContent; +class nsIStyleSet; +class nsIStyleSheet; +class nsIURL; +class nsIViewManager; +class nsString; + +// IID for the nsIDocument interface +#define NS_IDOCUMENT_IID \ +{ 0x94c6ceb0, 0x9447, 0x11d1, \ + {0x93, 0x23, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +//---------------------------------------------------------------------- + +// Document interface +class nsIDocument : public nsISupports { +public: + // All documents have a memory arena associated with them which is + // used for memory allocation during document creation. This call + // returns the arena associated with this document. + virtual nsIArena* GetArena() = 0; + + virtual void LoadURL(nsIURL* aURL) = 0; + + virtual void StartDocumentLoad() = 0; + virtual void PauseDocumentLoad() = 0; + virtual void StopDocumentLoad() = 0; + virtual void WaitForDocumentLoad() = 0; + virtual PRBool IsDocumentLoaded() = 0; + + /** + * Return the title of the document. May return null. + */ + virtual const nsString* GetDocumentTitle() const = 0; + + /** + * Return the URL for the document. May return null. + */ + virtual nsIURL* GetDocumentURL() const = 0; + + /** + * Return a standard name for the document's character set. This will + * trigger a startDocumentLoad if necessary to answer the question. + */ + virtual nsCharSetID GetDocumentCharacterSet() const = 0; + virtual void SetDocumentCharacterSet(nsCharSetID aCharSetID) = 0; + + /** + * Create a new presentation shell that will use aContext for + * it's presentation context (presentation context's must not be + * shared among multiple presentation shell's). + */ + virtual nsIPresShell* CreateShell(nsIPresContext* aContext, + nsIViewManager* aViewManager, + nsIStyleSet* aStyleSet) = 0; + virtual PRBool DeleteShell(nsIPresShell* aShell) = 0; + virtual PRInt32 GetNumberOfShells() = 0; + virtual nsIPresShell* GetShellAt(PRInt32 aIndex) = 0; + + /** + * Return the parent document of this document. Will return null + * unless this document is within a compound document and has a parent. + */ + virtual nsIDocument* GetParentDocument() = 0; + virtual void SetParentDocument(nsIDocument* aParent) = 0; + virtual void AddSubDocument(nsIDocument* aSubDoc) = 0; + virtual PRInt32 GetNumberOfSubDocuments() = 0; + virtual nsIDocument* GetSubDocumentAt(PRInt32 aIndex) = 0; + + /** + * Return the root content object for this document. + */ + virtual nsIContent* GetRootContent() = 0; + virtual void SetRootContent(nsIContent* aRoot) = 0; + + /** + * Get the style sheets owned by this document. + */ + virtual PRInt32 GetNumberOfStyleSheets() = 0; + virtual nsIStyleSheet* GetStyleSheetAt(PRInt32 aIndex) = 0; + virtual void AddStyleSheet(nsIStyleSheet* aSheet) = 0; + + //---------------------------------------------------------------------- + + // Document notification API's + + /** + * Add a new observer of document change notifications. Whenever + * content is changed, appended, inserted or removed the observers are + * informed. + */ + virtual void AddObserver(nsIDocumentObserver* aObserver) = 0; + + /** + * Remove an observer of document change notifications. This will + * return false if the observer cannot be found. + */ + virtual PRBool RemoveObserver(nsIDocumentObserver* aObserver) = 0; + + // Observation hooks used by content nodes to propagate + // notifications to document observers. + virtual void ContentChanged(nsIContent* aContent, + nsISubContent* aSubContent, + PRInt32 aChangeType) = 0; + + virtual void ContentAppended(nsIContent* aContainer) = 0; + + virtual void ContentInserted(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) = 0; + + virtual void ContentReplaced(nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer) = 0; + + virtual void ContentWillBeRemoved(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) = 0; + + virtual void ContentHasBeenRemoved(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) = 0; +}; + +// XXX Belongs somewhere else +extern NS_LAYOUT nsresult + NS_NewHTMLDocument(nsIDocument** aInstancePtrResult); + +// XXX temporary - it's going away! +extern NS_LAYOUT void + NS_HackAppendContent(nsIDocument* aDoc); + +#endif /* nsIDocument_h___ */ diff --git a/mozilla/layout/base/public/nsIDocumentContainer.h b/mozilla/layout/base/public/nsIDocumentContainer.h new file mode 100644 index 00000000000..96862447dc2 --- /dev/null +++ b/mozilla/layout/base/public/nsIDocumentContainer.h @@ -0,0 +1,71 @@ +/* -*- 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. + */ +#ifndef nsIDocumentContainer_h___ +#define nsIDocumentContainer_h___ + +#include "nsISupports.h" +class nsIScriptable; +class nsIScriptEnvironment; +class nsIURL; + +#define NS_IDOCUMENT_CONTAINER_IID \ +{ 0x8efd4470, 0x944d, 0x11d1, \ + {0x93, 0x23, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +class nIDocumentContainer : public nsISupports { +public: + /** + * Display the specified URL with the given connection. + * + * @param url the URL to display + * @param connection the connection to use. + */ + virtual void Display(nsIURL* aURL) = 0; + + /** + * Returns a script environment for the specified language and version. + * The expectation is that the script environment already has been + * set up with a container object. If a script environment has already + * been requested for the given language, the same instance should + * be returned. + * + * @param language the scripting language for the environment. If this + * is null, returns the default scripting environment. + * @param majorVersion the major version number of the language + * @param minorVersion the minor version number of the language + * @return the script environment for the language + * @see mg.magellan.script.IScriptEnvrionment + */ + virtual nsIScriptEnvironment* + GetScriptEnvironment(nsString* aLanguage, + PRInt32 aMajorVersion, + PRInt32 aMinorVersion) = 0; + + /** + * Returns the scriptable container object for the document container. + * The scriptable object will be used as the scoping object in the + * definition of scriptable classes used in the Document Object Model. + * + * @return the scriptable container for the application + * @see mg.magellan.script.IScriptable + * @see mg.magellan.script.IScriptEnvrionment + */ + virtual nsIScriptable* GetScriptableContainer() = 0; +} + +#endif /* nsIDocumentContainer_h___ */ diff --git a/mozilla/layout/base/public/nsIDocumentObserver.h b/mozilla/layout/base/public/nsIDocumentObserver.h new file mode 100644 index 00000000000..54fdc6ef4a2 --- /dev/null +++ b/mozilla/layout/base/public/nsIDocumentObserver.h @@ -0,0 +1,160 @@ +/* -*- 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. + */ +#ifndef nsIDocumentObserver_h___ +#define nsIDocumentObserver_h___ + +#include "nsISupports.h" +class nsIContent; +class nsISubContent; +class nsIStyleSheet; +class nsString; + +#define NS_IDOCUMENTOBSERVER_IID \ +{ 0xb3f92460, 0x944c, 0x11d1, \ + {0x93, 0x23, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +// Document observer interface +class nsIDocumentObserver : public nsISupports { +public: + /** + * This is called when the documents title has arrived. + */ + NS_IMETHOD SetTitle(const nsString& aTitle) = 0; + + /** + * Notify that a content model update is beginning. This call can be + * nested. + */ + virtual void BeginUpdate() = 0; + + /** + * Notify that a content model update is finished. This call can be + * nested. + */ + virtual void EndUpdate() = 0; + + /** + * Notification that the content model has changed. This method is + * called automatically by content objects when their state is changed + * (therefore there is normally no need to invoke this method + * directly). The notification is passed to any + * IDocumentObservers. The notification is passed on to all of the + * document observers.

+ * + * This notification is not sent when a piece of content is + * added/removed from the document (the other notifications are used + * for that). + * + * @param aContent the piece of content that changed + * @param aSubContent subrange information about the piece of content + * that change + * @param aChangeType one of the change types (kLogicalChange, + * kPhysicalChange or kRenderingChange) + */ + virtual void ContentChanged(nsIContent* aContent, + nsISubContent* aSubContent, + PRInt32 aChangeType) = 0; + + /** + * Notifcation that the content model has had data appended to the + * given content object. This method is called automatically by the + * content container objects when a new content object is appended to + * the container (therefore there is normally no need to invoke this + * method directly). The notification is passed on to all of the + * document observers. + * + * @param aContainer the container that had a new child appended + */ + virtual void ContentAppended(nsIContent* aContainer) = 0; + + /** + * Notification that content has been inserted. This method is called + * automatically by the content container objects when a new content + * object is inserted in the container (therefore there is normally no + * need to invoke this method directly). The notification is passed on + * to all of the document observers. + * + * @param aContainer the container that now contains aChild + * @param aChild the child that was inserted + * @param aIndexInContainer the index of the child in the container + */ + virtual void ContentInserted(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) = 0; + + /** + * Notification that content has been replaced. This method is called + * automatically by the content container objects when a content object + * is replaced in the container (therefore there is normally no need to + * invoke this method directly). The notification is passed on to all + * of the document observers. + * + * @param aContainer the container that now contains aChild + * @param aOldChild the child that was replaced + * @param aNewChild the child that replaced aOldChild + * @param aIndexInContainer the index of the old and new child in the + * container + */ + virtual void ContentReplaced(nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer) = 0; + + /** + * Content is going to be removed immediately after this call. This + * method is called automatically by content container objects when a + * content object is about to be removed from the container (therefore + * there is normally no need to invoke this method directly). The + * notification is passed on to all of the document observers. + * + * @param aContainer the container that contains aChild + * @param aChild the child that will be removed + * @param aIndexInContainer the index of the child in the container + */ + virtual void ContentWillBeRemoved(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) = 0; + + /** + * Content has just been removed. This method is called automatically + * by content container objects when a content object has just been + * removed from the container (therefore there is normally no need to + * invoke this method directly). The notification is passed on to all + * of the document observers. + * + * @param aContainer the container that had a child removed + * @param aChild the child that was just removed + * @param aIndexInContainer the index of the child in the container + * before it was removed + */ + virtual void ContentHasBeenRemoved(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) = 0; + + /** + * A StyleSheet has just been added to the document. + * This method is called automatically when a StyleSheet gets added + * to the document. The notification is passed on to all of the + * document observers. + * + * @param aStyleSheet the StyleSheet that has been added + */ + virtual void StyleSheetAdded(nsIStyleSheet* aStyleSheet) = 0; +}; + +#endif /* nsIDocumentObserver_h___ */ diff --git a/mozilla/layout/base/public/nsIFrame.h b/mozilla/layout/base/public/nsIFrame.h new file mode 100644 index 00000000000..25db0e7323b --- /dev/null +++ b/mozilla/layout/base/public/nsIFrame.h @@ -0,0 +1,385 @@ +/* -*- 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. + */ +#ifndef nsIFrame_h___ +#define nsIFrame_h___ + +#include +#include "nslayout.h" +#include "nsISupports.h" +#include "nsSize.h" +#include "nsGUIEvent.h" + +class nsIContent; +class nsIPresContext; +class nsIPresShell; +class nsIRenderingContext; +class nsISpaceManager; +class nsIStyleContext; +class nsIView; +class nsIWidget; +class nsReflowCommand; + +struct nsStyleStruct; +struct nsGUIEvent; + +struct nsPoint; +struct nsRect; +struct nsReflowMetrics; + +// IID for the nsIFrame interface {12B193D0-9F70-11d1-8500-00A02468FAB6} +#define NS_IFRAME_IID \ +{ 0x12b193d0, 0x9f70, 0x11d1, \ + {0x85, 0x0, 0x0, 0xa0, 0x24, 0x68, 0xfa, 0xb6}} + +/** + * Reflow metrics used to return the frame's desired size and alignment + * information. + * + * @see #ResizeReflow() + * @see #IncrementalReflow() + * @see #GetReflowMetrics() + */ +struct nsReflowMetrics { + nscoord width, height; + nscoord ascent, descent; +}; + +/** + * Constant used to indicate an unconstrained size. + * + * @see #ResizeReflow() + * @see #IncrementalReflow() + */ +#define NS_UNCONSTRAINEDSIZE NS_MAXSIZE + +/** + * A frame in the layout model. This interface is supported by all frame + * objects. + * + * Frames are NOT reference counted. Use the DeleteFrame() member function + * instead + */ +class nsIFrame : private nsISupports +{ +public: + /** + * QueryInterface() defined in nsISupports. This is the only member + * function of nsISupports that is public. + */ + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr) = 0; + + /** + * Deletes this frame and each of its child frames (recursively calls + * DeleteFrame() for each child) + */ + virtual void DeleteFrame() = 0; + + /** + * Get the content object associated with this frame. Adds a reference to + * the content object so the caller must do a release. + * + * @see nsISupports#Release() + */ + virtual nsIContent* GetContent() const = 0; + + /** + * Get/Set the frame's index in parent. + */ + virtual PRInt32 GetIndexInParent() const = 0; + virtual void SetIndexInParent(PRInt32 aIndexInParent) = 0; + + /** + * Get the style context associated with this frame. Note that GetStyleContext() + * adds a reference to the style context so the caller must do a release. + * + * @see #nsISupports#Release() + */ + virtual nsIStyleContext* GetStyleContext(nsIPresContext* aContext) = 0; + virtual void SetStyleContext(nsIStyleContext* aContext) = 0; + + + /** + * + * Get the style data associated with this frame + * + * + */ + virtual nsStyleStruct* GetStyleData(const nsIID& aSID) = 0; + + /** + * Accessor functions for geometric and content parent. + */ + virtual nsIFrame* GetContentParent() const = 0; + virtual void SetContentParent(const nsIFrame* aParent) = 0; + virtual nsIFrame* GetGeometricParent() const = 0; + virtual void SetGeometricParent(const nsIFrame* aParent) = 0; + + /** + * Bounding rect of the frame. The values are in twips, and the origin is + * relative to the upper-left of the geometric parent. The size includes the + * content area, borders, and padding. + */ + virtual nsRect GetRect() const = 0; + virtual void GetRect(nsRect& aRect) const = 0; + virtual void GetOrigin(nsPoint& aPoint) const = 0; + virtual nscoord GetWidth() const = 0; + virtual nscoord GetHeight() const = 0; + virtual void SetRect(const nsRect& aRect) = 0; + virtual void MoveTo(nscoord aX, nscoord aY) = 0; + virtual void SizeTo(nscoord aWidth, nscoord aHeight) = 0; + + /** + * Painting + */ + virtual void Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) = 0; + + /** + * Handle an event. + */ + virtual nsEventStatus HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent) = 0; + + /** + * Get the cursor for a given point in the frame tree. The + * call returns the desired cursor (or NS_STYLE_CURSOR_INHERIT if + * no cursor is wanted). In addition, if a cursor is desired + * then *aFrame is set to the frame that wants the cursor. + */ + virtual PRInt32 GetCursorAt(nsIPresContext& aPresContext, + const nsPoint& aPoint, + nsIFrame** aFrame) = 0; + + /** + * Child frame enumeration + */ + virtual PRInt32 ChildCount() const = 0; + virtual nsIFrame* ChildAt(PRInt32 aIndex) const = 0; + virtual PRInt32 IndexOf(const nsIFrame* aChild) const = 0; + virtual nsIFrame* FirstChild() const = 0; + virtual nsIFrame* NextChild(const nsIFrame* aChild) const = 0; + virtual nsIFrame* PrevChild(const nsIFrame* aChild) const = 0; + virtual nsIFrame* LastChild() const = 0; + + /** + * Reflow status returned by the reflow methods + * + * @see #ResizeReflow() + * @see #IncrementalReflow() + */ + enum ReflowStatus {frComplete, frNotComplete}; + + /** + * Resize reflow. The frame is given a maximum size and asked for its desired + * size. This is the frame's opportunity to reflow its children. + * + * @param aDesiredSize out parameter where you should return the + * desired size and ascent/descent info. You should include any + * space you want for border/padding in the desired size you return. + * @param aMaxSize the available space in which to lay out. Each dimension + * can either be constrained or unconstrained (a value of + * NS_UNCONSTRAINEDSIZE). If constrained you should choose a value that's + * less than or equal to the constrained size. If unconstrained you can + * choose as large a value as you like. + * + * It's okay to return a desired size that exceeds the max size if that's + * the smallest you can be, i.e. it's your minimum size. + * + * @param aMaxElementSize an optional parameter for returning your maximum + * element size. If may be null in which case you don't have to compute + * a maximum element size. The maximum element size must be less than or + * equal to your desired size. + */ + virtual ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) = 0; + + /** + * Post-processing reflow method invoked when justification is enabled. + * This is always called after ResizeReflow/IncrementalReflow. + * + * @param aAvailableSpace The amount of available space that the frame + * should distribute internally. + */ + virtual void JustifyReflow(nsIPresContext* aPresContext, + nscoord aAvailableSpace) = 0; + + /** + * Incremental reflow. The reflow command contains information about the + * type of change. The frame is given a maximum size and asked for its + * desired size. + * + * @param aDesiredSize out parameter where you should return + * the desired size and ascent/descent info. You should + * include any space you want for border/padding in the + * desired size you return. + * + * @param aMaxSize the available space in which to lay out. Each + * dimension can either be constrained or unconstrained (a + * value of NS_UNCONSTRAINEDSIZE). If constrained you + * should choose a value that's less than or equal to the + * constrained size. If unconstrained you can choose as + * large a value as you like. It's okay to return a + * desired size that exceeds the max size if that's the + * smallest you can be, i.e. it's your minimum size. + * + * @see nsReflowCommand#GetTarget() + * @see nsReflowCommand#GetType() + */ + virtual ReflowStatus IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand) = 0; + + /** + * This call is invoked when content is appended to the content + * tree. The container frame that maps that content is asked to deal + * with the appended content by creating new frames and updating the + * index-in-parent values for it's affected children. In addition, + * the call must generate reflow commands that will incrementally + * reflow and repair the damaged portion of the frame tree. + */ + virtual void ContentAppended(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer) = 0; + + /** + * This call is invoked when content is inserted in the content + * tree. The container frame that maps that content is asked to deal + * with the inserted content by creating new frames and updating the + * index-in-parent values for it's affected children. In addition, + * the call must generate reflow commands that will incrementally + * reflow and repair the damaged portion of the frame tree. + * + * @param aIndexInParent the index in the content container where + * the new content was inserted. + */ + virtual void ContentInserted(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInParent) = 0; + + /** + * This call is invoked when content is replaced in the content + * tree. The container frame that maps that content is asked to deal + * with the replaced content by deleting old frames and then + * creating new frames and updating the index-in-parent values for + * it's affected children. In addition, the call must generate + * reflow commands that will incrementally reflow and repair the + * damaged portion of the frame tree. + * + * @param aIndexInParent the index in the content container where + * the new content was inserted. */ + virtual void ContentReplaced(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInParent) = 0; + + /** + * This call is invoked when content is deleted from the content + * tree. The container frame that maps that content is asked to deal + * with the deleted content by deleting frames and updating the + * index-in-parent values for it's affected children. In addition, + * the call must generate reflow commands that will incrementally + * reflow and repair the damaged portion of the frame tree. + * + * @param aIndexInParent the index in the content container where + * the new content was deleted. + */ + virtual void ContentDeleted(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInParent) = 0; + + /** + * Return the reflow metrics for this frame. If the frame is a + * container then the values for ascent and descent are computed + * across the the various children in the appropriate manner + * (e.g. for a line frame the ascent value would be the maximum + * ascent of the line's children). Note that the metrics returned + * apply to the frame as it exists at the time of the call. + */ + virtual void GetReflowMetrics(nsIPresContext* aPresContext, + nsReflowMetrics& aMetrics) = 0; + + /** + * Flow member functions. CreateContinuingFrame() is responsible for appending + * the continuing frame to the flow. + */ + virtual PRBool IsSplittable() const = 0; + virtual nsIFrame* CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent) = 0; + virtual nsIFrame* GetPrevInFlow() const = 0; + virtual void SetPrevInFlow(nsIFrame*) = 0; + virtual nsIFrame* GetNextInFlow() const = 0; + virtual void SetNextInFlow(nsIFrame*) = 0; + + virtual void AppendToFlow(nsIFrame* aAfterFrame) = 0; + virtual void PrependToFlow(nsIFrame* aBeforeFrame) = 0; + virtual void RemoveFromFlow() = 0; + virtual void BreakFromPrevFlow() = 0; + virtual void BreakFromNextFlow() = 0; + + /** + * Accessor functions to get/set the associated view object + */ + virtual nsIView* GetView() const = 0; // may be null + virtual void SetView(nsIView* aView) = 0; + + /** + * Find the first geometric parent that has a view + */ + virtual nsIFrame* GetParentWithView() const = 0; + + /** + * Returns the offset from this frame to the closest geometric parent that + * has a view. Also returns the containing view or null in case of error + */ + virtual nsIView* GetOffsetFromView(nsPoint& aOffset) const = 0; + + /** + * Returns the window that contains this frame. If this frame has a + * view and the view has a window, then this frames window is + * returned, otherwise this frame's geometric parent is checked + * recursively upwards. + */ + virtual nsIWidget* GetWindow() const = 0; + + /** + * Sibling pointer used to link together frames + */ + virtual nsIFrame* GetNextSibling() const = 0; + virtual void SetNextSibling(nsIFrame* aNextSibling) = 0; + + // Debugging + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const= 0; + virtual void ListTag(FILE* out = stdout) const = 0; + virtual void VerifyTree() const = 0; + + // Show frame borders when rendering + static NS_LAYOUT void ShowFrameBorders(PRBool aEnable); + static NS_LAYOUT PRBool GetShowFrameBorders(); +}; + +#endif /* nsIFrame_h___ */ diff --git a/mozilla/layout/base/public/nsIPresContext.h b/mozilla/layout/base/public/nsIPresContext.h new file mode 100644 index 00000000000..916ea9538b5 --- /dev/null +++ b/mozilla/layout/base/public/nsIPresContext.h @@ -0,0 +1,150 @@ +/* -*- 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. + */ +#ifndef nsIPresContext_h___ +#define nsIPresContext_h___ + +#include "nslayout.h" +#include "nsISupports.h" +#include "nsRect.h" + +class nsIImage; +class nsILinkHandler; +class nsIPresShell; +class nsIRenderingContext; +class nsIFrame; +class nsIStyleContext; +class nsIFontMetrics; +class nsIContent; +class nsViewManager; +class nsIView; +class nsIFontCache; +class nsIDeviceContext; +class nsString; +struct nsFont; + +#define NS_IPRESCONTEXT_IID \ +{ 0x0a5d12e0, 0x944e, 0x11d1, \ + {0x93, 0x23, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + + +// An interface for presentation contexts. Presentation contexts are +// objects that provide an outer context for a presentation shell. +class nsIPresContext : public nsISupports { +public: + /** + * Set the presentation shell that this context is bound to. + * A presentation context may only be bound to a single shell. + */ + virtual void SetShell(nsIPresShell* aShell) = 0; + + /** + * Get the PresentationShell that this context is bound to. + */ + virtual nsIPresShell* GetShell() = 0; + + /** + * Resolve style for the given piece of content that will be a child + * of the aParentFrame frame. + */ + virtual nsIStyleContext* ResolveStyleContextFor(nsIContent* aContent, + nsIFrame* aParentFrame) = 0; + + /** + * Get the font metrics for a given font. + */ + virtual nsIFontMetrics* GetMetricsFor(const nsFont& aFont) = 0; + + /** + * Get the default font + */ + virtual const nsFont& GetDefaultFont(void) = 0; + + /** + * Load an image for the given url name for the given frame. When + * the image is ready for rendering the frame will be repainted. + * + * If the image is ready then this method will return the image, + * otherwise it will return nsnull and guarantee that the frame + * is repained when the image is ready. + * + * XXX this api needs work; the frame can't find out the size when + * it arrives nor can it find out any error information, etc. + */ + virtual nsIImage* LoadImage(const nsString& aURL, nsIFrame* aForFrame) = 0; + + /** + * Stop any image loading being done on behalf of the argument frame. + */ + virtual void StopLoadImage(nsIFrame* aForFrame) = 0; + + NS_IMETHOD SetContainer(nsISupports* aContainer) = 0; + + NS_IMETHOD GetContainer(nsISupports** aResult) = 0; + + NS_IMETHOD SetLinkHandler(nsILinkHandler* aHandler) = 0; + + NS_IMETHOD GetLinkHandler(nsILinkHandler** aResult) = 0; + + /** + * Get the currently visible portion of the RootContent ILayoutable. + * The units returned are in pixels. An acceptable answer is "null" + * which means "I don't know". + *

Speculative

+ */ + virtual nsRect GetVisibleArea() = 0; + + /** + * Set the currently visible area. This is the size and location + * of the visible portion of the RootContent ILayoutable. + */ + virtual void SetVisibleArea(const nsRect& r) = 0; + + /** + * Return true if this presentation context is a paginated + * context. + */ + virtual PRBool IsPaginated() = 0; + + /** + * Return the page width if this is a paginated context. + */ + virtual nscoord GetPageWidth() = 0; + + /** + * Return the page height if this is a paginated context + */ + virtual nscoord GetPageHeight() = 0; + + virtual float GetPixelsToTwips() const = 0; + virtual float GetTwipsToPixels() const = 0; + + //be sure to Relase() after you are done with the Get() + virtual nsIDeviceContext * GetDeviceContext() const = 0; +}; + +// Factory method to create a "galley" presentation context (galley is +// a kind of view that has no limit to the size of a page) +extern NS_LAYOUT nsresult + NS_NewGalleyContext(nsIPresContext** aInstancePtrResult); + +// Factory method to create a "paginated" presentation context for +// the screen. +extern NS_LAYOUT nsresult + NS_NewPrintPreviewContext(nsIPresContext** aInstancePtrResult); + +#endif /* nsIPresContext_h___ */ diff --git a/mozilla/layout/base/public/nsIPresShell.h b/mozilla/layout/base/public/nsIPresShell.h new file mode 100644 index 00000000000..7a88f3d12c6 --- /dev/null +++ b/mozilla/layout/base/public/nsIPresShell.h @@ -0,0 +1,103 @@ +/* -*- 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. + */ +#ifndef nsIPresShell_h___ +#define nsIPresShell_h___ + +#include "nslayout.h" +#include "nsIDocumentObserver.h" +#include "nsCoord.h" +class nsIContent; +class nsIDocument; +class nsIFrame; +class nsIPresContext; +class nsIStyleSet; +class nsIViewManager; +class nsReflowCommand; + +#define NS_IPRESSHELL_IID \ +{ 0x76e79c60, 0x944e, 0x11d1, \ + {0x93, 0x23, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +/** + * Presentation shell interface. Presentation shells are the + * controlling point for managing the presentation of a document. The + * presentation shell holds a live reference to the document, the + * presentation context, the style manager, the style set and the root + * frame.

+ * + * When this object is Release'd, it will release the document, the + * presentation context, the style manager, the style set and the root + * frame. + */ +class nsIPresShell : public nsIDocumentObserver { +public: + virtual nsresult Init(nsIDocument* aDocument, + nsIPresContext* aPresContext, + nsIViewManager* aViewManager, + nsIStyleSet* aStyleSet) = 0; + + virtual nsIDocument* GetDocument() = 0; + + virtual nsIPresContext* GetPresContext() = 0; + + virtual nsIViewManager * GetViewManager() = 0; + + virtual nsIStyleSet* GetStyleSet() = 0; + + // Make shell be a document observer + virtual void BeginObservingDocument() = 0; + + // Make shell stop being a document observer + virtual void EndObservingDocument() = 0; + + /** + * Reflow the frame model into a new width and height. The + * coordinates for aWidth and aHeight must be in standard nscoord's. + */ + virtual void ResizeReflow(nscoord aWidth, nscoord aHeight) = 0; + + virtual nsIFrame* GetRootFrame() = 0; + + virtual nsIFrame* FindFrameWithContent(nsIContent* aContent) = 0; + + virtual void AppendReflowCommand(nsReflowCommand* aReflowCommand) = 0; + + virtual void ProcessReflowCommands() = 0; + + /** + * Place some cached data into the shell's cache. The key for + * the cache is the given frame. + */ + virtual void PutCachedData(nsIFrame* aKeyFrame, void* aData) = 0; + + virtual void* GetCachedData(nsIFrame* aKeyFrame) = 0; + + virtual void* RemoveCachedData(nsIFrame* aKeyFrame) = 0; + + // XXX events + // XXX selection +}; + +/** + * Create a new empty presentation shell. Upon success, call Init + * before attempting to use the shell. + */ +extern NS_LAYOUT nsresult + NS_NewPresShell(nsIPresShell** aInstancePtrResult); + +#endif /* nsIPresShell_h___ */ diff --git a/mozilla/layout/base/public/nsIRunaround.h b/mozilla/layout/base/public/nsIRunaround.h new file mode 100644 index 00000000000..f7fe3a7e549 --- /dev/null +++ b/mozilla/layout/base/public/nsIRunaround.h @@ -0,0 +1,110 @@ +/* -*- 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. + */ +#ifndef nsIRunaround_h___ +#define nsIRunaround_h___ + +#include +#include "nsIFrame.h" + +// IID for the nsIRunaround interface {3C6ABCF0-C028-11d1-853F-00A02468FAB6} +#define NS_IRUNAROUND_IID \ +{ 0x3c6abcf0, 0xc028, 0x11d1, \ + {0x85, 0x3f, 0x0, 0xa0, 0x24, 0x68, 0xfa, 0xb6}} + +/** + * An interface for handling reflow that allows direct access to the space + * manager. Note that this interface is not an nsISupports interface, and + * therefore you cannot QueryInterface() back + */ +class nsIRunaround +{ +public: + /** + * Resize reflow. The frame is given a maximum size and asked for its + * desired rect. The space manager should be used to do runaround of anchored + * items. + * + * @param aSpaceManager the space manager to use. The caller has translated + * the coordinate system so the frame has its own local coordinate + * space with an origin of (0, 0). If you translate the coordinate + * space you must restore it before returning. + * @param aMaxSize the available space in which to lay out. Each dimension + * can either be constrained or unconstrained (a value of + * NS_UNCONSTRAINEDSIZE). If constrained you should choose a value + * that's less than or equal to the constrained size. If unconstrained + * you can choose as large a value as you like. + * + * It's okay to return a desired size that exceeds the max size if + * that's the smallest you can be, i.e. it's your minimum size. + * + * @param aDesiredRect out parameter where you should return the desired + * origin and size. You should include any space you want for border + * and padding in the desired size. + * + * The origin of the desired rect is relative to the upper-left of the + * local coordinate space. + * + * @param aMaxElementSize an optional parameter for returning your maximum + * element size. If may be null in which case you don't have to compute + * a maximum element size + * + * @see nsISpaceManager#Translate() + */ + virtual nsIFrame::ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsSize* aMaxElementSize) = 0; + + /** + * Incremental reflow. The reflow command contains information about the + * type of change. The frame is given a maximum size and asked for its + * desired rect. The space manager should be used to do runaround of anchored + * items. + * + * @param aSpaceManager the space manager to use. The caller has translated + * the coordinate system so the frame has its own local coordinate + * space with an origin of (0, 0). If you translate the coordinate + * space you must restore it before returning. + * @param aMaxSize the available space in which to lay out. Each dimension + * can either be constrained or unconstrained (a value of + * NS_UNCONSTRAINEDSIZE). If constrained you should choose a value + * that's less than or equal to the constrained size. If unconstrained + * you can choose as large a value as you like. + * + * It's okay to return a desired size that exceeds the max size if + * that's the smallest you can be, i.e. it's your minimum size. + * + * @param aDesiredRect out parameter where you should return the desired + * origin and size. You should include any space you want for border + * and padding in the desired size. + * + * The origin of the desired rect is relative to the upper-left of the + * local coordinate space. + * + * @param aReflowCommand the reflow command contains information about the + * type of change. + */ + virtual nsIFrame::ReflowStatus IncrementalReflow(nsIPresContext* aPresContext, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsReflowCommand& aReflowCommand) = 0; +}; + +#endif /* nsIRunaround_h___ */ diff --git a/mozilla/layout/base/public/nsISpaceManager.h b/mozilla/layout/base/public/nsISpaceManager.h new file mode 100644 index 00000000000..85e0f759a18 --- /dev/null +++ b/mozilla/layout/base/public/nsISpaceManager.h @@ -0,0 +1,111 @@ +/* -*- 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. + */ +#ifndef nsISpaceManager_h___ +#define nsISpaceManager_h___ + +#include "nsISupports.h" +#include "nsCoord.h" + +class nsIFrame; +struct nsPoint; +struct nsRect; +struct nsSize; + +// IID for the nsISpaceManager interface {17C8FB50-BE96-11d1-80B5-00805F8A274D} +#define NS_ISPACEMANAGER_IID \ +{ 0x17c8fb50, 0xbe96, 0x11d1, \ + {0x80, 0xb5, 0x0, 0x80, 0x5f, 0x8a, 0x27, 0x4d}} + +/** + * Structure used for returning the available space in a band. + * @see #GetBandData() + */ +struct nsBandData { + PRInt32 count; // 'out' parameter. Actual number of rects in the band data + PRInt32 size; // 'in' parameter. The size of the array + nsRect* rects; // 'out' parameter. Array of length 'size' +}; + +/** + * Interface for dealing with bands of available space. + * + * @see nsIRunaround + */ +class nsISpaceManager : public nsISupports { +public: + /** + * Get the frame that's associated with the space manager. This frame created + * the space manager, and the world coordinate space is relative to this frame. + * + * You can use QueryInterface() on this frame to get additional interfaces such + * as nsIAnchoredItems + */ + virtual nsIFrame* GetFrame() const = 0; + + /** + * Translate the current origin by the specified (dx, dy). This creates a new + * local coordinate space relative to the current coordinate space. + */ + virtual void Translate(nscoord aDx, nscoord aDy) = 0; + + /** + * Returns the current translation from local coordinate space to world + * coordinate space. This represents the accumulated calls to Translate(). + */ + virtual void GetTranslation(nscoord& aX, nscoord& aY) const = 0; + + /** + * Returns the y-most of the bottommost band, or 0 if there are no bands. + */ + virtual nscoord YMost() const = 0; + + /** + * Returns a band starting at the specified y-offset. The band data indicates + * which parts of the band are available + * + * The band data that is returned is in the coordinate space of the local + * coordinate system. + * + * The local coordinate space origin together with the max size describe a + * rectangle that's used to clip the underlying band of available space. + * + * @param aYOffset the y-offset of where the band begins. The coordinate is + * relative to the upper-left corner of the local coordinate space + * @param aMaxSize the size to use to constrain the band data + * @param aAvailableSpace out parameter used to return the list of + * rects that make up the available space. + * @returns the number of rects in the band data. If the band data is not + * large enough returns the negative of the number of rects needed + */ + virtual PRInt32 GetBandData(nscoord aYOffset, + const nsSize& aMaxSize, + nsBandData& aAvailableSpace) const = 0; + + /** + * Add a rectangular region of unavailable space. The space is relative to + * the local coordinate system. + */ + virtual void AddRectRegion(const nsRect& aUnavailableSpace) = 0; + + /** + * Clears the list of regions representing the unavailable space. + */ + virtual void ClearRegions() = 0; +}; + +#endif /* nsISpaceManager_h___ */ diff --git a/mozilla/layout/base/public/nsIStyleContext.h b/mozilla/layout/base/public/nsIStyleContext.h new file mode 100644 index 00000000000..66ab46a4561 --- /dev/null +++ b/mozilla/layout/base/public/nsIStyleContext.h @@ -0,0 +1,160 @@ +/* -*- 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. + */ +#ifndef nsIStyleContext_h___ +#define nsIStyleContext_h___ + +#include "nslayout.h" +#include "nsISupports.h" +#include "nsColor.h" +#include "nsCoord.h" +#include "nsMargin.h" +#include "nsFont.h" +class nsIFrame; +class nsIPresContext; +class nsIContent; +class nsISupportsArray; + +// SID e31e1bc0-ca9b-11d1-8031-006008159b5a +#define NS_STYLEFONT_SID \ +{0xe31e1bc0, 0xca9b, 0x11d1, {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}} + +// SID 05953860-ca9c-11d1-8031-006008159b5a +#define NS_STYLECOLOR_SID \ +{0x05953860, 0xca9c, 0x11d1, {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}} + +// SID 4fb83b60-cf27-11d1-8031-006008159b5a +#define NS_STYLELIST_SID \ +{0x4fb83b60, 0xcf27, 0x11d1, {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}} + +// Indicies into border/padding/margin arrays +#define NS_SIDE_TOP 0 +#define NS_SIDE_RIGHT 1 +#define NS_SIDE_BOTTOM 2 +#define NS_SIDE_LEFT 3 + +// The lifetime of these objects is managed by the nsIStyleContext. + +struct nsStyleStruct { + virtual const nsID& GetID(void) = 0; +}; + +struct nsStyleFont : public nsStyleStruct { + nsFont mFont; + PRUint8 mThreeD; // XXX fold this into nsFont + +protected: + nsStyleFont(const nsFont& aFont); + ~nsStyleFont(void); +}; + +struct nsStyleColor : public nsStyleStruct { + nscolor mColor; + + PRUint8 mBackgroundAttachment; // See nsStyleConsts.h + PRUint8 mBackgroundFlags; // See nsStyleConsts.h + PRUint8 mBackgroundRepeat; // See nsStyleConsts.h + + nscolor mBackgroundColor; + nscoord mBackgroundXPosition; + nscoord mBackgroundYPosition; + nsString mBackgroundImage; // absolute url string +}; + +struct nsStyleList : public nsStyleStruct { + PRUint8 mListStyleType; // See nsStyleConsts.h + nsString mListStyleImage; // absolute url string + PRUint8 mListStylePosition; +}; + +//---------------------------------------------------------------------- +// XXX begin temporary doomed code + +// This data structure is doomed: it's a temporary hack for catch-all +// style that hasn't yet been factored properly into nsStyleX +// struct's. + +// SID 05fb99f0-ca9c-11d1-8031-006008159b5a +#define NS_STYLEMOLECULE_SID \ +{0x05fb99f0, 0xca9c, 0x11d1, {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}} + +struct nsStyleMolecule : public nsStyleStruct { + PRUint8 borderSizeFlags[4]; + nsMargin border; + PRUint8 borderStyle[4]; + nscolor borderColor[4]; + PRUint8 clear; + PRUint8 clipFlags; + PRUint8 cursor; + PRUint8 display; + PRUint8 direction; + PRUint8 floats; + nsMargin margin; + nsMargin padding; + nsMargin borderPadding; + PRUint32 textDecoration; + PRUint8 textAlign; + PRInt32 whiteSpace; + PRUint8 verticalAlign; + float verticalAlignPct; + PRInt32 fixedWidth; + PRInt32 proportionalWidth; + PRInt32 fixedHeight; + PRInt32 proportionalHeight; + PRUint8 positionFlags; + nscoord top, left; + +protected: + // The constructor is protected because you may not make these + // automatic variables. + nsStyleMolecule(); + ~nsStyleMolecule(); + +private: + // These are not allowed + nsStyleMolecule(const nsStyleMolecule& other); + nsStyleMolecule& operator=(const nsStyleMolecule& other); +}; + +// XXX end temporary doomed code +//---------------------------------------------------------------------- + +#define NS_ISTYLECONTEXT_IID \ + { 0x26a4d970, 0xa342, 0x11d1, \ + {0x89, 0x74, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } + +class nsIStyleContext : public nsISupports { +public: + virtual PRBool Equals(const nsIStyleContext* aOther) const = 0; + virtual PRUint32 HashValue(void) const = 0; + + virtual nsIStyleContext* GetParent(void) const = 0; + virtual nsISupportsArray* GetStyleRules(void) const = 0; + + // get a style data struct by ID, may return null + virtual nsStyleStruct* GetData(const nsIID& aSID) = 0; +}; + +// this is private to nsStyleSet, don't call it +extern NS_LAYOUT nsresult + NS_NewStyleContext(nsIStyleContext** aInstancePtrResult, + nsISupportsArray* aRules, + nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame); + +#endif /* nsIStyleContext_h___ */ diff --git a/mozilla/layout/base/public/nsIStyleRule.h b/mozilla/layout/base/public/nsIStyleRule.h new file mode 100644 index 00000000000..e79eff7dae8 --- /dev/null +++ b/mozilla/layout/base/public/nsIStyleRule.h @@ -0,0 +1,43 @@ +/* -*- 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. + */ +#ifndef nsIStyleRule_h___ +#define nsIStyleRule_h___ + +#include + +#include "nslayout.h" +#include "nsISupports.h" + +class nsIStyleContext; +class nsIPresContext; + +// IID for the nsIStyleRule interface {40ae5c90-ad6a-11d1-8031-006008159b5a} +#define NS_ISTYLE_RULE_IID \ +{0x40ae5c90, 0xad6a, 0x11d1, {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}} + +class nsIStyleRule : public nsISupports { +public: + virtual PRBool Equals(const nsIStyleRule* aRule) const = 0; + virtual PRUint32 HashValue(void) const = 0; + + virtual void MapStyleInto(nsIStyleContext* aContext, nsIPresContext* aPresContext) = 0; + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const = 0; +}; + +#endif /* nsIStyleRule_h___ */ diff --git a/mozilla/layout/base/public/nsIStyleSet.h b/mozilla/layout/base/public/nsIStyleSet.h new file mode 100644 index 00000000000..c084ed98826 --- /dev/null +++ b/mozilla/layout/base/public/nsIStyleSet.h @@ -0,0 +1,81 @@ +/* -*- 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. + */ +#ifndef nsStyleSet_h___ +#define nsStyleSet_h___ + +#include +#include "nsISupports.h" +#include "nslayout.h" + +class nsIAtom; +class nsIStyleMolecule; +class nsIStyleRule; +class nsIStyleSheet; +class nsIStyleContext; +class nsIPresContext; +class nsIContent; +class nsIFrame; + + +// IID for the nsIStyleSet interface {e59396b0-b244-11d1-8031-006008159b5a} +#define NS_ISTYLE_SET_IID \ +{0xe59396b0, 0xb244, 0x11d1, {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}} + +class nsIStyleSet : public nsISupports { +public: + virtual void AppendOverrideStyleSheet(nsIStyleSheet* aSheet) = 0; + virtual void InsertOverrideStyleSheetAfter(nsIStyleSheet* aSheet, + nsIStyleSheet* aAfterSheet) = 0; + virtual void InsertOverrideStyleSheetBefore(nsIStyleSheet* aSheet, + nsIStyleSheet* aBeforeSheet) = 0; + virtual void RemoveOverrideStyleSheet(nsIStyleSheet* aSheet) = 0; + virtual PRInt32 GetNumberOfOverrideStyleSheets() = 0; + virtual nsIStyleSheet* GetOverrideStyleSheetAt(PRInt32 aIndex) = 0; + + virtual void AppendDocStyleSheet(nsIStyleSheet* aSheet) = 0; + virtual void InsertDocStyleSheetAfter(nsIStyleSheet* aSheet, + nsIStyleSheet* aAfterSheet) = 0; + virtual void InsertDocStyleSheetBefore(nsIStyleSheet* aSheet, + nsIStyleSheet* aBeforeSheet) = 0; + virtual void RemoveDocStyleSheet(nsIStyleSheet* aSheet) = 0; + virtual PRInt32 GetNumberOfDocStyleSheets() = 0; + virtual nsIStyleSheet* GetDocStyleSheetAt(PRInt32 aIndex) = 0; + + virtual void AppendBackstopStyleSheet(nsIStyleSheet* aSheet) = 0; + virtual void InsertBackstopStyleSheetAfter(nsIStyleSheet* aSheet, + nsIStyleSheet* aAfterSheet) = 0; + virtual void InsertBackstopStyleSheetBefore(nsIStyleSheet* aSheet, + nsIStyleSheet* aBeforeSheet) = 0; + virtual void RemoveBackstopStyleSheet(nsIStyleSheet* aSheet) = 0; + virtual PRInt32 GetNumberOfBackstopStyleSheets() = 0; + virtual nsIStyleSheet* GetBackstopStyleSheetAt(PRInt32 aIndex) = 0; + + + virtual nsIStyleContext* ResolveStyleFor(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame) = 0; + + // xxx style rules enumeration + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) = 0; +}; + +extern NS_LAYOUT nsresult + NS_NewStyleSet(nsIStyleSet** aInstancePtrResult); + +#endif /* nsIStyleSet_h___ */ diff --git a/mozilla/layout/base/public/nsIStyleSheet.h b/mozilla/layout/base/public/nsIStyleSheet.h new file mode 100644 index 00000000000..bac20159aa0 --- /dev/null +++ b/mozilla/layout/base/public/nsIStyleSheet.h @@ -0,0 +1,50 @@ +/* -*- 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. + */ +#ifndef nsIStyleSheet_h___ +#define nsIStyleSheet_h___ + +#include +#include "nsISupports.h" +class nsIAtom; +class nsIURL; +class nsIStyleRule; +class nsISupportsArray; +class nsIPresContext; +class nsIContent; +class nsIFrame; + +// IID for the nsIStyleSheet interface {8c4a80a0-ad6a-11d1-8031-006008159b5a} +#define NS_ISTYLE_SHEET_IID \ +{0x8c4a80a0, 0xad6a, 0x11d1, {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}} + +class nsIStyleSheet : public nsISupports { +public: + virtual nsIURL* GetURL(void) = 0; + + // populate void array with nsIStyleRule* + virtual PRInt32 RulesMatching(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsISupportsArray* aResults) = 0; + + // XXX style rule enumerations + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const = 0; +}; + +#endif /* nsIStyleSheet_h___ */ diff --git a/mozilla/layout/base/public/nsITextContent.h b/mozilla/layout/base/public/nsITextContent.h new file mode 100644 index 00000000000..fca6973fa58 --- /dev/null +++ b/mozilla/layout/base/public/nsITextContent.h @@ -0,0 +1,48 @@ +/* -*- 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. + */ +#ifndef nsITextContent_h___ +#define nsITextContent_h___ + +#include "nslayout.h" +class nsString; + +// IID for the nsITextContent interface +#define NS_ITEXTCONTENT_IID \ +{ 0xdd0755d0, 0x944d, 0x11d1, \ + {0x93, 0x23, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +// Abstract interface for textual content. Note that this interface +// does not implement nsISupports (which means it's not transitive or +// reflexive). This is done for efficiency reasons. +class nsITextContent { +public: + /* + * Get the total length of the text content. + */ + virtual PRInt32 GetLength() = 0; + + /* + * Copy a subrange of the text content into aBuf starting at aOffset + * for aCount characters. aBuf's length will be reset before the + * copy occurs and it's length upon return will reflect the amount + * of data copied. + */ + virtual void GetText(nsString& aBuf, PRInt32 aOffset, PRInt32 aCount) = 0; +}; + +#endif /* nsITextContent_h___ */ diff --git a/mozilla/layout/base/public/nsPresContext.h b/mozilla/layout/base/public/nsPresContext.h new file mode 100644 index 00000000000..916ea9538b5 --- /dev/null +++ b/mozilla/layout/base/public/nsPresContext.h @@ -0,0 +1,150 @@ +/* -*- 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. + */ +#ifndef nsIPresContext_h___ +#define nsIPresContext_h___ + +#include "nslayout.h" +#include "nsISupports.h" +#include "nsRect.h" + +class nsIImage; +class nsILinkHandler; +class nsIPresShell; +class nsIRenderingContext; +class nsIFrame; +class nsIStyleContext; +class nsIFontMetrics; +class nsIContent; +class nsViewManager; +class nsIView; +class nsIFontCache; +class nsIDeviceContext; +class nsString; +struct nsFont; + +#define NS_IPRESCONTEXT_IID \ +{ 0x0a5d12e0, 0x944e, 0x11d1, \ + {0x93, 0x23, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + + +// An interface for presentation contexts. Presentation contexts are +// objects that provide an outer context for a presentation shell. +class nsIPresContext : public nsISupports { +public: + /** + * Set the presentation shell that this context is bound to. + * A presentation context may only be bound to a single shell. + */ + virtual void SetShell(nsIPresShell* aShell) = 0; + + /** + * Get the PresentationShell that this context is bound to. + */ + virtual nsIPresShell* GetShell() = 0; + + /** + * Resolve style for the given piece of content that will be a child + * of the aParentFrame frame. + */ + virtual nsIStyleContext* ResolveStyleContextFor(nsIContent* aContent, + nsIFrame* aParentFrame) = 0; + + /** + * Get the font metrics for a given font. + */ + virtual nsIFontMetrics* GetMetricsFor(const nsFont& aFont) = 0; + + /** + * Get the default font + */ + virtual const nsFont& GetDefaultFont(void) = 0; + + /** + * Load an image for the given url name for the given frame. When + * the image is ready for rendering the frame will be repainted. + * + * If the image is ready then this method will return the image, + * otherwise it will return nsnull and guarantee that the frame + * is repained when the image is ready. + * + * XXX this api needs work; the frame can't find out the size when + * it arrives nor can it find out any error information, etc. + */ + virtual nsIImage* LoadImage(const nsString& aURL, nsIFrame* aForFrame) = 0; + + /** + * Stop any image loading being done on behalf of the argument frame. + */ + virtual void StopLoadImage(nsIFrame* aForFrame) = 0; + + NS_IMETHOD SetContainer(nsISupports* aContainer) = 0; + + NS_IMETHOD GetContainer(nsISupports** aResult) = 0; + + NS_IMETHOD SetLinkHandler(nsILinkHandler* aHandler) = 0; + + NS_IMETHOD GetLinkHandler(nsILinkHandler** aResult) = 0; + + /** + * Get the currently visible portion of the RootContent ILayoutable. + * The units returned are in pixels. An acceptable answer is "null" + * which means "I don't know". + *

Speculative

+ */ + virtual nsRect GetVisibleArea() = 0; + + /** + * Set the currently visible area. This is the size and location + * of the visible portion of the RootContent ILayoutable. + */ + virtual void SetVisibleArea(const nsRect& r) = 0; + + /** + * Return true if this presentation context is a paginated + * context. + */ + virtual PRBool IsPaginated() = 0; + + /** + * Return the page width if this is a paginated context. + */ + virtual nscoord GetPageWidth() = 0; + + /** + * Return the page height if this is a paginated context + */ + virtual nscoord GetPageHeight() = 0; + + virtual float GetPixelsToTwips() const = 0; + virtual float GetTwipsToPixels() const = 0; + + //be sure to Relase() after you are done with the Get() + virtual nsIDeviceContext * GetDeviceContext() const = 0; +}; + +// Factory method to create a "galley" presentation context (galley is +// a kind of view that has no limit to the size of a page) +extern NS_LAYOUT nsresult + NS_NewGalleyContext(nsIPresContext** aInstancePtrResult); + +// Factory method to create a "paginated" presentation context for +// the screen. +extern NS_LAYOUT nsresult + NS_NewPrintPreviewContext(nsIPresContext** aInstancePtrResult); + +#endif /* nsIPresContext_h___ */ diff --git a/mozilla/layout/base/public/nslayout.h b/mozilla/layout/base/public/nslayout.h new file mode 100644 index 00000000000..585c564e22b --- /dev/null +++ b/mozilla/layout/base/public/nslayout.h @@ -0,0 +1,32 @@ +/* -*- 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. + */ +#ifndef nslayout_h___ +#define nslayout_h___ + +#include "nscore.h" + +// Note: For now, NS_LAYOUT and NS_HTML are joined at the hip +#if defined(_IMPL_NS_LAYOUT) || defined(_IMPL_NS_HTML) +#define NS_LAYOUT NS_EXPORT +#define NS_HTML NS_EXPORT +#else +#define NS_LAYOUT NS_IMPORT +#define NS_HTML NS_IMPORT +#endif + +#endif /* nslayout_h___ */ diff --git a/mozilla/layout/base/src/Makefile b/mozilla/layout/base/src/Makefile new file mode 100644 index 00000000000..6943c78eb87 --- /dev/null +++ b/mozilla/layout/base/src/Makefile @@ -0,0 +1,73 @@ +#!gmake +# +# 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. + +DEPTH=../../.. + +LIBRARY_NAME = raptorlayout_s + +DEFINES = -D_IMPL_NS_LAYOUT + +CPPSRCS = \ + nsContainerFrame.cpp \ + nsDocument.cpp \ + nsFrame.cpp \ + nsGalleyContext.cpp \ + nsPresContext.cpp \ + nsPresShell.cpp \ + nsPrintPreviewContext.cpp \ + nsReflowCommand.cpp \ + nsSpaceManager.cpp \ + nsSplittableFrame.cpp \ + nsStyleContext.cpp \ + nsStyleSet.cpp \ + $(NULL) + +EXPORTS = \ + nslayout.h \ + nsIContent.h \ + nsIContentDelegate.h \ + nsIDocument.h \ + nsIDocumentContainer.h \ + nsIDocumentObserver.h \ + nsIFrame.h \ + nsIPresContext.h \ + nsIPresShell.h \ + nsIRunaround.h \ + nsISpaceManager.h \ + nsIStyleContext.h \ + nsIStyleRule.h \ + nsIStyleSet.h \ + nsIStyleSheet.h \ + nsITextContent.h \ + nsDocument.h \ + nsStyleConsts.h \ + nsFrame.h \ + nsSplittableFrame.h \ + nsContainerFrame.h \ + nsReflowCommand.h \ + nsSpaceManager.h \ + $(NULL) + +MODULE = raptor + +REQUIRES = xpcom raptor dom + +include $(DEPTH)/config/config.mk + +TARGETS = $(LIBRARY) + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/layout/base/src/makefile.win b/mozilla/layout/base/src/makefile.win new file mode 100644 index 00000000000..d430e4a12e3 --- /dev/null +++ b/mozilla/layout/base/src/makefile.win @@ -0,0 +1,51 @@ +#!nmake +# +# 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. + +DEPTH=..\..\.. +IGNORE_MANIFEST=1 + +LIBRARY_NAME=raptorlayout_s +DEFINES=-D_IMPL_NS_LAYOUT +CPPSRCS=nsContainerFrame.cpp nsDocument.cpp nsFrame.cpp \ + nsGalleyContext.cpp nsPresContext.cpp nsPresShell.cpp \ + nsPrintPreviewContext.cpp nsReflowCommand.cpp nsSpaceManager.cpp \ + nsSplittableFrame.cpp nsStyleContext.cpp nsStyleSet.cpp +MODULE=raptor +REQUIRES=xpcom raptor dom +CPP_OBJS=.\$(OBJDIR)\nsContainerFrame.obj .\$(OBJDIR)\nsDocument.obj \ + .\$(OBJDIR)\nsFrame.obj .\$(OBJDIR)\nsGalleyContext.obj \ + .\$(OBJDIR)\nsPresContext.obj .\$(OBJDIR)\nsPresShell.obj \ + .\$(OBJDIR)\nsPrintPreviewContext.obj \ + .\$(OBJDIR)\nsReflowCommand.obj .\$(OBJDIR)\nsSpaceManager.obj \ + .\$(OBJDIR)\nsSplittableFrame.obj .\$(OBJDIR)\nsStyleContext.obj \ + .\$(OBJDIR)\nsStyleSet.obj + +LINCS=-I$(XPDIST)\public\xpcom -I$(XPDIST)\public\raptor \ + -I$(XPDIST)\public\dom -I$(XPDIST)\public\js + +LCFLAGS = \ + $(LCFLAGS) \ + $(DEFINES) \ + $(NULL) + +include <$(DEPTH)\config\rules.mak> + +libs:: $(LIBRARY) + $(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib + +clobber:: + rm -f $(DIST)\lib\$(LIBRARY_NAME).lib diff --git a/mozilla/layout/base/src/nsContainerFrame.cpp b/mozilla/layout/base/src/nsContainerFrame.cpp new file mode 100644 index 00000000000..d8102be0a20 --- /dev/null +++ b/mozilla/layout/base/src/nsContainerFrame.cpp @@ -0,0 +1,1243 @@ +/* -*- 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 "nsContainerFrame.h" +#include "nsIContent.h" +#include "nsIPresContext.h" +#include "nsIRenderingContext.h" +#include "nsIRunaround.h" +#include "nsISpaceManager.h" +#include "nsIStyleContext.h" +#include "nsIContentDelegate.h" +#include "nsRect.h" +#include "nsPoint.h" +#include "nsGUIEvent.h" +#include "nsStyleConsts.h" + +#ifdef NS_DEBUG +#undef NOISY +#else +#undef NOISY +#endif + +static NS_DEFINE_IID(kIRunaroundIID, NS_IRUNAROUND_IID); + +nsContainerFrame::nsContainerFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) + : nsSplittableFrame(aContent, aIndexInParent, aParent), + mLastContentIsComplete(PR_TRUE) +{ +} + +nsContainerFrame::~nsContainerFrame() +{ + // 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 = mFirstChild; child; ) { + nsIFrame* nextChild = child->GetNextSibling(); + child->DeleteFrame(); + child = nextChild; + } +} + +void nsContainerFrame::PrepareContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent, + nsContainerFrame* aContFrame) +{ + // Append the continuing frame to the flow + aContFrame->AppendToFlow(this); + + // Initialize it's content offsets. Note that we assume for now that + // the continuingFrame will map the remainder of the content and + // that therefore mLastContentIsComplete will be true. + PRInt32 nextOffset = NextChildOffset(); + aContFrame->mFirstContentOffset = nextOffset; + aContFrame->mLastContentOffset = nextOffset; + aContFrame->mLastContentIsComplete = PR_TRUE; + + // Resolve style for the continuing frame and set its style context. + // XXX presumptive + nsIStyleContext* styleContext = + aPresContext->ResolveStyleContextFor(mContent, aParent); + aContFrame->SetStyleContext(styleContext); + NS_RELEASE(styleContext); +} + +nsIFrame* +nsContainerFrame::CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent) +{ + nsIContentDelegate* contentDelegate = mContent->GetDelegate(aPresContext); + nsContainerFrame* continuingFrame = (nsContainerFrame*) + contentDelegate->CreateFrame(aPresContext, mContent, mIndexInParent, + aParent); + NS_RELEASE(contentDelegate); + + PrepareContinuingFrame(aPresContext, aParent, continuingFrame); + + return continuingFrame; +} + + +///////////////////////////////////////////////////////////////////////////// +// Child frame enumeration + +PRInt32 nsContainerFrame::ChildCount() const +{ + return mChildCount; +} + +nsIFrame* nsContainerFrame::ChildAt(PRInt32 aIndex) const +{ + // Check that the index is in range + if ((aIndex < 0) || (aIndex >= mChildCount)) { + return nsnull; + } + + nsIFrame* result = mFirstChild; + + while ((aIndex-- > 0) && (result != nsnull)) { + result = result->GetNextSibling(); + } + return result; +} + +PRInt32 nsContainerFrame::IndexOf(const nsIFrame* aChild) const +{ + PRInt32 result = -1; + + for (nsIFrame* f = mFirstChild; f != nsnull; f = f->GetNextSibling()) { + result++; + + if (f == aChild) + break; + } + + return result; +} + +nsIFrame* nsContainerFrame::FirstChild() const +{ + return mFirstChild; +} + +nsIFrame* nsContainerFrame::NextChild(const nsIFrame* aChild) const +{ + NS_PRECONDITION(aChild != nsnull, "null pointer"); + return aChild->GetNextSibling(); +} + +nsIFrame* nsContainerFrame::PrevChild(const nsIFrame* aChild) const +{ + NS_PRECONDITION(aChild != nsnull, "null pointer"); + + nsIFrame* result; + + if (mFirstChild == aChild) { + result = nsnull; + } else { + result = mFirstChild; + + while ((result != nsnull) && (result->GetNextSibling() != aChild)) + result = result->GetNextSibling(); + } + + return result; +} + +nsIFrame* nsContainerFrame::LastChild() const +{ + nsIFrame* result = mFirstChild; + + if (result) { + while (result->GetNextSibling() != nsnull) + result = result->GetNextSibling(); + } + + return result; +} + +///////////////////////////////////////////////////////////////////////////// +// Painting + +void nsContainerFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + PaintChildren(aPresContext, aRenderingContext, aDirtyRect); +} + +// aDirtyRect is in our coordinate system +// child rect's are also in our coordinate system +void nsContainerFrame::PaintChildren(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + nsIFrame* kid = mFirstChild; + while (nsnull != kid) { + nsRect kidRect; + kid->GetRect(kidRect); + nsRect damageArea; + PRBool overlap = damageArea.IntersectRect(aDirtyRect, kidRect); + if (overlap) { + // Translate damage area into kid's coordinate system + nsRect kidDamageArea(damageArea.x - kidRect.x, damageArea.y - kidRect.y, + damageArea.width, damageArea.height); + aRenderingContext.PushState(); + aRenderingContext.Translate(kidRect.x, kidRect.y); + kid->Paint(aPresContext, aRenderingContext, kidDamageArea); + if (nsIFrame::GetShowFrameBorders()) { + aRenderingContext.SetColor(NS_RGB(255,0,0)); + aRenderingContext.DrawRect(0, 0, kidRect.width, kidRect.height); + } + aRenderingContext.PopState(); + } + kid = kid->GetNextSibling(); + } +} + +///////////////////////////////////////////////////////////////////////////// +// Events + +nsEventStatus nsContainerFrame::HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent) +{ + nsEventStatus retval = nsEventStatus_eIgnore; + + nsIFrame* kid = mFirstChild; + while (nsnull != kid) { + nsRect kidRect; + kid->GetRect(kidRect); + if (kidRect.Contains(aEvent->point)) { + aEvent->point.MoveBy(-kidRect.x, -kidRect.y); + retval = kid->HandleEvent(aPresContext, aEvent); + aEvent->point.MoveBy(kidRect.x, kidRect.y); + return retval; + } + kid = kid->GetNextSibling(); + } + + return retval; +} + +PRInt32 nsContainerFrame::GetCursorAt(nsIPresContext& aPresContext, + const nsPoint& aPoint, + nsIFrame** aFrame) +{ + PRInt32 retval = NS_STYLE_CURSOR_INHERIT; + + nsIFrame* kid = mFirstChild; + nsPoint tmp; + while (nsnull != kid) { + nsRect kidRect; + kid->GetRect(kidRect); + if (kidRect.Contains(aPoint)) { + tmp.MoveTo(aPoint.x - kidRect.x, aPoint.y - kidRect.y); + retval = kid->GetCursorAt(aPresContext, tmp, aFrame); + return retval; + } + kid = kid->GetNextSibling(); + } + return retval; +} + +///////////////////////////////////////////////////////////////////////////// +// Managing content mapping + +// Get the offset for the next child content, i.e. the child after the +// last child that fit in us +PRInt32 nsContainerFrame::NextChildOffset() const +{ + PRInt32 result; + + if (mChildCount > 0) { + result = mLastContentOffset; + +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif + if (mLastContentIsComplete) { + result++; + } + } else { + result = mFirstContentOffset; + } + return result; +} + +/** + * Sets the first content offset based on the first child frame. + */ +void nsContainerFrame::SetFirstContentOffset(const nsIFrame* aFirstChild) +{ + NS_PRECONDITION(nsnull != aFirstChild, "bad argument"); + NS_PRECONDITION(aFirstChild->GetGeometricParent() == this, "bad geometric parent"); + + if (ChildIsPseudoFrame(aFirstChild)) { + nsContainerFrame* pseudoFrame = (nsContainerFrame*)aFirstChild; + mFirstContentOffset = pseudoFrame->mFirstContentOffset; + } else { + mFirstContentOffset = aFirstChild->GetIndexInParent(); + } +} + +/** + * Sets the last content offset based on the last child frame. If the last + * child is a pseudo frame then it sets mLastContentIsComplete to be the same + * as the last child's mLastContentIsComplete + */ +void nsContainerFrame::SetLastContentOffset(const nsIFrame* aLastChild) +{ + NS_PRECONDITION(nsnull != aLastChild, "bad argument"); + NS_PRECONDITION(aLastChild->GetGeometricParent() == this, "bad geometric parent"); + + if (ChildIsPseudoFrame(aLastChild)) { + nsContainerFrame* pseudoFrame = (nsContainerFrame*)aLastChild; + mLastContentOffset = pseudoFrame->mLastContentOffset; +#ifdef NS_DEBUG + pseudoFrame->VerifyLastIsComplete(); +#endif + mLastContentIsComplete = pseudoFrame->mLastContentIsComplete; + } else { + mLastContentOffset = aLastChild->GetIndexInParent(); + } +#ifdef NS_DEBUG + if (mLastContentOffset < mFirstContentOffset) { + nsIFrame* top = this; + while (top->GetGeometricParent() != nsnull) { + top = top->GetGeometricParent(); + } + top->List(); + } +#endif + NS_ASSERTION(mLastContentOffset >= mFirstContentOffset, "unexpected content mapping"); +} + +///////////////////////////////////////////////////////////////////////////// +// Pseudo frame related + +// Returns true if this frame is being used a pseudo frame +PRBool nsContainerFrame::IsPseudoFrame() const +{ + PRBool result = PR_FALSE; + + if (nsnull != mGeometricParent) { + nsIContent* parentContent = mGeometricParent->GetContent(); + + if (parentContent == mContent) { + result = PR_TRUE; + } + NS_RELEASE(parentContent); + } + + return result; +} + +// Returns true if aChild is being used as a pseudo frame +PRBool nsContainerFrame::ChildIsPseudoFrame(const nsIFrame* aChild) const +{ + NS_PRECONDITION(aChild->GetGeometricParent() == (nsIFrame*)this, "bad geometric parent"); + nsIContent* childContent = aChild->GetContent(); + PRBool result = PRBool(childContent == mContent); + + NS_RELEASE(childContent); + return result; +} + +///////////////////////////////////////////////////////////////////////////// +// Helper member functions + +/** + * Reflow a child frame and return the status of the reflow. If the + * child is complete and it has next-in-flows (it was a splittable child) + * then delete the next-in-flows. + */ +nsIFrame::ReflowStatus +nsContainerFrame::ReflowChild(nsIFrame* aKidFrame, + nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ + ReflowStatus status = aKidFrame->ResizeReflow(aPresContext, aDesiredSize, + aMaxSize, aMaxElementSize); + + if (frComplete == status) { + nsIFrame* kidNextInFlow = aKidFrame->GetNextInFlow(); + if (nsnull != kidNextInFlow) { + // Remove all of the childs next-in-flows. Make sure that we ask + // the right parent to do the removal (it's possible that the + // parent is not this because we are executing pullup code) + nsContainerFrame* parent = (nsContainerFrame*) + aKidFrame->GetGeometricParent(); + parent->DeleteChildsNextInFlow(aKidFrame); + } + } + return status; +} + +/** + * Reflow a child frame and return the status of the reflow. If the child + * is complete and it has next-in-flows, then delete the next-in-flows. + * + * Use this version if you have a space manager. Checks if the child frame + * supports interface nsIRunaround. If it does, interface nsIRunaround is + * used to reflow the child; otherwise interface nsIFrame is used. If the + * child is splittable then runaround is done using continuing frames. + */ +nsIFrame::ReflowStatus +nsContainerFrame::ReflowChild(nsIFrame* aKidFrame, + nsIPresContext* aPresContext, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsSize* aMaxElementSize) +{ + nsIRunaround* reflowRunaround; + ReflowStatus status; + + // Does the child frame support interface nsIRunaround? + if (NS_OK == aKidFrame->QueryInterface(kIRunaroundIID, (void**)&reflowRunaround)) { + // Yes, the child frame wants to interact directly with the space manager + status = reflowRunaround->ResizeReflow(aPresContext, aSpaceManager, aMaxSize, + aDesiredRect, aMaxElementSize); + } else { + // No, use interface nsIFrame instead. + nsReflowMetrics desiredSize; + + // Get the band for this y-offset and adjust the max size that we pass + // to exclude any left/right margins occupied by floaters. We should be + // checking whether the frame is splittable and taking that into account + // as well... + // + // XXX In order to do this efficiently we should move all this code to + // nsBlockFrame since it already has band data, and it's probably the only + // one who calls this routine anyway + nsBandData bandData; + nsRect rects[7]; + nsRect* availRect = rects; + + bandData.rects = rects; + bandData.size = 7; + aSpaceManager->GetBandData(0, aMaxSize, bandData); + + // If there's more than one rect than figure out which one determines the + // available reflow area + if (bandData.count == 2) { + // Either a left or right floater. Use whichever space is larger + if (rects[1].width > rects[0].width) { + availRect = &rects[1]; + } + } else if (bandData.count == 3) { + // Assume there are floaters on the left and right, and use the middle rect + availRect = &rects[1]; + } + + nsSize availSize(rects->width, aMaxSize.height); + status = aKidFrame->ResizeReflow(aPresContext, desiredSize, availSize, + aMaxElementSize); + + // Return the desired rect + aDesiredRect.x = rects->x; + aDesiredRect.y = 0; + aDesiredRect.width = desiredSize.width; + aDesiredRect.height = desiredSize.height; + } + + if (frComplete == status) { + nsIFrame* kidNextInFlow = aKidFrame->GetNextInFlow(); + if (nsnull != kidNextInFlow) { + // Remove all of the childs next-in-flows. Make sure that we ask + // the right parent to do the removal (it's possible that the + // parent is not this because we are executing pullup code) + nsContainerFrame* parent = (nsContainerFrame*) + aKidFrame->GetGeometricParent(); + parent->DeleteChildsNextInFlow(aKidFrame); + } + } + return status; +} + +/** + * Remove and delete aChild's next-in-flow(s). Updates the sibling and flow + * pointers + * + * Updates the child count and content offsets of all containers that are + * affected + * + * @param aChild child this child's next-in-flow + * @return PR_TRUE if successful and PR_FALSE otherwise + */ +PRBool nsContainerFrame::DeleteChildsNextInFlow(nsIFrame* aChild) +{ + NS_PRECONDITION(aChild->GetGeometricParent() == (nsIFrame*)this, "bad geometric parent"); + NS_PRECONDITION(nsnull != aChild->GetNextInFlow(), "null next-in-flow"); + + nsIFrame* nextInFlow = aChild->GetNextInFlow(); + nsContainerFrame* parent = (nsContainerFrame*)nextInFlow->GetGeometricParent(); + + // If the next-in-flow has a next-in-flow then delete it too (and + // delete it first). + if (nsnull != nextInFlow->GetNextInFlow()) { + parent->DeleteChildsNextInFlow(nextInFlow); + } + + NS_ASSERTION((0 == nextInFlow->ChildCount()) && + (nsnull == nextInFlow->FirstChild()), + "deleting !empty next-in-flow"); + + // Disconnect the next-in-flow from the flow list + nextInFlow->BreakFromPrevFlow(); + + // Take the next-in-flow out of the parent's child list + if (parent->mFirstChild == nextInFlow) { + parent->mFirstChild = nextInFlow->GetNextSibling(); + if (nsnull != parent->mFirstChild) { + parent->SetFirstContentOffset(parent->mFirstChild); + if (parent->IsPseudoFrame()) { + parent->PropagateContentOffsets(); + } + } + + // When a parent loses it's last child and that last child is a + // pseudo-frame then the parent's content offsets are now wrong. + // However, we know that the parent will eventually be reflowed + // in one of two ways: it will either get a chance to pullup + // children or it will be deleted because it's prev-in-flow + // (e.g. this) is complete. In either case, the content offsets + // will be repaired. + + } else { + // Because the next-in-flow is not the first child of the parent + // we know that it shares a parent with aChild. Therefore, we need + // to capture the next-in-flow's next sibling (in case the + // next-in-flow is the last next-in-flow for aChild AND the + // next-in-flow is not the last child in parent) + NS_ASSERTION(aChild->GetGeometricParent() == parent, "screwy flow"); + NS_ASSERTION(aChild->GetNextSibling() == nextInFlow, "unexpected sibling"); + + aChild->SetNextSibling(nextInFlow->GetNextSibling()); + } + + // Delete the next-in-flow frame and adjust it's parent's child count + nextInFlow->DeleteFrame(); + parent->mChildCount--; +#ifdef NS_DEBUG + if (0 != parent->mChildCount) { + parent->CheckContentOffsets(); + } +#endif + + NS_POSTCONDITION(nsnull == aChild->GetNextInFlow(), "non null next-in-flow"); + return PR_TRUE; +} + +void nsContainerFrame::PropagateContentOffsets() +{ + NS_PRECONDITION(IsPseudoFrame(), "not a pseudo frame"); + nsContainerFrame* parent = (nsContainerFrame*)mGeometricParent; + + if (nsnull != parent) { + // If we're the first child frame then update our parent's content offset + if (parent->mFirstChild == this) { + parent->mFirstContentOffset = mFirstContentOffset; + } + + // If we're the last child frame then update our parent's content offset + if (nsnull == mNextSibling) { + parent->mLastContentOffset = mLastContentOffset; + parent->mLastContentIsComplete = mLastContentIsComplete; + } + + // If the parent is being used as a pseudo frame then we need to propagate + // the content offsets upwards to its parent frame + if (parent->IsPseudoFrame()) { + parent->PropagateContentOffsets(); + } + } +} + +/** + * Push aFromChild and its next siblings to the next-in-flow. Change the + * geometric parent of each frame that's pushed. If there is no next-in-flow + * the frames are placed on the overflow list (and the geometric parent is + * left unchanged). + * + * Updates the next-in-flow's child count and content offsets. Does + * not update the pusher's child count or last content offset. + * + * @param aFromChild the first child frame to push. It is disconnected from + * aPrevSibling + * @param aPrevSibling aFromChild's previous sibling. Must not be null. It's + * an error to push a parent's first child frame + * @param aNextInFlowsLastChildIsComplete the next-in-flow's + * mLastContentIsComplete flag. This is used when refilling an + * empty next-in-flow that was drained by the caller. + * + */ +// Note: we cannot VerifyLastIsComplete here because the caller is +// responsible for setting it. +void nsContainerFrame::PushChildren(nsIFrame* aFromChild, + nsIFrame* aPrevSibling, + PRBool aNextInFlowsLastContentIsComplete) +{ + NS_PRECONDITION(nsnull != aFromChild, "null pointer"); + NS_PRECONDITION(nsnull != aPrevSibling, "pushing first child"); + NS_PRECONDITION(aPrevSibling->GetNextSibling() == aFromChild, "bad prev sibling"); + + // Disconnect aFromChild from its previous sibling + aPrevSibling->SetNextSibling(nsnull); + + // Do we have a next-in-flow? + nsContainerFrame* nextInFlow = (nsContainerFrame*)mNextInFlow; + if (nsnull != nextInFlow) { + PRInt32 numChildren = 0; + nsIFrame* lastChild = nsnull; + +#ifdef NOISY + ListTag(stdout); + printf(": pushing kids (childCount=%d)\n", mChildCount); + { + nsContainerFrame* flow = (nsContainerFrame*) mNextInFlow; + while (flow != 0) { + printf(" %p: [%d,%d,%c]\n", + flow, flow->mFirstContentOffset, flow->mLastContentOffset, + (flow->mLastContentIsComplete ? 'T' : 'F')); + flow = (nsContainerFrame*) flow->mNextInFlow; + } + } +#endif + // Compute the number of children being pushed, and for each child change + // its geometric parent. Remember the last child + for (nsIFrame* f = aFromChild; nsnull != f; f = f->GetNextSibling()) { + numChildren++; +#ifdef NOISY + printf(" "); + ((nsFrame*)f)->ListTag(stdout); + printf("\n"); +#endif + lastChild = f; + f->SetGeometricParent(nextInFlow); + if (this == f->GetContentParent()) { + f->SetContentParent(nextInFlow); + } + } + NS_ASSERTION(numChildren > 0, "no children to push"); + + // Prepend the frames to our next-in-flow's child list + lastChild->SetNextSibling(nextInFlow->mFirstChild); + nextInFlow->mFirstChild = aFromChild; + + // Update our next-in-flow's first content offset and child count + nextInFlow->SetFirstContentOffset(aFromChild); + if (0 == nextInFlow->mChildCount) { + NS_ASSERTION(nextInFlow->LastChild() == lastChild, "unexpected last child"); + nextInFlow->SetLastContentOffset(lastChild); + // If the child is pseudo-frame then SetLastContentOffset will + // have updated the next-in-flow's mLastContentIsComplete flag, + // otherwise we have to do it. + if (!nextInFlow->ChildIsPseudoFrame(lastChild)) { + nextInFlow->mLastContentIsComplete = + PRBool(nsnull == lastChild->GetNextInFlow()); + } + } + nextInFlow->mChildCount += numChildren; +#ifdef NS_DEBUG + nextInFlow->VerifyLastIsComplete(); +#endif + + // If the next-in-flow is being used as a pseudo frame then we need + // to propagate the content offsets upwards to its parent frame + if (nextInFlow->IsPseudoFrame()) { + nextInFlow->PropagateContentOffsets(); + } + +#ifdef NOISY + ListTag(stdout); + printf(": push kids done (childCount=%d)\n", mChildCount); + { + nsContainerFrame* flow = (nsContainerFrame*) mNextInFlow; + while (flow != 0) { + printf(" %p: [%d,%d,%c]\n", + flow, flow->mFirstContentOffset, flow->mLastContentOffset, + (flow->mLastContentIsComplete ? 'T' : 'F')); + flow = (nsContainerFrame*) flow->mNextInFlow; + } + } +#endif + } else { + // Add the frames to our overflow list + NS_ASSERTION(nsnull == mOverflowList, "bad overflow list"); +#ifdef NOISY + ListTag(stdout); + printf(": pushing kids to my overflow list\n"); +#endif + mOverflowList = aFromChild; + } +} + +// Note: mLastContentIsComplete is not set correctly by this routine +// (we don't always know the correct value at this time) +nsIFrame* nsContainerFrame::PullUpOneChild(nsContainerFrame* aNextInFlow, + nsIFrame* aLastChild) +{ + NS_PRECONDITION(nsnull != aNextInFlow, "null ptr"); +#ifdef NS_DEBUG + if (nsnull != aLastChild) { + NS_PRECONDITION(nsnull == aLastChild->GetNextSibling(), "bad last child"); + } +#endif + + // Get first available frame from the next-in-flow + NS_ASSERTION(nsnull == aNextInFlow->mOverflowList, "bad next in flow"); + nsIFrame* kidFrame = aNextInFlow->mFirstChild; + if (nsnull == kidFrame) { + return nsnull; + } + +#ifdef NOISY + ListTag(stdout); + printf(": pulled "); + kidFrame->ListTag(stdout); + printf("\n"); +#endif + + // Take the frame away from the next-in-flow. Update it's first + // content offset and propagate upward the offset if the + // next-in-flow is a pseudo-frame. + aNextInFlow->mFirstChild = kidFrame->GetNextSibling(); + aNextInFlow->mChildCount--; + if (nsnull != aNextInFlow->mFirstChild) { + aNextInFlow->SetFirstContentOffset(aNextInFlow->mFirstChild); + if (aNextInFlow->IsPseudoFrame()) { + aNextInFlow->PropagateContentOffsets(); + } + } else { +#ifdef NOISY + ListTag(stdout); + printf(": drained next-in-flow %p\n", aNextInFlow); +#endif + } + + // Now give the frame to this container + kidFrame->SetGeometricParent(this); + if (aNextInFlow == kidFrame->GetContentParent()) { + kidFrame->SetContentParent(this); + } + if (nsnull == aLastChild) { + mFirstChild = kidFrame; + SetFirstContentOffset(kidFrame); + // If we are a pseudo-frame propagate our first offset upward + if (IsPseudoFrame()) { + PropagateContentOffsets(); + } + } else { + aLastChild->SetNextSibling(kidFrame); + } + kidFrame->SetNextSibling(nsnull); + mChildCount++; + + return kidFrame; +} + +/** + * Moves any frames on the overflwo lists (the prev-in-flow's overflow list and + * the receiver's overflow list) to the child list. + * + * Updates this frame's child count and content mapping. + * + * @return PR_TRUE if any frames were moved and PR_FALSE otherwise + */ +PRBool nsContainerFrame::MoveOverflowToChildList() +{ + PRBool result = PR_FALSE; + + // Check for an overflow list with our prev-in-flow + nsContainerFrame* prevInFlow = (nsContainerFrame*)mPrevInFlow; + if (nsnull != prevInFlow) { + if (nsnull != prevInFlow->mOverflowList) { + NS_ASSERTION(nsnull == mFirstChild, "bad overflow list"); + AppendChildren(prevInFlow->mOverflowList); + prevInFlow->mOverflowList = nsnull; + result = PR_TRUE; + } + } + + // It's also possible that we have an overflow list for ourselves + if (nsnull != mOverflowList) { + NS_ASSERTION(nsnull != mFirstChild, "overflow list but no mapped children"); + AppendChildren(mOverflowList, PR_FALSE); + mOverflowList = nsnull; + result = PR_TRUE; + } + + return result; +} + +/** + * Append child list starting at aChild to this frame's child list. Used for + * processing of the overflow list. + * + * Updates this frame's child count and content mapping. + * + * @param aChild the beginning of the child list + * @param aSetParent if true each child's geometric (and content parent if + * they're the same) parent is set to this frame. + */ +void nsContainerFrame::AppendChildren(nsIFrame* aChild, PRBool aSetParent) +{ + // Link the frames into our child frame list + if (nsnull == mFirstChild) { + // We have no children so aChild becomes the first child + mFirstChild = aChild; + } else { + LastChild()->SetNextSibling(aChild); + } + + // Update our child count and last content offset + nsIFrame* lastChild; + for (nsIFrame* f = aChild; nsnull != f; f = f->GetNextSibling()) { + lastChild = f; + mChildCount++; + + // Reset the geometric parent if requested + if (aSetParent) { + if (f->GetContentParent() == f->GetGeometricParent()) { + f->SetContentParent(this); + } + f->SetGeometricParent(this); + } + } + + // Update our content mapping + if (mFirstChild == aChild) { + SetFirstContentOffset(mFirstChild); + } + SetLastContentOffset(lastChild); + if (!ChildIsPseudoFrame(lastChild)) { + mLastContentIsComplete = PRBool(nsnull == lastChild->GetNextInFlow()); + } + +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif +} + +/** + * Called after pulling-up children from the next-in-flow. Adjusts the first + * content offset of all the empty next-in-flows + * + * It's an error to call this function if all of the next-in-flow frames + * are empty. + * + * @return PR_TRUE if successful and PR_FALSE if all the next-in-flows are + * empty + */ +void nsContainerFrame::AdjustOffsetOfEmptyNextInFlows() +{ + // If the first next-in-flow is not empty then the caller drained + // more than one next-in-flow and then pushed back into it's + // immediate next-in-flow. + nsContainerFrame* nextInFlow = (nsContainerFrame*)mNextInFlow; + PRInt32 nextOffset; + if ((nsnull != nextInFlow) && (nsnull != nextInFlow->mFirstChild)) { + // Use the offset from this frame's first next-in-flow (because + // it's not empty) to propagate into the next next-in-flow (and + // onward if necessary) + nextOffset = nextInFlow->NextChildOffset(); + + // Use next next-in-flow + nextInFlow = (nsContainerFrame*) nextInFlow->mNextInFlow; + + // When this happens, there *must* be a next next-in-flow and the + // next next-in-flow must be empty. + NS_ASSERTION(nsnull != nextInFlow, "bad adjust offsets"); + NS_ASSERTION(nsnull == nextInFlow->mFirstChild, "bad adjust offsets"); + } else { + // Use our offset (since our next-in-flow is empty) to propagate + // into our empty next-in-flows + nextOffset = NextChildOffset(); + } + + while (nsnull != nextInFlow) { + if (nsnull == nextInFlow->mFirstChild) { + NS_ASSERTION(0 == nextInFlow->ChildCount(), "bad child count"); + nextInFlow->mFirstContentOffset = nextOffset; + // If the next-in-flow is a pseudo-frame then we need to have it + // update it's parents offsets too. + if (nextInFlow->IsPseudoFrame()) { + nextInFlow->PropagateContentOffsets(); + } + } else { + // We found a non-empty frame. Verify that its first content offset + // is correct + NS_ASSERTION(nextInFlow->mFirstContentOffset == nextOffset, "bad first content offset"); + return; + } + + nextInFlow = (nsContainerFrame*)nextInFlow->mNextInFlow; + } + + // Make sure that all the next-in-flows weren't empty + NS_ASSERTION(nsnull != ((nsContainerFrame*)mNextInFlow)->mFirstChild, + "Every next-in-flow is empty!"); +} + +///////////////////////////////////////////////////////////////////////////// +// Debugging + +void nsContainerFrame::List(FILE* out, PRInt32 aIndent) const +{ + // Indent + for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out); + + // Output the tag + ListTag(out); + + // Output the first/last content offset + fprintf(out, "[%d,%d,%c] pif=%p nif=%p", + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F'), + mPrevInFlow, mNextInFlow); + + // Output the rect + out << mRect; + + // Output the children + if (ChildCount() > 0) { + if (!mLastContentIsComplete) { + fputs(", complete=>false ", out); + } + + fputs("<\n", out); + for (nsIFrame* child = FirstChild(); child; child = NextChild(child)) { + child->List(out, aIndent + 1); + } + for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out); + fputs(">\n", out); + } else { + fputs("<>\n", out); + } +} + +void nsContainerFrame::ListTag(FILE* out) const +{ + if ((nsnull != mGeometricParent) && IsPseudoFrame()) { + fputs("*", out); + } + nsFrame::ListTag(out); +} + +#define VERIFY_ASSERT(_expr, _msg) \ + if (!(_expr)) { \ + const nsIFrame* top = this; \ + while (top->GetGeometricParent() != nsnull) { \ + top = top->GetGeometricParent(); \ + } \ + top->List(); \ + } \ + NS_ASSERTION(_expr, _msg) + +void nsContainerFrame::VerifyTree() const +{ +#ifdef NS_DEBUG + // Check our child count + PRInt32 len = LengthOf(mFirstChild); + VERIFY_ASSERT(len == mChildCount, "bad child count"); + nsIFrame* lastChild = LastChild(); + if (len != 0) { + VERIFY_ASSERT(nsnull != lastChild, "bad last child"); + } + VERIFY_ASSERT(nsnull == mOverflowList, "bad overflow list"); + + // Make sure our content offsets are sane + VERIFY_ASSERT(mFirstContentOffset <= mLastContentOffset, "bad offsets"); + + // Verify child content offsets and index-in-parents + PRInt32 offset = mFirstContentOffset; + nsIFrame* child = mFirstChild; + while (nsnull != child) { + // Make sure that the child's tree is valid + child->VerifyTree(); + + // Make sure child's index-in-parent is correct + if (ChildIsPseudoFrame(child)) { + nsContainerFrame* pseudo = (nsContainerFrame*) child; + if (pseudo == mFirstChild) { + VERIFY_ASSERT(pseudo->mFirstContentOffset == offset, + "bad pseudo first content offset"); + } + if (pseudo == lastChild) { + VERIFY_ASSERT(pseudo->mFirstContentOffset == offset, + "bad pseudo first content offset"); + VERIFY_ASSERT(pseudo->mLastContentOffset == mLastContentOffset, + "bad pseudo last content offset"); + VERIFY_ASSERT(pseudo->mLastContentIsComplete == mLastContentIsComplete, + "bad pseudo last content is complete"); + } + + offset = pseudo->mLastContentOffset; + if (pseudo->mLastContentIsComplete) { + offset++; + } + } else { + VERIFY_ASSERT(offset == child->GetIndexInParent(), "bad child offset"); + if (nsnull == child->GetNextInFlow()) { + offset++; + } + } + + child = child->GetNextSibling(); + } + + // Verify that our last content offset is correct + if (0 != mChildCount) { + if (mLastContentIsComplete) { + VERIFY_ASSERT(offset == mLastContentOffset + 1, "bad last offset"); + } else { + VERIFY_ASSERT(offset == mLastContentOffset, "bad last offset"); + } + } + + // Make sure that our flow blocks offsets are all correct + if (nsnull == mPrevInFlow) { + PRInt32 nextOffset = NextChildOffset(); + nsContainerFrame* nextInFlow = (nsContainerFrame*) mNextInFlow; + while (nsnull != nextInFlow) { + VERIFY_ASSERT(0 != nextInFlow->mChildCount, "empty next-in-flow"); + VERIFY_ASSERT(nextInFlow->GetFirstContentOffset() == nextOffset, + "bad next-in-flow first offset"); + nextOffset = nextInFlow->NextChildOffset(); + nextInFlow = (nsContainerFrame*) nextInFlow->mNextInFlow; + } + } +#endif +} + +///////////////////////////////////////////////////////////////////////////// + +#ifdef NS_DEBUG +PRInt32 nsContainerFrame::LengthOf(nsIFrame* aFrame) +{ + PRInt32 result = 0; + + while (nsnull != aFrame) { + result++; + aFrame = aFrame->GetNextSibling(); + } + + return result; +} + +void nsContainerFrame::CheckContentOffsets() +{ + NS_PRECONDITION(nsnull != mFirstChild, "null first child"); + + // Verify that our first content offset is correct + if (ChildIsPseudoFrame(mFirstChild)) { + nsContainerFrame* pseudoFrame = (nsContainerFrame*)mFirstChild; + + if (pseudoFrame->GetFirstContentOffset() != mFirstContentOffset) { + nsIFrame* top = this; + while (top->GetGeometricParent() != nsnull) { + top = top->GetGeometricParent(); + } + top->List(); + } + NS_ASSERTION(pseudoFrame->GetFirstContentOffset() == mFirstContentOffset, + "bad first content offset"); + } else { +#ifdef NS_DEBUG + if (!(mFirstChild->GetIndexInParent() == mFirstContentOffset)) { + nsIFrame* top = this; + while (top->GetGeometricParent() != nsnull) { + top = top->GetGeometricParent(); + } + top->List(); + } +#endif + NS_ASSERTION(mFirstChild->GetIndexInParent() == mFirstContentOffset, + "bad first content offset"); + } + + // Verify that our last content offset is correct + nsIFrame* lastChild = LastChild(); + if (ChildIsPseudoFrame(lastChild)) { + nsContainerFrame* pseudoFrame = (nsContainerFrame*)lastChild; + + NS_ASSERTION(pseudoFrame->GetLastContentOffset() == mLastContentOffset, + "bad last content offset"); + + } else { + NS_ASSERTION(lastChild->GetIndexInParent() == mLastContentOffset, + "bad last content offset"); + } +} + +void nsContainerFrame::PreReflowCheck() +{ + PRInt32 len = LengthOf(mFirstChild); + NS_ASSERTION(len == mChildCount, "bad child count"); + + if (0 == mChildCount) { + NS_ASSERTION(nsnull == mFirstChild, "bad child-count/first-child"); + } else { + NS_ASSERTION(nsnull != mFirstChild, "bad child-count/first-child"); + CheckContentOffsets(); + } + VerifyLastIsComplete(); +} + +void nsContainerFrame::PostReflowCheck(ReflowStatus aStatus) +{ + PRInt32 len = LengthOf(mFirstChild) ; + NS_ASSERTION(len == mChildCount, "bad child count"); + + if (0 == mChildCount) { + NS_ASSERTION(nsnull == mFirstChild, "bad child-count/first-child"); + } else { + NS_ASSERTION(nsnull != mFirstChild, "bad child-count/first-child"); + CheckContentOffsets(); + } + VerifyLastIsComplete(); +} + +/** + * A container is empty if it has no children, or it has exactly one + * child and that child is a pseudo-frame and it's empty (recursively + * applied if that child contains one child which is a + * pseudo-frame...) + */ +PRBool nsContainerFrame::IsEmpty() +{ + if (0 == mChildCount) { + return PR_TRUE; + } + if (mChildCount > 1) { + return PR_FALSE; + } + if (ChildIsPseudoFrame(mFirstChild)) { + return ((nsContainerFrame*)mFirstChild)->IsEmpty(); + } + return PR_FALSE; +} + +void nsContainerFrame::CheckNextInFlowOffsets() +{ + // We have to be in a safe state before we can even consider + // checking our next-in-flows state. + if (!SafeToCheckLastContentOffset(this)) { + return; + } + + PRInt32 nextOffset = NextChildOffset(); + nsContainerFrame* nextInFlow = (nsContainerFrame*)mNextInFlow; + while (nsnull != nextInFlow) { + if (!SafeToCheckLastContentOffset(nextInFlow)) { + return; + } +#ifdef NS_DEBUG + if (nextInFlow->GetFirstContentOffset() != nextOffset) { + nsIFrame* top = this; + while (top->GetGeometricParent() != nsnull) { + top = top->GetGeometricParent(); + } + top->List(); + } +#endif + NS_ASSERTION(nextInFlow->GetFirstContentOffset() == nextOffset, + "bad next-in-flow first offset"); + // Verify the content offsets are in sync with the first/last child + nextInFlow->CheckContentOffsets(); + nextOffset = nextInFlow->NextChildOffset(); + + // Move to the next-in-flow + nextInFlow = (nsContainerFrame*)nextInFlow->mNextInFlow; + } +} + +PRBool +nsContainerFrame::SafeToCheckLastContentOffset(nsContainerFrame* aContainer) +{ + if (0 == aContainer->mChildCount) { + // We can't use the last content offset on an empty frame + return PR_FALSE; + } + + if (nsnull != aContainer->mOverflowList) { + // If a frame has an overflow list then it's last content offset + // cannot be used for assertion checks (because it's not done + // being reflowed). + return PR_FALSE; + } + + nsIFrame* lastChild = aContainer->LastChild(); + if (aContainer->ChildIsPseudoFrame(lastChild)) { + // If the containers last child is a pseudo-frame then the + // containers last content offset is determined by the child. Ask + // the child if it's safe to use the last content offset. + return SafeToCheckLastContentOffset((nsContainerFrame*)lastChild); + } + + return PR_TRUE; +} + +void nsContainerFrame::VerifyLastIsComplete() const +{ + if (nsnull == mFirstChild) { + // If we have no children, our mLastContentIsComplete doesn't mean + // anything + return; + } + if (nsnull != mOverflowList) { + // If we can an overflow list then our mLastContentIsComplete and + // mLastContentOffset are un-verifyable because a reflow is in + // process. + return; + } + + nsIFrame* lastKid = LastChild(); + + if (ChildIsPseudoFrame(lastKid)) { + // When my last child is a pseudo-frame it means that our + // mLastContentIsComplete is a copy of it's. + nsContainerFrame* pseudoFrame = (nsContainerFrame*) lastKid; + NS_ASSERTION(mLastContentIsComplete == pseudoFrame->mLastContentIsComplete, + "bad mLastContentIsComplete"); + } else { + // If my last child has a next-in-flow then our + // mLastContentIsComplete must be false (because our last child is + // obviously not complete) + nsIFrame* lastKidNextInFlow = lastKid->GetNextInFlow(); + if (nsnull != lastKidNextInFlow) { + if (mLastContentIsComplete) { + const nsIFrame* top = this; + while (top->GetGeometricParent() != nsnull) { + top = top->GetGeometricParent(); + } + top->List(); + } + NS_ASSERTION(mLastContentIsComplete == PR_FALSE, + "bad mLastContentIsComplete"); + } else { + // We don't know what state our mLastContentIsComplete should be in. + } + } +} +#endif diff --git a/mozilla/layout/base/src/nsContainerFrame.h b/mozilla/layout/base/src/nsContainerFrame.h new file mode 100644 index 00000000000..da03faf7e43 --- /dev/null +++ b/mozilla/layout/base/src/nsContainerFrame.h @@ -0,0 +1,391 @@ +/* -*- 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. + */ +#ifndef nsContainerFrame_h___ +#define nsContainerFrame_h___ + +#include "nsSplittableFrame.h" + +/** + * Implementation of a container frame. Supports being used a pseudo- + * frame (a frame that maps the same content as its parent). + * + * Container frame iterates its child content and for each content object creates + * one or more child frames. There are three member variables (class invariants) + * used to manage this mapping: + *
+ *
mFirstContentOffset + *
the content offset of the first piece of content mapped by this container. + *
mLastContentOffset + *
the content offset of the last piece of content mapped by this container + *
mLastContentIsComplete + *
a boolean indicating whether the last piece of content mapped by this + * container is complete, or whether its frame needs to be continued. + *
+ * + * Here are the rules governing the state of the class invariants. The debug member + * functions PreReflowCheck() and PostReflowCheck() validate these rules. For the + * purposes of this discussion an empty frame is defined as a container + * frame with a null child-list, i.e. its mFirstChild is nsnull. + * + *

Non-Empty Frames

+ * For a container frame that is not an empty frame the following must be true: + *
    + *
  • if the first child frame is a pseudo-frame then mFirstContentOffset must be + * equal to the first child's mFirstContentOffset; otherwise, mFirstContentOffset + * must be equal to the first child frame's index in parent + *
  • if the last child frame is a pseudo-frame then mLastContentOffset must be + * equal to the last child's mLastContentOffset; otherwise, mLastContentOffset + * must be equal to the last child frame's index in parent + *
  • if the last child is a pseudo-frame then mLastContentIsComplete should be + * equal to that last child's mLastContentIsComplete; otherwise, if the last + * child frame has a next-in-flow then mLastContentIsComplete must be PR_TRUE + *
+ * + *

Empty Frames

+ * For an empty container frame the following must be true: + *
    + *
  • mFirstContentOffset must be equal to the NextContentOffset() of the first + * non-empty prev-in-flow + *
  • mChildCount must be 0 + *
+ * + * The value of mLastContentOffset and mLastContentIsComplete are undefined + * for an empty frame. + * + *

Next-In-Flow List

+ * The rule is that if a container frame is not complete then the mFirstContentOffset, + * mLastContentOffset, and mLastContentIsComplete of its next-in-flow frames must + * always correct. This means that whenever you push/pull child frames from a + * next-in-flow you must update that next-in-flow's state so that it is + * consistent with the aforementioned rules for empty and non-empty frames. + * + *

Pulling-Up Frames

+ * In the processing of pulling-up child frames from a next-in-flow it's possible + * to pull-up all the child frames from a next-in-flow thereby leaving the next-in-flow + * empty. There are two cases to consider: + *
    + *
  1. All of the child frames from all of the next-in-flow have been pulled-up. + * This means that all the next-in-flow frames are empty, the container being + * reflowed is complete, and the next-in-flows will be deleted. + * + * In this case the next-in-flows' mFirstContentOffset is also undefined. + *
  2. Not all the child frames from all the next-in-flows have been pulled-up. + * This means the next-in-flow consists of one or more empty frames followed + * by one or more non-empty frames. Note that all the empty frames must be + * consecutive. This means it is illegal to have an empty frame followed by + * a non-empty frame, followed by an empty frame, followed by a non-empty frame. + *
+ * + *

Pseudo-Frames

+ * As stated above, when pulling/pushing child frames from/to a next-in-flow the + * state of the next-in-flow must be updated. + * + * If the next-in-flow is a pseudo-frame then not only does the next-in-flow's state + * need to be updated, but the state of its geometric parent must be updated as well. + * See member function PropagateContentOffsets() for details. + * + * This rule is applied recursively, so if the next-in-flow's geometric parent is + * also a pseudo-frame then its geometric parent must be updated. + */ +class nsContainerFrame : public nsSplittableFrame +{ +public: + /** + * Default implementation is to use the content delegate to create a new + * frame. After the frame is created it uses PrepareContinuingFrame() to + * set the content offsets, mLastContentOffset, and append the continuing + * frame to the flow. + */ + virtual nsIFrame* CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent); + + // Painting + virtual void Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + /** + * Pass through the event to the correct child frame. + * Return PR_TRUE if the event is consumed. + */ + virtual nsEventStatus HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent); + + virtual PRInt32 GetCursorAt(nsIPresContext& aPresContext, + const nsPoint& aPoint, + nsIFrame** aFrame); + + // Child frame enumeration. + // ChildAt() retruns null if the index is not in the range 0 .. ChildCount() - 1. + // IndexOf() returns -1 if the frame is not in the child list. + virtual PRInt32 ChildCount() const; + virtual nsIFrame* ChildAt(PRInt32 aIndex) const; + virtual PRInt32 IndexOf(const nsIFrame* aChild) const; + virtual nsIFrame* FirstChild() const; + virtual nsIFrame* NextChild(const nsIFrame* aChild) const; + virtual nsIFrame* PrevChild(const nsIFrame* aChild) const; + virtual nsIFrame* LastChild() const; + + // Access functions for starting and end content offsets. These reflect the + // range of content mapped by the frame. + // + // If the container is empty (has no children) the last content offset is + // undefined + PRInt32 GetFirstContentOffset() const {return mFirstContentOffset;} + void SetFirstContentOffset(PRInt32 aOffset) {mFirstContentOffset = aOffset;} + PRInt32 GetLastContentOffset() const {return mLastContentOffset;} + void SetLastContentOffset(PRInt32 aOffset) {mLastContentOffset = aOffset;} + + /** return PR_TRUE if the last mapped child is complete */ + PRBool GetLastContentIsComplete() const {return mLastContentIsComplete;} + /** set the state indicating whether the last mapped child is complete */ + void SetLastContentIsComplete(PRBool aLIC) {mLastContentIsComplete = aLIC;} + + // Get the offset for the next child content, i.e. the child after the + // last child that fit in us + PRInt32 NextChildOffset() const; + + // Returns true if this frame is being used a pseudo frame + PRBool IsPseudoFrame() const; + + // Debugging + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + virtual void ListTag(FILE* out = stdout) const; + virtual void VerifyTree() const; + + /** + * This is used to propagate this frame's mFirstContentOffset, mLastContentOffset, + * and mLastContentIsComplete to its geometric parent frame. Recurses if the + * geometric parent is a pseudo-frame. + * + * If this frame is the parent's first child then the parent's mFirstContentOffset + * is set to be this frame's mFirstContentOffset. + * + * If this frame is the parent's last child then the parent's mLastContentOffset + * is set to be this frame's mLastContentOffset, and the parent's + * mLastContentIsComplete is set to be this frame's mLastContentIsComplete. + * + * It's a precondition that this frame must be a pseudo-frame. + */ + void PropagateContentOffsets(); + +protected: + // Constructor. Takes as arguments the content object, the index in parent, + // and the Frame for the content parent + nsContainerFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + virtual ~nsContainerFrame(); + + /** + * Prepare a continuation frame of this frame for reflow. Appends it to the + * flow, sets its content offsets, mLastContentIsComplete, and style context. + * Subclasses should invoke this method after construction of a continuing frame. + */ + void PrepareContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent, + nsContainerFrame* aContFrame); + + + virtual void PaintChildren(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + /** + * Reflow a child frame and return the status of the reflow. If the child + * is complete and it has next-in-flows, then delete the next-in-flows. + */ + ReflowStatus ReflowChild(nsIFrame* aKidFrame, + nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + + /** + * Reflow a child frame and return the status of the reflow. If the child + * is complete and it has next-in-flows, then delete the next-in-flows. + * + * Use this version if you have a space manager. Checks if the child frame + * supports interface nsIRunaround. If it does, interface nsIRunaround is + * used to reflow the child; otherwise interface nsIFrame is used. If the + * child is splittable then runaround is done using continuing frames. + * + * @see nsIRunaround + */ + ReflowStatus ReflowChild(nsIFrame* aKidFrame, + nsIPresContext* aPresContext, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsSize* aMaxElementSize); + + /** + * Moves any frames on both the prev-in-flow's overflow list and the receiver's + * overflow to the receiver's child list. + * + * Resets the overlist pointers to nsnull, and updates the receiver's child + * count and content mapping. + * + * @return PR_TRUE if any frames were moved and PR_FALSE otherwise + */ + PRBool MoveOverflowToChildList(); + + /** + * Remove and delete aChild's next-in-flow(s). Updates the sibling and flow + * pointers + * + * Updates the child count and content offsets of all containers that are + * affected + * + * @param aChild child this child's next-in-flow + * @return PR_TRUE if successful and PR_FALSE otherwise + */ + PRBool DeleteChildsNextInFlow(nsIFrame* aChild); + + /** + * Push aFromChild and its next siblings to the next-in-flow. Change the + * geometric parent of each frame that's pushed. If there is no next-in-flow + * the frames are placed on the overflow list (and the geometric parent is + * left unchanged). + * + * Updates the next-in-flow's child count and content offsets. Does + * not update the pusher's child count or last content offset. + * + * @param aFromChild the first child frame to push. It is disconnected from + * aPrevSibling + * @param aPrevSibling aFromChild's previous sibling. Must not be null. It's + * an error to push a parent's first child frame + * @param aNextInFlowsLastChildIsComplete the next-in-flow's + * mLastContentIsComplete flag. This is used when refilling an + * empty next-in-flow that was drained by the caller. + */ + void PushChildren(nsIFrame* aFromChild, nsIFrame* aPrevSibling, + PRBool aNextInFlowsLastChildIsComplete); + + /** + * Attempt to pull one child from the next-in-flow, if any. This + * does everything necessary for the receiving frame and the + * next-in-flow frame to ensure that the content offsets and + * mLastContentIsComplete flags are correct, and it makes sure that + * the parent offsets if this frame or the next is a pseudo-frame + * are correct. If there are no children to pull from the next + * in flow, nsnull is returned. + * + * If the caller decides that it doesn't want the child from the + * next in flow, it can call PushChildren to push it back. + * + * @param aNextInFlow the next-in-flow frame to attempt to pull a child + * from + * @param aLastChild the current last child for this frame. If a child + * is pullable then the child will become aLastChild's next + * sibling + */ + nsIFrame* PullUpOneChild(nsContainerFrame* aNextInFlow, + nsIFrame* aLastChild); + + /** + * Called after pulling-up children from the next-in-flow. Adjusts the first + * content offset of all the empty next-in-flows + * + * It's an error to call this function if all of the next-in-flow frames + * are empty. + */ + void AdjustOffsetOfEmptyNextInFlows(); + + /** + * Append child list starting at aChild to this frame's child list. Used for + * processing of the overflow list. + * + * Updates this frame's child count and content mapping. + * + * @param aChild the beginning of the child list + * @param aSetParent if true each child's geometric (and content parent if + * they're the same) parent is set to this frame. + */ + void AppendChildren(nsIFrame* aChild, PRBool aSetParent = PR_TRUE); + + // Returns true if aChild is being used as a pseudo frame + PRBool ChildIsPseudoFrame(const nsIFrame* aChild) const; + + /** + * Sets the first content offset based on the first child frame. + */ + void SetFirstContentOffset(const nsIFrame* aFirstChild); + + /** + * Sets the last content offset based on the last child frame. If the last + * child is a pseudo frame then it sets mLastContentIsComplete to be the same + * as the last child's mLastContentIsComplete + */ + void SetLastContentOffset(const nsIFrame* aLastChild); + +#ifdef NS_DEBUG + /** + * Return the number of children in the sibling list, starting at aChild. + * Returns zero if aChild is nsnull. + */ + static PRInt32 LengthOf(nsIFrame* aChild); + + /** + * Before reflow for this container has started we check that all + * is well. + */ + void PreReflowCheck(); + + /** + * After reflow for this container has finished we check that all + * is well. + * + * @param aStatus status to be returned from the resize reflow. If the status + * is frNotComplete then the next-in-flow content offsets are + * validated as well + */ + void PostReflowCheck(ReflowStatus aStatus); + + void CheckNextInFlowOffsets(); + + PRBool IsEmpty(); + + PRBool SafeToCheckLastContentOffset(nsContainerFrame* nextInFlow); + + /** + * Verify that our mLastContentIsComplete flag is set correctly. + */ + void VerifyLastIsComplete() const; +#endif + + nsIFrame* mFirstChild; + PRInt32 mChildCount; + PRInt32 mFirstContentOffset; // index of first child we map + PRInt32 mLastContentOffset; // index of last child we map + PRBool mLastContentIsComplete; + nsIFrame* mOverflowList; + +private: +#ifdef NS_DEBUG + /** + * Helper function to verify that the first/last content offsets + * are correct. Note: this call will blow up if you have no + * children. + */ + void CheckContentOffsets(); +#endif +}; + +#endif /* nsContainerFrame_h___ */ diff --git a/mozilla/layout/base/src/nsDocument.cpp b/mozilla/layout/base/src/nsDocument.cpp new file mode 100644 index 00000000000..6f94c0a0175 --- /dev/null +++ b/mozilla/layout/base/src/nsDocument.cpp @@ -0,0 +1,618 @@ +/* -*- 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 "nsDocument.h" +#include "nsIArena.h" +#include "nsIURL.h" +#include "nsString.h" +#include "nsIContent.h" +#include "nsIStyleSet.h" +#include "nsIStyleSheet.h" +#include "nsIPresShell.h" +#include "nsIDocumentObserver.h" + +static NS_DEFINE_IID(kIDocumentIID, NS_IDOCUMENT_IID); + +#include "nsIDOMElement.h" + +static NS_DEFINE_IID(kIDOMDocumentIID, NS_IDOMDOCUMENT_IID); +static NS_DEFINE_IID(kIDOMNodeIID, NS_IDOMNODE_IID); +static NS_DEFINE_IID(kIContentIID, NS_ICONTENT_IID); +static NS_DEFINE_IID(kIDOMElementIID, NS_IDOMELEMENT_IID); +static NS_DEFINE_IID(kIScriptObjectOwnerIID, NS_ISCRIPTOBJECTOWNER_IID); + + +nsDocument::nsDocument() +{ + NS_INIT_REFCNT(); + + mArena = nsnull; + mDocumentTitle = nsnull; + mDocumentURL = nsnull; + mCharacterSet = eCharSetID_IsoLatin1; + mParentDocument = nsnull; + mRootContent = nsnull; + mScriptObject = nsnull; + + Init();/* XXX */ +} + +nsDocument::~nsDocument() +{ + if (nsnull != mDocumentTitle) { + delete mDocumentTitle; + mDocumentTitle = nsnull; + } + NS_IF_RELEASE(mDocumentURL); + + mParentDocument = nsnull; + + // Delete references to sub-documents + PRInt32 index = mSubDocuments.Count(); + while (--index >= 0) { + nsIDocument* subdoc = (nsIDocument*) mSubDocuments.ElementAt(index); + NS_RELEASE(subdoc); + } + + NS_IF_RELEASE(mRootContent); + // Delete references to style sheets + index = mStyleSheets.Count(); + while (--index >= 0) { + nsIStyleSheet* sheet = (nsIStyleSheet*) mStyleSheets.ElementAt(index); + NS_RELEASE(sheet); + } + + NS_IF_RELEASE(mArena); +} + +nsresult nsDocument::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if (nsnull == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kIDocumentIID)) { + *aInstancePtr = (void*)(nsIDocument*)this; + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIDOMDocumentIID)) { + *aInstancePtr = (void*)(nsIDOMDocument*)this; + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIScriptObjectOwnerIID)) { + *aInstancePtr = (void*)(nsIScriptObjectOwner*)this; + AddRef(); + return NS_OK; + } + static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + if (aIID.Equals(kISupportsIID)) { + *aInstancePtr = (void*)(nsISupports*)(nsIDocument*)this; + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +NS_IMPL_ADDREF(nsDocument) +NS_IMPL_RELEASE(nsDocument) + +nsresult nsDocument::Init() +{ + nsresult rv = NS_NewHeapArena(&mArena, nsnull); + if (NS_OK != rv) { + return rv; + } + return NS_OK; +} + +nsIArena* nsDocument::GetArena() +{ + if (nsnull != mArena) { + NS_ADDREF(mArena); + } + return mArena; +} + +void nsDocument::StartDocumentLoad() +{ +} + +void nsDocument::PauseDocumentLoad() +{ +} + +void nsDocument::StopDocumentLoad() +{ +} + +void nsDocument::WaitForDocumentLoad() +{ +} + +PRBool nsDocument::IsDocumentLoaded() +{ + return PR_TRUE; +} + +const nsString* nsDocument::GetDocumentTitle() const +{ + return mDocumentTitle; +} + +nsIURL* nsDocument::GetDocumentURL() const +{ + NS_IF_ADDREF(mDocumentURL); + return mDocumentURL; +} + +nsCharSetID nsDocument::GetDocumentCharacterSet() const +{ + return mCharacterSet; +} + +void nsDocument::SetDocumentCharacterSet(nsCharSetID aCharSetID) +{ + mCharacterSet = aCharSetID; +} + +nsIPresShell* nsDocument::CreateShell(nsIPresContext* aContext, + nsIViewManager* aViewManager, + nsIStyleSet* aStyleSet) +{ + nsIPresShell* shell; + nsresult status = NS_NewPresShell(&shell); + if ((NS_OK == status) && + (NS_OK == shell->Init(this, aContext, aViewManager, aStyleSet))) { + // Note: we don't hold a ref to the shell (it holds a ref to us) + mPresShells.AppendElement(shell); + } + return shell; +} + +PRBool nsDocument::DeleteShell(nsIPresShell* aShell) +{ + return mPresShells.RemoveElement(aShell); +} + +PRInt32 nsDocument::GetNumberOfShells() +{ + return mPresShells.Count(); +} + +nsIPresShell* nsDocument::GetShellAt(PRInt32 aIndex) +{ + nsIPresShell* shell = (nsIPresShell*) mPresShells.ElementAt(aIndex); + if (nsnull != shell) { + NS_ADDREF(shell); + } + return shell; +} + +nsIDocument* nsDocument::GetParentDocument() +{ + if (nsnull != mParentDocument) { + NS_ADDREF(mParentDocument); + } + return mParentDocument; +} + +/** + * Note that we do *not* AddRef our parent because that would + * create a circular reference. + */ +void nsDocument::SetParentDocument(nsIDocument* aParent) +{ + mParentDocument = aParent; +} + +void nsDocument::AddSubDocument(nsIDocument* aSubDoc) +{ + NS_ADDREF(aSubDoc); + mSubDocuments.AppendElement(aSubDoc); +} + +PRInt32 nsDocument::GetNumberOfSubDocuments() +{ + return mSubDocuments.Count(); +} + +nsIDocument* nsDocument::GetSubDocumentAt(PRInt32 aIndex) +{ + nsIDocument* doc = (nsIDocument*) mSubDocuments.ElementAt(aIndex); + if (nsnull != doc) { + NS_ADDREF(doc); + } + return doc; +} + +nsIContent* nsDocument::GetRootContent() +{ + if (nsnull != mRootContent) { + NS_ADDREF(mRootContent); + } + return mRootContent; +} + +void nsDocument::SetRootContent(nsIContent* aRoot) +{ + NS_IF_RELEASE(mRootContent); + if (nsnull != aRoot) { + mRootContent = aRoot; + NS_ADDREF(aRoot); + } +} + +PRInt32 nsDocument::GetNumberOfStyleSheets() +{ + return mStyleSheets.Count(); +} + +nsIStyleSheet* nsDocument::GetStyleSheetAt(PRInt32 aIndex) +{ + nsIStyleSheet* sheet = (nsIStyleSheet*)mStyleSheets.ElementAt(aIndex); + NS_IF_ADDREF(sheet); + return sheet; +} + +void nsDocument::AddStyleSheetToSet(nsIStyleSheet* aSheet, nsIStyleSet* aSet) +{ + aSet->AppendDocStyleSheet(aSheet); +} + +void nsDocument::AddStyleSheet(nsIStyleSheet* aSheet) +{ + NS_PRECONDITION(nsnull != aSheet, "null arg"); + mStyleSheets.AppendElement(aSheet); + NS_ADDREF(aSheet); + + PRInt32 count = mPresShells.Count(); + PRInt32 index; + for (index = 0; index < count; index++) { + nsIPresShell* shell = (nsIPresShell*)mPresShells.ElementAt(index); + nsIStyleSet* set = shell->GetStyleSet(); + if (nsnull != set) { + AddStyleSheetToSet(aSheet, set); + NS_RELEASE(set); + } + } + + count = mObservers.Count(); + for (index = 0; index < count; index++) { + nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers.ElementAt(index); + observer->StyleSheetAdded(aSheet); + } +} + +// Note: We don't hold a reference to the document observer; we assume +// that it has a live reference to the document. +void nsDocument::AddObserver(nsIDocumentObserver* aObserver) +{ + mObservers.AppendElement(aObserver); +} + +PRBool nsDocument::RemoveObserver(nsIDocumentObserver* aObserver) +{ + return mObservers.RemoveElement(aObserver); +} + +void nsDocument::ContentChanged(nsIContent* aContent, + nsISubContent* aSubContent, + PRInt32 aChangeType) +{ + PRInt32 count = mObservers.Count(); + for (PRInt32 i = 0; i < count; i++) { + nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; + observer->ContentChanged(aContent, aSubContent, aChangeType); + } +} + +void nsDocument::ContentAppended(nsIContent* aContainer) +{ + PRInt32 count = mObservers.Count(); + for (PRInt32 i = 0; i < count; i++) { + nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; + observer->ContentAppended(aContainer); + } +} + +void nsDocument::ContentInserted(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) +{ + PRInt32 count = mObservers.Count(); + for (PRInt32 i = 0; i < count; i++) { + nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; + observer->ContentInserted(aContainer, aChild, aIndexInContainer); + } +} + +void nsDocument::ContentReplaced(nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer) +{ + PRInt32 count = mObservers.Count(); + for (PRInt32 i = 0; i < count; i++) { + nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; + observer->ContentReplaced(aContainer, aOldChild, aNewChild, + aIndexInContainer); + } +} + +void nsDocument::ContentWillBeRemoved(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) +{ + PRInt32 count = mObservers.Count(); + for (PRInt32 i = 0; i < count; i++) { + nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; + observer->ContentWillBeRemoved(aContainer, aChild, aIndexInContainer); + } +} + +void nsDocument::ContentHasBeenRemoved(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) +{ + PRInt32 count = mObservers.Count(); + for (PRInt32 i = 0; i < count; i++) { + nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; + observer->ContentHasBeenRemoved(aContainer, aChild, aIndexInContainer); + } +} + +nsresult nsDocument::GetScriptObject(JSContext *aContext, void** aScriptObject) +{ + nsresult res = NS_OK; + + if (nsnull == mScriptObject) { + res = NS_NewScriptDocument(aContext, this, nsnull, (JSObject**)&mScriptObject); + } + *aScriptObject = mScriptObject; + + return res; +} + +nsresult nsDocument::ResetScriptObject() +{ + mScriptObject = nsnull; + return NS_OK; +} + +// +// nsIDOMDocument interface +// +nsresult nsDocument::GetNodeType(PRInt32 *aType) +{ + *aType = nsIDOMNode::DOCUMENT; + return NS_OK; +} + +nsresult nsDocument::GetParentNode(nsIDOMNode **aNode) +{ + return NS_ERROR_FAILURE; +} + +nsresult nsDocument::GetChildNodes(nsIDOMNodeIterator **aIterator) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::HasChildNodes() +{ + if (nsnull != mRootContent) { + return NS_OK; + } + else { + return NS_ERROR_FAILURE; + } +} + +nsresult nsDocument::GetFirstChild(nsIDOMNode **aNode) +{ + if (nsnull != mRootContent) { + nsresult res = mRootContent->QueryInterface(kIDOMNodeIID, (void**)aNode); + NS_ASSERTION(NS_OK == res, "Must be a DOM Node"); + return res; + } + + return NS_ERROR_FAILURE; +} + +nsresult nsDocument::GetPreviousSibling(nsIDOMNode **aNode) +{ + // no siblings + return NS_ERROR_FAILURE; +} + +nsresult nsDocument::GetNextSibling(nsIDOMNode **aNode) +{ + // no siblings + return NS_ERROR_FAILURE; +} + +nsresult nsDocument::InsertBefore(nsIDOMNode *newChild, nsIDOMNode *refChild) +{ + // a document has only one child + return NS_ERROR_FAILURE; +} + +nsresult nsDocument::ReplaceChild(nsIDOMNode *newChild, nsIDOMNode *oldChild) +{ + NS_PRECONDITION(nsnull != newChild && nsnull != oldChild, "null arg"); + nsIContent* content; + + nsresult res = oldChild->QueryInterface(kIContentIID, (void**)&content); + if (NS_OK == res) { + // check that we are replacing the root content + if (content == mRootContent) { + nsIContent* newContent; + res = newChild->QueryInterface(kIContentIID, (void**)&newContent); + if (NS_OK == res) { + SetRootContent(newContent); + NS_RELEASE(newContent); + } + else NS_ASSERTION(0, "Must be an nsIContent"); // nsIContent not supported. Who are you? + } + + NS_RELEASE(content); + } + else NS_ASSERTION(0, "Must be an nsIContent"); // nsIContent not supported. Who are you? + + return res; +} + +nsresult nsDocument::RemoveChild(nsIDOMNode *oldChild) +{ + NS_PRECONDITION(nsnull != oldChild, "null arg"); + nsIContent* content; + + nsresult res = oldChild->QueryInterface(kIContentIID, (void**)&content); + if (NS_OK == res) { + if (content == mRootContent) { + NS_RELEASE(mRootContent); + mRootContent = nsnull; + } + } + + return res; +} + +nsresult nsDocument::GetMasterDoc(nsIDOMDocument **aDocument) +{ + AddRef(); + *aDocument = (nsIDOMDocument*)this; + return NS_OK; +} + +nsresult nsDocument::SetMasterDoc(nsIDOMDocument *aDocument) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::GetDocumentType(nsIDOMNode **aDocType) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::SetDocumentType(nsIDOMNode *aNode) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::GetDocumentElement(nsIDOMElement **aElement) +{ + nsresult res = NS_ERROR_FAILURE; + + if (nsnull != mRootContent) { + res = mRootContent->QueryInterface(kIDOMElementIID, (void**)aElement); + NS_ASSERTION(NS_OK == res, "Must be a DOM Element"); + } + + return res; +} + +nsresult nsDocument::SetDocumentElement(nsIDOMElement *aElement) +{ + NS_PRECONDITION(nsnull != aElement, "null arg"); + nsIContent* content; + + nsresult res = aElement->QueryInterface(kIContentIID, (void**)&content); + if (NS_OK == res) { + SetRootContent(content); + NS_RELEASE(content); + } + else NS_ASSERTION(0, "Must be an nsIContent"); // nsIContent not supported. Who are you? + + return res; +} + +nsresult nsDocument::GetDocumentContext(nsIDOMDocumentContext **aDocContext) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::SetDocumentContext(nsIDOMDocumentContext *aContext) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::CreateDocumentContext(nsIDOMDocumentContext **aDocContext) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::CreateElement(nsString &aTagName, + nsIDOMAttributeList *aAttributes, + nsIDOMElement **aElement) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::CreateTextNode(nsString &aData, nsIDOMText** aTextNode) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::CreateComment(nsString &aData, nsIDOMComment **aComment) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::CreatePI(nsString &aName, nsString &aData, nsIDOMPI **aPI) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::CreateAttribute(nsString &aName, + nsIDOMNode *value, + nsIDOMAttribute **aAttribute) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::CreateAttributeList(nsIDOMAttributeList **aAttributesList) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::CreateTreeIterator(nsIDOMNode **aNode, nsIDOMTreeIterator **aTreeIterator) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDocument::GetElementsByTagName(nsIDOMNodeIterator **aIterator) +{ + //XXX TBI + return NS_ERROR_NOT_IMPLEMENTED; +} + diff --git a/mozilla/layout/base/src/nsDocument.h b/mozilla/layout/base/src/nsDocument.h new file mode 100644 index 00000000000..7567f3c2a5e --- /dev/null +++ b/mozilla/layout/base/src/nsDocument.h @@ -0,0 +1,187 @@ +/* -*- 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. + */ +#ifndef nsDocument_h___ +#define nsDocument_h___ + +#include "nsIDocument.h" +#include "nsVoidArray.h" +#include "nsIDOMDocument.h" +#include "nsIScriptObjectOwner.h" + +// Base class for our document implementations +class nsDocument : public nsIDocument, public nsIDOMDocument, public nsIScriptObjectOwner { +public: + NS_DECL_ISUPPORTS + + virtual nsIArena* GetArena(); + + virtual void StartDocumentLoad(); + virtual void PauseDocumentLoad(); + virtual void StopDocumentLoad(); + virtual void WaitForDocumentLoad(); + virtual PRBool IsDocumentLoaded(); + + /** + * Return the title of the document. May return null. + */ + virtual const nsString* GetDocumentTitle() const; + + /** + * Return the URL for the document. May return null. + */ + virtual nsIURL* GetDocumentURL() const; + + /** + * Return a standard name for the document's character set. This will + * trigger a startDocumentLoad if necessary to answer the question. + */ + virtual nsCharSetID GetDocumentCharacterSet() const; + virtual void SetDocumentCharacterSet(nsCharSetID aCharSetID); + + /** + * Create a new presentation shell that will use aContext for + * it's presentation context (presentation context's must not be + * shared among multiple presentation shell's). + */ + virtual nsIPresShell* CreateShell(nsIPresContext* aContext, + nsIViewManager* aViewManager, + nsIStyleSet* aStyleSet); + virtual PRBool DeleteShell(nsIPresShell* aShell); + virtual PRInt32 GetNumberOfShells(); + virtual nsIPresShell* GetShellAt(PRInt32 aIndex); + + /** + * Return the parent document of this document. Will return null + * unless this document is within a compound document and has a parent. + */ + virtual nsIDocument* GetParentDocument(); + virtual void SetParentDocument(nsIDocument* aParent); + virtual void AddSubDocument(nsIDocument* aSubDoc); + virtual PRInt32 GetNumberOfSubDocuments(); + virtual nsIDocument* GetSubDocumentAt(PRInt32 aIndex); + + /** + * Return the root content object for this document. + */ + virtual nsIContent* GetRootContent(); + virtual void SetRootContent(nsIContent* aRoot); + + /** + * Get the style sheets owned by this document. + */ + virtual PRInt32 GetNumberOfStyleSheets(); + virtual nsIStyleSheet* GetStyleSheetAt(PRInt32 aIndex); + virtual void AddStyleSheet(nsIStyleSheet* aSheet); + + /** + * Add a new observer of document change notifications. Whenever + * content is changed, appended, inserted or removed the observers are + * informed. + */ + virtual void AddObserver(nsIDocumentObserver* aObserver); + + /** + * Remove an observer of document change notifications. This will + * return false if the observer cannot be found. + */ + virtual PRBool RemoveObserver(nsIDocumentObserver* aObserver); + + // Observation hooks used by content nodes to propagate + // notifications to document observers. + virtual void ContentChanged(nsIContent* aContent, + nsISubContent* aSubContent, + PRInt32 aChangeType); + + virtual void ContentAppended(nsIContent* aContainer); + + virtual void ContentInserted(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer); + + virtual void ContentReplaced(nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer); + + virtual void ContentWillBeRemoved(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer); + + virtual void ContentHasBeenRemoved(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer); + +public: + + virtual nsresult GetScriptObject(JSContext *aContext, void** aScriptObject); + virtual nsresult ResetScriptObject(); + + // nsIDOMDocument interface + virtual nsresult GetNodeType(PRInt32 *aType); + virtual nsresult GetParentNode(nsIDOMNode **aNode); + virtual nsresult GetChildNodes(nsIDOMNodeIterator **aIterator); + virtual nsresult HasChildNodes(); + virtual nsresult GetFirstChild(nsIDOMNode **aNode); + virtual nsresult GetPreviousSibling(nsIDOMNode **aNode); + virtual nsresult GetNextSibling(nsIDOMNode **aNode); + virtual nsresult InsertBefore(nsIDOMNode *newChild, nsIDOMNode *refChild); + virtual nsresult ReplaceChild(nsIDOMNode *newChild, nsIDOMNode *oldChild); + virtual nsresult RemoveChild(nsIDOMNode *oldChild); + virtual nsresult GetMasterDoc(nsIDOMDocument **aDocument); + virtual nsresult SetMasterDoc(nsIDOMDocument *aDocument); + virtual nsresult GetDocumentType(nsIDOMNode **aDocType); + virtual nsresult SetDocumentType(nsIDOMNode *aNode); + virtual nsresult GetDocumentElement(nsIDOMElement **aElement); + virtual nsresult SetDocumentElement(nsIDOMElement *aElement); + virtual nsresult GetDocumentContext(nsIDOMDocumentContext **aDocContext); + virtual nsresult SetDocumentContext(nsIDOMDocumentContext *aContext); + virtual nsresult CreateDocumentContext(nsIDOMDocumentContext **aDocContext); + virtual nsresult CreateElement(nsString &aTagName, + nsIDOMAttributeList *aAttributes, + nsIDOMElement **aElement); + virtual nsresult CreateTextNode(nsString &aData, nsIDOMText** aTextNode); + virtual nsresult CreateComment(nsString &aData, nsIDOMComment **aComment); + virtual nsresult CreatePI(nsString &aName, nsString &aData, nsIDOMPI **aPI); + virtual nsresult CreateAttribute(nsString &aName, + nsIDOMNode *value, + nsIDOMAttribute **aAttribute); + virtual nsresult CreateAttributeList(nsIDOMAttributeList **aAttributesList); + virtual nsresult CreateTreeIterator(nsIDOMNode **aNode, nsIDOMTreeIterator **aTreeIterator); + virtual nsresult GetElementsByTagName(nsIDOMNodeIterator **aIterator); + +protected: + virtual void AddStyleSheetToSet(nsIStyleSheet* aSheet, nsIStyleSet* aSet); // subclass hook + + nsDocument(); + virtual ~nsDocument(); + nsresult Init(); + + nsIArena* mArena; + nsString* mDocumentTitle; + nsIURL* mDocumentURL; + nsCharSetID mCharacterSet; + nsIDocument* mParentDocument; + nsVoidArray mSubDocuments; + nsVoidArray mPresShells; + nsIContent* mRootContent; + nsVoidArray mStyleSheets; + nsVoidArray mObservers; + void* mScriptObject; +}; + +#endif /* nsDocument_h___ */ diff --git a/mozilla/layout/base/src/nsFrame.cpp b/mozilla/layout/base/src/nsFrame.cpp new file mode 100644 index 00000000000..905fad7319d --- /dev/null +++ b/mozilla/layout/base/src/nsFrame.cpp @@ -0,0 +1,585 @@ +/* -*- 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 "nsFrame.h" +#include "nsIContent.h" +#include "nsIAtom.h" +#include "nsString.h" +#include "nsIStyleContext.h" +#include "nsIView.h" +#include "nsIViewManager.h" +#include "nsIPresContext.h" +#include "nsCRT.h" +#include "nsGUIEvent.h" +#include "nsStyleConsts.h" + +static PRBool gShowFrameBorders = PR_FALSE; + +NS_LAYOUT void nsIFrame::ShowFrameBorders(PRBool aEnable) +{ + gShowFrameBorders = aEnable; +} + +NS_LAYOUT PRBool nsIFrame::GetShowFrameBorders() +{ + return gShowFrameBorders; +} + +static NS_DEFINE_IID(kIFrameIID, NS_IFRAME_IID); + +nsresult +nsFrame::NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIFrame* it = new nsFrame(aContent, aIndexInParent, aParent); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aInstancePtrResult = it; + return NS_OK; +} + +void* nsFrame::operator new(size_t size) +{ + void* result = new char[size]; + + nsCRT::zero(result, size); + return result; +} + +nsFrame::nsFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) + : mContent(aContent), mIndexInParent(aIndexInParent), mContentParent(aParent), + mGeometricParent(aParent) +{ + NS_ADDREF(mContent); +} + +nsFrame::~nsFrame() +{ + NS_RELEASE(mContent); + NS_IF_RELEASE(mStyleContext); + if (nsnull != mView) { + // Break association between view and frame + mView->SetFrame(nsnull); + NS_RELEASE(mView); + } +} + +///////////////////////////////////////////////////////////////////////////// +// nsISupports + +nsresult nsFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) +{ + if (NULL == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + static NS_DEFINE_IID(kClassIID, kIFrameIID); + if (aIID.Equals(kClassIID) || (aIID.Equals(kISupportsIID))) { + *aInstancePtr = (void*)this; + return NS_OK; + } + return NS_NOINTERFACE; +} + +nsrefcnt nsFrame::AddRef(void) +{ + NS_ERROR("not supported"); + return 0; +} + +nsrefcnt nsFrame::Release(void) +{ + NS_ERROR("not supported"); + return 0; +} + +///////////////////////////////////////////////////////////////////////////// +// nsIFrame + +void nsFrame::DeleteFrame() +{ + nsIView* view = mView; + if (nsnull == view) { + nsIFrame* parent = GetParentWithView(); + if (nsnull != parent) { + view = parent->GetView(); + } + } + if (nsnull != view) { + nsIViewManager* vm = view->GetViewManager(); + nsIPresContext* cx = vm->GetPresContext(); + //is this a really good ordering for the releases? MMP + NS_RELEASE(vm); + NS_RELEASE(view); + cx->StopLoadImage(this); + NS_RELEASE(cx); + } + + delete this; +} + +nsIContent* nsFrame::GetContent() const +{ + if (nsnull != mContent) { + NS_ADDREF(mContent); + } + return mContent; +} + +PRInt32 nsFrame::GetIndexInParent() const +{ + return mIndexInParent; +} + +void nsFrame::SetIndexInParent(PRInt32 aIndexInParent) +{ + mIndexInParent = aIndexInParent; +} + +nsIStyleContext* nsFrame::GetStyleContext(nsIPresContext* aPresContext) +{ + if (nsnull == mStyleContext) { + mStyleContext = aPresContext->ResolveStyleContextFor(mContent, mGeometricParent); // XXX should be content parent??? + } + NS_IF_ADDREF(mStyleContext); + return mStyleContext; +} + +void nsFrame::SetStyleContext(nsIStyleContext* aContext) +{ + NS_PRECONDITION(nsnull != aContext, "null ptr"); + if (aContext != mStyleContext) { + NS_IF_RELEASE(mStyleContext); + if (nsnull != aContext) { + mStyleContext = aContext; + NS_ADDREF(aContext); + } + } +} + +// Geometric and content parent member functions + +nsIFrame* nsFrame::GetContentParent() const +{ + return mContentParent; +} + +void nsFrame::SetContentParent(const nsIFrame* aParent) +{ + mContentParent = (nsIFrame*)aParent; +} + +nsIFrame* nsFrame::GetGeometricParent() const +{ + return mGeometricParent; +} + +void nsFrame::SetGeometricParent(const nsIFrame* aParent) +{ + mGeometricParent = (nsIFrame*)aParent; +} + +// Bounding rect member functions + +nsRect nsFrame::GetRect() const +{ + return mRect; +} + +void nsFrame::GetRect(nsRect& aRect) const +{ + aRect = mRect; +} + +void nsFrame::GetOrigin(nsPoint& aPoint) const +{ + aPoint.x = mRect.x; + aPoint.y = mRect.y; +} + +nscoord nsFrame::GetWidth() const +{ + return mRect.width; +} + +nscoord nsFrame::GetHeight() const +{ + return mRect.height; +} + +void nsFrame::SetRect(const nsRect& aRect) +{ + MoveTo(aRect.x, aRect.y); + SizeTo(aRect.width, aRect.height); +} + +void nsFrame::MoveTo(nscoord aX, nscoord aY) +{ + if ((aX != mRect.x) || (aY != mRect.y)) { + mRect.x = aX; + mRect.y = aY; + + // Let the view know + if (nsnull != mView) { + mView->SetPosition(aX, aY); + } + } +} + +void nsFrame::SizeTo(nscoord aWidth, nscoord aHeight) +{ + if ((aWidth != mRect.width) || (aHeight != mRect.height)) { + mRect.width = aWidth; + mRect.height = aHeight; + + // Let the view know + if (nsnull != mView) { + mView->SetDimensions(aWidth, aHeight); + } + } +} + +// Child frame enumeration + +PRInt32 nsFrame::ChildCount() const +{ + return 0; +} + +nsIFrame* nsFrame::ChildAt(PRInt32 aIndex) const +{ + NS_ERROR("not a container"); + return nsnull; +} + +PRInt32 nsFrame::IndexOf(const nsIFrame* aChild) const +{ + NS_ERROR("not a container"); + return -1; +} + +nsIFrame* nsFrame::FirstChild() const +{ + return nsnull; +} + +nsIFrame* nsFrame::NextChild(const nsIFrame* aChild) const +{ + NS_ERROR("not a container"); + return nsnull; +} + +nsIFrame* nsFrame::PrevChild(const nsIFrame* aChild) const +{ + NS_ERROR("not a container"); + return nsnull; +} + +nsIFrame* nsFrame::LastChild() const +{ + return nsnull; +} + +void nsFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ +} + +nsEventStatus nsFrame::HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent) +{ + nsEventStatus retval = nsEventStatus_eIgnore; + return retval; +} + +PRInt32 nsFrame::GetCursorAt(nsIPresContext& aPresContext, + const nsPoint& aPoint, + nsIFrame** aFrame) +{ + return NS_STYLE_CURSOR_INHERIT; +} + +// Resize and incremental reflow + +nsIFrame::ReflowStatus +nsFrame::ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ + aDesiredSize.width = 0; + aDesiredSize.height = 0; + aDesiredSize.ascent = 0; + aDesiredSize.descent = 0; + if (nsnull != aMaxElementSize) { + aMaxElementSize->width = 0; + aMaxElementSize->height = 0; + } + return frComplete; +} + +void +nsFrame::JustifyReflow(nsIPresContext* aPresContext, + nscoord aAvailableSpace) +{ +} + +nsIFrame::ReflowStatus +nsFrame::IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand) +{ + NS_ERROR("not a reflow command handler"); + aDesiredSize.width = 0; + aDesiredSize.height = 0; + aDesiredSize.ascent = 0; + aDesiredSize.descent = 0; + return frComplete; +} + +void nsFrame::ContentAppended(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer) +{ +} + +void nsFrame::ContentInserted(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInParent) +{ +} + +void nsFrame::ContentReplaced(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInParent) +{ +} + +void nsFrame::ContentDeleted(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInParent) +{ +} + +void nsFrame::GetReflowMetrics(nsIPresContext* aPresContext, + nsReflowMetrics& aMetrics) +{ + aMetrics.width = mRect.width; + aMetrics.height = mRect.height; + aMetrics.ascent = mRect.height; + aMetrics.descent = 0; +} + +// Flow member functions + +PRBool nsFrame::IsSplittable() const +{ + return PR_FALSE; +} + +nsIFrame* nsFrame::CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent) +{ + NS_ERROR("not splittable"); + return nsnull; +} + +nsIFrame* nsFrame::GetPrevInFlow() const +{ + return nsnull; +} + +void nsFrame::SetPrevInFlow(nsIFrame*) +{ + NS_ERROR("not splittable"); +} + +nsIFrame* nsFrame::GetNextInFlow() const +{ + return nsnull; +} + +void nsFrame::SetNextInFlow(nsIFrame*) +{ + NS_ERROR("not splittable"); +} + +void nsFrame::AppendToFlow(nsIFrame* aAfterFrame) +{ + NS_ERROR("not splittable"); +} + +void nsFrame::PrependToFlow(nsIFrame* aBeforeFrame) +{ + NS_ERROR("not splittable"); +} + +void nsFrame::RemoveFromFlow() +{ + NS_ERROR("not splittable"); +} + +void nsFrame::BreakFromPrevFlow() +{ + NS_ERROR("not splittable"); +} + +void nsFrame::BreakFromNextFlow() +{ + NS_ERROR("not splittable"); +} + +// Associated view object +nsIView* nsFrame::GetView() const +{ + NS_IF_ADDREF(mView); + return mView; +} + +void nsFrame::SetView(nsIView* aView) +{ + NS_IF_RELEASE(mView); + if (nsnull != aView) { + mView = aView; + aView->SetFrame(this); + NS_ADDREF(aView); + } +} + +// Find the first geometric parent that has a view +nsIFrame* nsFrame::GetParentWithView() const +{ + nsIFrame* parent = mGeometricParent; + + while (nsnull != parent) { + nsIView* parView = parent->GetView(); + if (nsnull != parView) { + NS_RELEASE(parView); + break; + } + parent = parent->GetGeometricParent(); + } + + return parent; +} + +// Returns the offset from this frame to the closest geometric parent that +// has a view. Also returns the containing view or null in case of error +nsIView* nsFrame::GetOffsetFromView(nsPoint& aOffset) const +{ + const nsIFrame* frame = this; + nsIView* result = nsnull; + nsPoint origin; + + aOffset.MoveTo(0, 0); + nsIView* view = nsnull; + do { + frame->GetOrigin(origin); + aOffset += origin; + frame = frame->GetGeometricParent(); + view = (frame == nsnull) ? nsnull : frame->GetView(); + } while ((nsnull != frame) && (nsnull == view)); + + return view; +} + +nsIWidget* nsFrame::GetWindow() const +{ + nsIWidget* window = nsnull; + const nsIFrame* frame = this; + while (nsnull != frame) { + nsIView* view = frame->GetView(); + if (nsnull != view) { + window = view->GetWidget(); + NS_RELEASE(view); + if (nsnull != window) { + return window; + } + } + frame = frame->GetParentWithView(); + } + NS_POSTCONDITION(nsnull != window, "no window in frame tree"); + return nsnull; +} + +// Sibling pointer used to link together frames + +nsIFrame* nsFrame::GetNextSibling() const +{ + return mNextSibling; +} + +void nsFrame::SetNextSibling(nsIFrame* aNextSibling) +{ + mNextSibling = aNextSibling; +} + +// Debugging +void nsFrame::List(FILE* out, PRInt32 aIndent) const +{ + // Indent + for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out); + + // Output the tag and rect + ListTag(out); + fputs(" ", out); + out << mRect; + fputs("<>\n", out); +} + +// Output the frame's tag +void nsFrame::ListTag(FILE* out) const +{ + nsIAtom* tag = mContent->GetTag(); + if (tag != nsnull) { + nsAutoString buf; + tag->ToString(buf); + fputs(buf, out); + NS_RELEASE(tag); + } + fprintf(out, "(%d)@%p", mIndexInParent, this); +} + +void nsFrame::VerifyTree() const +{ +} + +nsStyleStruct* nsFrame::GetStyleData(const nsIID& aSID) +{ + NS_ASSERTION(mStyleContext!=nsnull,"null style context"); + if (mStyleContext) + return mStyleContext->GetData(aSID); + return nsnull; +} diff --git a/mozilla/layout/base/src/nsFrame.h b/mozilla/layout/base/src/nsFrame.h new file mode 100644 index 00000000000..f64dfafcb99 --- /dev/null +++ b/mozilla/layout/base/src/nsFrame.h @@ -0,0 +1,190 @@ +/* -*- 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. + */ +#ifndef nsFrame_h___ +#define nsFrame_h___ + +#include "nsIFrame.h" +#include "nsRect.h" + + +// Implementation of a simple frame with no children and that isn't splittable +class nsFrame : public nsIFrame +{ +public: + /** + * Create a new "empty" frame that maps a given piece of content into a + * 0,0 area. + */ + static nsresult NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); + + // Overloaded new operator. Initializes the memory to 0 + void* operator new(size_t size); + + virtual void DeleteFrame(); + + virtual nsIContent* GetContent() const; + virtual PRInt32 GetIndexInParent() const; + virtual void SetIndexInParent(PRInt32 aIndexInParent); + + virtual nsIStyleContext* GetStyleContext(nsIPresContext* aContext); + virtual void SetStyleContext(nsIStyleContext* aContext); + + // Geometric and content parent + virtual nsIFrame* GetContentParent() const; + virtual void SetContentParent(const nsIFrame* aParent); + virtual nsIFrame* GetGeometricParent() const; + virtual void SetGeometricParent(const nsIFrame* aParent); + + // Bounding rect + virtual nsRect GetRect() const; + virtual void GetRect(nsRect& aRect) const; + virtual void GetOrigin(nsPoint& aPoint) const; + virtual nscoord GetWidth() const; + virtual nscoord GetHeight() const; + virtual void SetRect(const nsRect& aRect); + virtual void MoveTo(nscoord aX, nscoord aY); + virtual void SizeTo(nscoord aWidth, nscoord aHeight); + + // Child frame enumeration + virtual PRInt32 ChildCount() const; + virtual nsIFrame* ChildAt(PRInt32 aIndex) const; + virtual PRInt32 IndexOf(const nsIFrame* aChild) const; + virtual nsIFrame* FirstChild() const; + virtual nsIFrame* NextChild(const nsIFrame* aChild) const; + virtual nsIFrame* PrevChild(const nsIFrame* aChild) const; + virtual nsIFrame* LastChild() const; + + virtual void Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + virtual nsEventStatus HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent); + + virtual PRInt32 GetCursorAt(nsIPresContext& aPresContext, + const nsPoint& aPoint, + nsIFrame** aFrame); + + // Resize reflow methods + virtual ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + virtual void JustifyReflow(nsIPresContext* aCX, + nscoord aAvailableSpace); + + // Incremental reflow methods + virtual ReflowStatus IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand); + virtual void ContentAppended(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer); + virtual void ContentInserted(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInParent); + virtual void ContentReplaced(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInParent); + virtual void ContentDeleted(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInParent); + virtual void GetReflowMetrics(nsIPresContext* aPresContext, + nsReflowMetrics& aMetrics); + + // Flow member functions + virtual PRBool IsSplittable() const; + virtual nsIFrame* CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent); + virtual nsIFrame* GetPrevInFlow() const; + virtual void SetPrevInFlow(nsIFrame*); + virtual nsIFrame* GetNextInFlow() const; + virtual void SetNextInFlow(nsIFrame*); + + virtual void AppendToFlow(nsIFrame* aAfterFrame); + virtual void PrependToFlow(nsIFrame* aAfterFrame); + virtual void RemoveFromFlow(); + virtual void BreakFromPrevFlow(); + virtual void BreakFromNextFlow(); + + // Associated view object + virtual nsIView* GetView() const; + virtual void SetView(nsIView* aView); + + // Find the first geometric parent that has a view + virtual nsIFrame* GetParentWithView() const; + + // Returns the offset from this frame to the closest geometric parent that + // has a view. Also returns the containing view, or null in case of error + virtual nsIView* GetOffsetFromView(nsPoint& aOffset) const; + + // Returns the closest geometric parent that has a view which has a + // a window. + virtual nsIWidget* GetWindow() const; + + // Sibling pointer used to link together frames + virtual nsIFrame* GetNextSibling() const; + virtual void SetNextSibling(nsIFrame* aNextSibling); + + // Debugging + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + virtual void ListTag(FILE* out = stdout) const; + virtual void VerifyTree() const; + + // Get the style struct associated with this frame + virtual nsStyleStruct* GetStyleData(const nsIID& aSID); + + +protected: + // Constructor. Takes as arguments the content object, the index in parent, + // and the Frame for the content parent + nsFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + virtual ~nsFrame(); + + nsRect mRect; + nsIContent* mContent; + nsIStyleContext* mStyleContext; + PRInt32 mIndexInParent; + nsIFrame* mContentParent; + nsIFrame* mGeometricParent; + nsIFrame* mNextSibling; // singly linked list of frames + +private: + nsIView* mView; // must use accessor member functions + + NS_IMETHOD_(nsrefcnt) AddRef(void); + NS_IMETHOD_(nsrefcnt) Release(void); +}; + +#endif /* nsFrame_h___ */ diff --git a/mozilla/layout/base/src/nsGalleyContext.cpp b/mozilla/layout/base/src/nsGalleyContext.cpp new file mode 100644 index 00000000000..03f9dd9d309 --- /dev/null +++ b/mozilla/layout/base/src/nsGalleyContext.cpp @@ -0,0 +1,88 @@ +/* -*- 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 "nsPresContext.h" +#include "nsIRenderingContext.h" +#include "nsIView.h" +#include "nsIWidget.h" +#include "nsGfxCIID.h" + +static NS_DEFINE_IID(kIPresContextIID, NS_IPRESCONTEXT_IID); + +class GalleyContext : public nsPresContext { +public: + GalleyContext(); + ~GalleyContext(); + + virtual PRBool IsPaginated(); + virtual nscoord GetPageWidth(); + virtual nscoord GetPageHeight(); +}; + +GalleyContext::GalleyContext() +{ + nsresult res; + + static NS_DEFINE_IID(kDeviceContextCID, NS_DEVICE_CONTEXT_CID); + static NS_DEFINE_IID(kDeviceContextIID, NS_IDEVICE_CONTEXT_IID); + + res = NSRepository::CreateInstance(kDeviceContextCID, nsnull, + kDeviceContextIID, + (void **)&mDeviceContext); + if (NS_OK == res) { + mDeviceContext->Init(); + mDeviceContext->SetDevUnitsToAppUnits(mDeviceContext->GetDevUnitsToTwips()); + mDeviceContext->SetAppUnitsToDevUnits(mDeviceContext->GetTwipsToDevUnits()); + } +} + +GalleyContext::~GalleyContext() +{ + mDeviceContext->FlushFontCache(); + NS_IF_RELEASE(mDeviceContext); +} + +PRBool GalleyContext::IsPaginated() +{ + return PR_FALSE; +} + +nscoord GalleyContext::GetPageWidth() +{ + return 0; +} + +nscoord GalleyContext::GetPageHeight() +{ + return 0; +} + +NS_LAYOUT nsresult +NS_NewGalleyContext(nsIPresContext** aInstancePtrResult) +{ + if (aInstancePtrResult == nsnull) { + return NS_ERROR_NULL_POINTER; + } + + GalleyContext *it = new GalleyContext(); + + if (it == nsnull) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(kIPresContextIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/layout/base/src/nsPresContext.cpp b/mozilla/layout/base/src/nsPresContext.cpp new file mode 100644 index 00000000000..36784d930b1 --- /dev/null +++ b/mozilla/layout/base/src/nsPresContext.cpp @@ -0,0 +1,463 @@ +/* -*- 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 "nsPresContext.h" +#include "nsIPresShell.h" +#include "nsILinkHandler.h" +#include "nsIStyleContext.h" +#include "nsIStyleSet.h" +#include "nsIFontMetrics.h" +#include "nsIImageManager.h" +#include "nsIImageGroup.h" +#include "nsIImageRequest.h" +#include "nsIImageObserver.h" +#include "nsIView.h" +#include "nsIViewManager.h" +#include "nsIFrame.h" +#include "nsIRenderingContext.h" +#include "nsTransform2D.h" +#include "nsIDocument.h" +#include "nsIURL.h" +#include "nsString.h" + +static NS_DEFINE_IID(kIPresContextIID, NS_IPRESCONTEXT_IID); + +// XXX this code needs to move far away from here +static nsIImageManager* gImageManager = nsnull; +static void InitImageLibrary() +{ + // Initialize image library + if (NS_OK == NS_NewImageManager(&gImageManager)) { + if (NS_OK == gImageManager->Init()) { + gImageManager->SetCacheSize(1024*1024); + return; + } + } + printf("can't initialize image library\n"); +} +// XXX end code with no home... + +class ImageLoader : nsIImageRequestObserver { +public: + ImageLoader(nsPresContext* aCX, nsIImageGroup* aGroup, nsIFrame* aFrame); + ~ImageLoader(); + + NS_DECL_ISUPPORTS + + void LoadImage(const nsString& aURL); + + const nsString& GetURL() const { + return mURL; + } + + nsIImage* GetImage() { + return mImage; + } + + PRInt32 FrameCount(); + + PRBool RemoveFrame(nsIFrame* aFrame); + + void AddFrame(nsIFrame* aFrame); + + void UpdateFrames(); + + virtual void Notify(nsIImageRequest *aImageRequest, + nsIImage *aImage, + nsImageNotification aNotificationType, + PRInt32 aParam1, PRInt32 aParam2, + void *aParam3); + + virtual void NotifyError(nsIImageRequest *aImageRequest, + nsImageError aErrorType); + + nsVoidArray mFrames; + nsString mURL; + nsPresContext* mCX; + nsIImage* mImage; + nsIImageRequest* mImageRequest; + nsIImageGroup* mImageGroup; + + PRInt32 mWidth, mHeight; // in pixels +}; + +ImageLoader::ImageLoader(nsPresContext* aCX, nsIImageGroup* aGroup, + nsIFrame* aFrame) +{ + mCX = aCX; + AddFrame(aFrame); + mImage = nsnull; + mImageRequest = nsnull; + mImageGroup = aGroup; NS_ADDREF(aGroup); + mWidth = -1; + mHeight = -1; +} + +ImageLoader::~ImageLoader() +{ + if (nsnull != mImageRequest) { + mImageRequest->Interrupt(); + mImageRequest->RemoveObserver(this); + } +} + +void ImageLoader::LoadImage(const nsString& aURL) +{ + if (nsnull == mImage) { + // Save url + mURL.SetLength(0); + mURL.Append(aURL); + + // Start image load + char* cp = aURL.ToNewCString(); + mImageRequest = mImageGroup->GetImage(cp, this, NS_RGB(255,255,255), + 0, 0, 0); + delete cp; + } +} + +static NS_DEFINE_IID(kIImageRequestObserver, NS_IIMAGEREQUESTOBSERVER_IID); + +NS_IMPL_ISUPPORTS(ImageLoader, kIImageRequestObserver); + +static PRBool gXXXInstalledColorMap; +void ImageLoader::Notify(nsIImageRequest *aImageRequest, + nsIImage *aImage, + nsImageNotification aNotificationType, + PRInt32 aParam1, PRInt32 aParam2, + void *aParam3) +{ + switch (aNotificationType) { + case nsImageNotification_kDimensions: +#ifdef NOISY + printf("Image:%d x %d\n", aParam1, aParam2); +#endif + mWidth = aParam1; + mHeight = aParam2; + break; + + case nsImageNotification_kPixmapUpdate: + case nsImageNotification_kImageComplete: + case nsImageNotification_kFrameComplete: + if ((mImage == nsnull) && (nsnull != aImage)) { + mImage = aImage; + NS_ADDREF(aImage); + } + UpdateFrames(); + } +} + +PRInt32 ImageLoader::FrameCount() +{ + return mFrames.Count(); +} + +PRBool ImageLoader::RemoveFrame(nsIFrame* aFrame) +{ + return mFrames.RemoveElement(aFrame); +} + +void ImageLoader::AddFrame(nsIFrame* aFrame) +{ + PRInt32 i, n = mFrames.Count(); + for (i = 0; i < n; i++) { + nsIFrame* frame = (nsIFrame*) mFrames.ElementAt(i); + if (frame == aFrame) { + return; + } + } + mFrames.AppendElement(aFrame); +} + +void ImageLoader::UpdateFrames() +{ + PRInt32 i, n = mFrames.Count(); + for (i = 0; i < n; i++) { + nsIFrame* frame = (nsIFrame*) mFrames.ElementAt(i); + + // XXX installed colormap should be presentation-context/window state + nsIWidget* window = frame->GetWindow(); + if (!gXXXInstalledColorMap && mImage) { + nsColorMap* cmap = mImage->GetColorMap(); + if ((nsnull != cmap) && (cmap->NumColors > 0)) { + window->SetColorMap(cmap); + } + gXXXInstalledColorMap = PR_TRUE; + } + + // Determine damaged area and tell view manager to redraw it + nsPoint offset; + nsRect bounds; + frame->GetRect(bounds); + nsIView* view = frame->GetOffsetFromView(offset); + nsIViewManager* vm = view->GetViewManager(); + bounds.x = offset.x; + bounds.y = offset.y; + vm->UpdateView(view, &bounds, 0); + NS_RELEASE(vm); + NS_RELEASE(view); + } +} + +void ImageLoader::NotifyError(nsIImageRequest *aImageRequest, + nsImageError aErrorType) +{ + printf("XXX image error: %d\n", aErrorType); +} + +//---------------------------------------------------------------------- + +nsPresContext::nsPresContext() + : mVisibleArea(0, 0, 0, 0), + mDefaultFont("Times", NS_FONT_STYLE_NORMAL, + NS_FONT_VARIANT_NORMAL, + NS_FONT_WEIGHT_NORMAL, + 0, + NS_POINTS_TO_TWIPS_INT(12)) +{ + NS_INIT_REFCNT(); + mShell = nsnull; + mDeviceContext = nsnull; + mImageGroup = nsnull; + mLinkHandler = nsnull; + mContainer = nsnull; +} + +nsPresContext::~nsPresContext() +{ + mShell = nsnull; + + // XXX there is a race between an async notify and this code because + // the presentation shell code deletes the frame tree first and then + // deletes us. We need an "Deactivation" hook for this code too + + // Release all the image loaders + PRInt32 n = mImageLoaders.Count(); + for (PRInt32 i = 0; i < n; i++) { + ImageLoader* loader = (ImageLoader*) mImageLoaders.ElementAt(i); + delete loader; + } + + // XXX Release all the cached images + + if (nsnull != mImageGroup) { + mImageGroup->Interrupt(); + NS_RELEASE(mImageGroup); + } + + NS_IF_RELEASE(mLinkHandler); + NS_IF_RELEASE(mContainer); +} + +nsrefcnt nsPresContext::AddRef(void) +{ + return ++mRefCnt; +} + +nsrefcnt nsPresContext::Release(void) +{ + NS_PRECONDITION(0 != mRefCnt, "bad refcnt"); + if (--mRefCnt == 0) { + delete this; + return 0; + } + return mRefCnt; +} + +NS_IMPL_QUERY_INTERFACE(nsPresContext, kIPresContextIID); + +// Note: We don't hold a reference on the shell; it has a reference to +// us +void nsPresContext::SetShell(nsIPresShell* aShell) +{ + mShell = aShell; +} + +nsIPresShell* nsPresContext::GetShell() +{ + if (nsnull != mShell) { + NS_ADDREF(mShell); + } + return mShell; +} + +nsIStyleContext* +nsPresContext::ResolveStyleContextFor(nsIContent* aContent, + nsIFrame* aParentFrame) +{ + nsIStyleContext* result = nsnull; + + nsIStyleSet* set = mShell->GetStyleSet(); + if (nsnull != set) { + result = set->ResolveStyleFor(this, aContent, aParentFrame); + NS_RELEASE(set); + } + + return result; +} + +nsIFontMetrics* nsPresContext::GetMetricsFor(const nsFont& aFont) +{ + if (nsnull != mDeviceContext) + return mDeviceContext->GetMetricsFor(aFont); + + return nsnull; +} + +const nsFont& nsPresContext::GetDefaultFont(void) +{ + return mDefaultFont; +} + +nsRect nsPresContext::GetVisibleArea() +{ + return mVisibleArea; +} + +void nsPresContext::SetVisibleArea(const nsRect& r) +{ + mVisibleArea = r; +} + +float nsPresContext::GetPixelsToTwips() const +{ + if (nsnull != mDeviceContext) + return mDeviceContext->GetDevUnitsToAppUnits(); + + return 1.0f; +} + +float nsPresContext::GetTwipsToPixels() const +{ + if (nsnull != mDeviceContext) + return mDeviceContext->GetAppUnitsToDevUnits(); + + return 1.0f; +} + +nsIDeviceContext * nsPresContext::GetDeviceContext() const +{ + NS_IF_ADDREF(mDeviceContext); + return mDeviceContext; +} + +nsIImage* nsPresContext::LoadImage(const nsString& aURL, nsIFrame* aForFrame) +{ + if (nsnull == mImageGroup) { + // XXX this is bad; if we allow for subwindows that have different + // rendering context's this won't work + nsIWidget* window = aForFrame->GetWindow(); + nsIRenderingContext* drawCtx = window->GetRenderingContext(); + drawCtx->Scale(mDeviceContext->GetAppUnitsToDevUnits(), + mDeviceContext->GetAppUnitsToDevUnits()); + if ((NS_OK != NS_NewImageGroup(&mImageGroup)) || + (NS_OK != mImageGroup->Init(drawCtx))) { + // XXX what to do? + printf("XXX: can't get image group created\n"); + NS_RELEASE(drawCtx); + return nsnull; + } + NS_RELEASE(drawCtx); + } + + // Get absolute version of the url + nsIDocument* doc = mShell->GetDocument(); + nsIURL* docURL = doc->GetDocumentURL(); + char* spec = aURL.ToNewCString(); + nsIURL* url; + nsresult rv = NS_NewURL(&url, docURL, spec); + delete spec; + NS_RELEASE(docURL); + NS_RELEASE(doc); + if (NS_OK != rv) { + // XXX lost error + return nsnull; + } + nsAutoString absURL; + url->ToString(absURL); + NS_RELEASE(url); + + PRInt32 n = mImageLoaders.Count(); + for (PRInt32 i = 0; i < n; i++) { + ImageLoader* loader = (ImageLoader*) mImageLoaders.ElementAt(i); + if (absURL.Equals(loader->GetURL())) { + loader->AddFrame(aForFrame); + return loader->GetImage(); + } + } + + ImageLoader* loader = new ImageLoader(this, mImageGroup, aForFrame); + mImageLoaders.AppendElement(loader); + + loader->LoadImage(absURL); + return loader->GetImage(); +} + +void nsPresContext::StopLoadImage(nsIFrame* aForFrame) +{ + PRInt32 n = mImageLoaders.Count(); + for (PRInt32 i = 0; i < n;) { + ImageLoader* loader = (ImageLoader*) mImageLoaders.ElementAt(i); + if (loader->RemoveFrame(aForFrame)) { + if (0 == loader->FrameCount()) { + delete loader; + mImageLoaders.RemoveElementAt(i); + n--; + continue; + } + } + i++; + } +} + +NS_IMETHODIMP nsPresContext::SetLinkHandler(nsILinkHandler* aHandler) +{ + NS_IF_RELEASE(mLinkHandler); + mLinkHandler = aHandler; + NS_IF_ADDREF(aHandler); + return NS_OK; +} + +NS_IMETHODIMP nsPresContext::GetLinkHandler(nsILinkHandler** aResult) +{ + NS_PRECONDITION(nsnull != aResult, "null ptr"); + if (nsnull == aResult) { + return NS_ERROR_NULL_POINTER; + } + *aResult = mLinkHandler; + NS_IF_ADDREF(mLinkHandler); + return NS_OK; +} + +NS_IMETHODIMP nsPresContext::SetContainer(nsISupports* aHandler) +{ + NS_IF_RELEASE(mContainer); + mContainer = aHandler; + NS_IF_ADDREF(aHandler); + return NS_OK; +} + +NS_IMETHODIMP nsPresContext::GetContainer(nsISupports** aResult) +{ + NS_PRECONDITION(nsnull != aResult, "null ptr"); + if (nsnull == aResult) { + return NS_ERROR_NULL_POINTER; + } + *aResult = mContainer; + NS_IF_ADDREF(mContainer); + return NS_OK; +} diff --git a/mozilla/layout/base/src/nsPresContext.h b/mozilla/layout/base/src/nsPresContext.h new file mode 100644 index 00000000000..92ca53013a7 --- /dev/null +++ b/mozilla/layout/base/src/nsPresContext.h @@ -0,0 +1,77 @@ +/* -*- 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. + */ +#ifndef nsPresContext_h___ +#define nsPresContext_h___ + +#include "nsIPresContext.h" +#include "nsIDeviceContext.h" +#include "nsVoidArray.h" +#include "nsFont.h" +class nsIImageGroup; + +// Base class for concrete presentation context classes +class nsPresContext : public nsIPresContext { +public: + NS_DECL_ISUPPORTS + + virtual void SetShell(nsIPresShell* aShell); + virtual nsIPresShell* GetShell(); + virtual nsIStyleContext* ResolveStyleContextFor(nsIContent* aContent, + nsIFrame* aParentFrame); + virtual nsIFontMetrics* GetMetricsFor(const nsFont& aFont); + virtual const nsFont& GetDefaultFont(void); + virtual nsIImage* LoadImage(const nsString&, nsIFrame* aForFrame); + virtual void StopLoadImage(nsIFrame* aForFrame); + + NS_IMETHOD SetContainer(nsISupports* aContainer); + + NS_IMETHOD GetContainer(nsISupports** aResult); + + NS_IMETHOD SetLinkHandler(nsILinkHandler* aHander); + + NS_IMETHOD GetLinkHandler(nsILinkHandler** aResult); + + virtual nsRect GetVisibleArea(); + virtual void SetVisibleArea(const nsRect& r); + + virtual float GetPixelsToTwips() const; + virtual float GetTwipsToPixels() const; + + virtual nsIDeviceContext* GetDeviceContext() const; + +protected: + nsPresContext(); + virtual ~nsPresContext(); + + nsIPresShell* mShell; + nsRect mVisibleArea; + nsIDeviceContext* mDeviceContext; + nsIImageGroup* mImageGroup; + nsILinkHandler* mLinkHandler; + nsISupports* mContainer; + nsFont mDefaultFont; + + nsVoidArray mImageLoaders;/* XXX temporary */ + +private: + // Not supported and not implemented + nsPresContext(const nsPresContext&); + nsPresContext& operator=(const nsPresContext&); +}; + +#endif /* nsPresContext_h___ */ diff --git a/mozilla/layout/base/src/nsPresShell.cpp b/mozilla/layout/base/src/nsPresShell.cpp new file mode 100644 index 00000000000..947d4d0a0a5 --- /dev/null +++ b/mozilla/layout/base/src/nsPresShell.cpp @@ -0,0 +1,597 @@ +/* -*- 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 "nsIPresShell.h" +#include "nsIPresContext.h" +#include "nsIContent.h" +#include "nsIContentDelegate.h" +#include "nsIDocument.h" +#include "nsIStyleSet.h" +#include "nsIStyleContext.h" +#include "nsIFrame.h" +#include "nsReflowCommand.h" +#include "nsIViewManager.h" +#include "nsIView.h" +#include "nsCRT.h" +#include "plhash.h" + +#undef NOISY + +static PLHashNumber HashKey(nsIFrame* key) +{ + return (PLHashNumber) key; +} + +static PRIntn CompareKeys(nsIFrame* key1, nsIFrame* key2) +{ + return key1 == key2; +} + +class FrameHashTable { +public: + FrameHashTable(); + ~FrameHashTable(); + + void* Get(nsIFrame* aKey); + void* Put(nsIFrame* aKey, void* aValue); + void* Remove(nsIFrame* aKey); + +protected: + PLHashTable* mTable; +}; + +FrameHashTable::FrameHashTable() +{ + mTable = PL_NewHashTable(8, (PLHashFunction) HashKey, + (PLHashComparator) CompareKeys, + (PLHashComparator) nsnull, + nsnull, nsnull); +} + +FrameHashTable::~FrameHashTable() +{ + // XXX if debugging then we should assert that the table is empty + PL_HashTableDestroy(mTable); +} + +/** + * Get the data associated with a frame. + */ +void* FrameHashTable::Get(nsIFrame* aKey) +{ + PRInt32 hashCode = (PRInt32) aKey; + PLHashEntry** hep = PL_HashTableRawLookup(mTable, hashCode, aKey); + PLHashEntry* he = *hep; + if (nsnull != he) { + return he->value; + } + return nsnull; +} + +/** + * Create an association between a frame and some data. This call + * returns an old association if there was one (or nsnull if there + * wasn't). + */ +void* FrameHashTable::Put(nsIFrame* aKey, void* aData) +{ + PRInt32 hashCode = (PRInt32) aKey; + PLHashEntry** hep = PL_HashTableRawLookup(mTable, hashCode, aKey); + PLHashEntry* he = *hep; + if (nsnull != he) { + void* oldValue = he->value; + he->value = aData; + return oldValue; + } + PL_HashTableRawAdd(mTable, hep, hashCode, aKey, aData); + return nsnull; +} + +/** + * Remove an association between a frame and it's data. This returns + * the old associated data. + */ +void* FrameHashTable::Remove(nsIFrame* aKey) +{ + PRInt32 hashCode = (PRInt32) aKey; + PLHashEntry** hep = PL_HashTableRawLookup(mTable, hashCode, aKey); + PLHashEntry* he = *hep; + void* oldValue = nsnull; + if (nsnull != he) { + oldValue = he->value; + PL_HashTableRawRemove(mTable, hep, he); + } + return oldValue; +} + +//---------------------------------------------------------------------- + +static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); +static NS_DEFINE_IID(kIPresShellIID, NS_IPRESSHELL_IID); +static NS_DEFINE_IID(kIDocumentObserverIID, NS_IDOCUMENTOBSERVER_IID); + +class PresShell : public nsIPresShell { +public: + PresShell(); + + void* operator new(size_t sz) { + void* rv = new char[sz]; + nsCRT::zero(rv, sz); + return rv; + } + + // nsISupports + NS_DECL_ISUPPORTS + + // nsIDocumentObserver + NS_IMETHOD SetTitle(const nsString& aTitle); + virtual void BeginUpdate(); + virtual void EndUpdate(); + virtual void ContentChanged(nsIContent* aContent, + nsISubContent* aSubContent, + PRInt32 aChangeType); + virtual void ContentAppended(nsIContent* aContainer); + virtual void ContentInserted(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer); + virtual void ContentReplaced(nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer); + virtual void ContentWillBeRemoved(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer); + virtual void ContentHasBeenRemoved(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer); + virtual void StyleSheetAdded(nsIStyleSheet* aStyleSheet); + + // nsIPresShell + virtual nsresult Init(nsIDocument* aDocument, + nsIPresContext* aPresContext, + nsIViewManager* aViewManager, + nsIStyleSet* aStyleSet); + virtual nsIDocument* GetDocument(); + virtual nsIPresContext* GetPresContext(); + virtual nsIViewManager* GetViewManager(); + virtual nsIStyleSet* GetStyleSet(); + virtual void BeginObservingDocument(); + virtual void EndObservingDocument(); + virtual void ResizeReflow(nscoord aWidth, nscoord aHeight); + virtual nsIFrame* GetRootFrame(); + virtual nsIFrame* FindFrameWithContent(nsIContent* aContent); + virtual void AppendReflowCommand(nsReflowCommand* aReflowCommand); + virtual void ProcessReflowCommands(); + virtual void PutCachedData(nsIFrame* aKeyFrame, void* aData); + virtual void* GetCachedData(nsIFrame* aKeyFrame); + virtual void* RemoveCachedData(nsIFrame* aKeyFrame); + +protected: + ~PresShell(); + + FrameHashTable* mCache; + nsIDocument* mDocument; + nsIPresContext* mPresContext; + nsIStyleSet* mStyleSet; + nsIFrame* mRootFrame; + nsIViewManager* mViewManager; + PRUint32 mUpdateCount; + nsVoidArray mReflowCommands; +}; + +//---------------------------------------------------------------------- + +PresShell::PresShell() +{ +} + +nsrefcnt PresShell::AddRef(void) +{ + return ++mRefCnt; +} + +nsrefcnt PresShell::Release(void) +{ + NS_PRECONDITION(0 != mRefCnt, "bad refcnt"); + if (--mRefCnt == 0) { + delete this; + return 0; + } + return mRefCnt; +} + +nsresult PresShell::QueryInterface(const nsIID& aIID, void** aInstancePtr) +{ + if (aIID.Equals(kIPresShellIID)) { + *aInstancePtr = (void*) ((nsIPresShell*) this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIDocumentObserverIID)) { + *aInstancePtr = (void*) ((nsIDocumentObserver*) this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kISupportsIID)) { + *aInstancePtr = (void*) ((nsISupports*) ((nsIPresShell*)this)); + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +PresShell::~PresShell() +{ + delete mCache; + + if (nsnull != mDocument) { + mDocument->DeleteShell(this); + NS_RELEASE(mDocument); + } + if (nsnull != mRootFrame) { + mRootFrame->DeleteFrame(); + } + NS_IF_RELEASE(mPresContext); + NS_IF_RELEASE(mViewManager); + NS_IF_RELEASE(mStyleSet); +} + +/** + * Initialize the presentation shell. Create view manager and style + * manager. + */ +nsresult PresShell::Init(nsIDocument* aDocument, + nsIPresContext* aPresContext, + nsIViewManager* aViewManager, + nsIStyleSet* aStyleSet) +{ + NS_PRECONDITION(nsnull != aDocument, "null ptr"); + NS_PRECONDITION(nsnull != aPresContext, "null ptr"); + NS_PRECONDITION(nsnull != aViewManager, "null ptr"); + if ((nsnull == aDocument) || (nsnull == aPresContext) || + (nsnull == aViewManager)) { + return NS_ERROR_NULL_POINTER; + } + if (nsnull != mDocument) { + return NS_ERROR_ALREADY_INITIALIZED; + } + + mCache = new FrameHashTable(); + + mDocument = aDocument; + NS_ADDREF(aDocument); + mViewManager = aViewManager; + NS_ADDREF(mViewManager); + + // Bind the context to the presentation shell. + mPresContext = aPresContext; + NS_ADDREF(aPresContext); + aPresContext->SetShell(this); + + mStyleSet = aStyleSet; + NS_ADDREF(aStyleSet); + + return NS_OK; +} + +nsIDocument* PresShell::GetDocument() +{ + NS_IF_ADDREF(mDocument); + return mDocument; +} + +nsIPresContext* PresShell::GetPresContext() +{ + NS_IF_ADDREF(mPresContext); + return mPresContext; +} + +nsIViewManager* PresShell::GetViewManager() +{ + NS_IF_ADDREF(mViewManager); + return mViewManager; +} + +nsIStyleSet* PresShell::GetStyleSet() +{ + NS_IF_ADDREF(mStyleSet); + return mStyleSet; +} + +// Make shell be a document observer +void PresShell::BeginObservingDocument() +{ + if (nsnull != mDocument) { + mDocument->AddObserver(this); + } +} + +// Make shell stop being a document observer +void PresShell::EndObservingDocument() +{ + if (nsnull != mDocument) { + mDocument->RemoveObserver(this); + } +} + +void PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight) +{ + if (nsnull != mPresContext) { + nsRect r(0, 0, aWidth, aHeight); + mPresContext->SetVisibleArea(r); + } + + if (nsnull == mRootFrame) { + if (nsnull != mDocument) { + nsIContent* root = mDocument->GetRootContent(); + if (nsnull != root) { + nsIContentDelegate* cd = root->GetDelegate(mPresContext); + if (nsnull != cd) { + mRootFrame = cd->CreateFrame(mPresContext, root, -1, nsnull); + NS_RELEASE(cd); + + // set root frame's style context + nsIStyleContext* rootContext = mPresContext->ResolveStyleContextFor(root, nsnull); + mRootFrame->SetStyleContext(rootContext); + NS_RELEASE(rootContext); + + // Bind root frame to root view (and root window) + nsIView* rootView = mViewManager->GetRootView(); + mRootFrame->SetView(rootView); + NS_RELEASE(rootView); + } + NS_RELEASE(root); + } + } + } + + if (nsnull != mRootFrame) { + nsRect bounds = mPresContext->GetVisibleArea(); + nsReflowMetrics desiredSize; + nsSize maxSize(bounds.width, bounds.height); + + // Kick off a top-down reflow +#ifdef NS_DEBUG + mRootFrame->VerifyTree(); +#endif + mRootFrame->ResizeReflow(mPresContext, desiredSize, maxSize, nsnull); + mRootFrame->SizeTo(desiredSize.width, desiredSize.height); +#ifdef NS_DEBUG + mRootFrame->VerifyTree(); +#endif +#ifdef NOISY + mRootFrame->List(); +#endif + + //force a redraw of the entire view + +#if 0 + nsIView *view = mRootFrame->GetView(); + + if (nsnull != view) { + nsRect rect = mRootFrame->GetRect(); + nsIViewManager* vm = view->GetViewManager(); + vm->UpdateView(view, &rect, NS_VMREFRESH_DOUBLE_BUFFER); + NS_RELEASE(vm); + NS_RELEASE(view); + } +#endif + // XXX if debugging then we should assert that the cache is empty + } else { +#ifdef NOISY + printf("PresShell::ResizeReflow: null root frame\n"); +#endif + } +} + +nsIFrame* PresShell::GetRootFrame() +{ + return mRootFrame; +} + +NS_IMETHODIMP PresShell::SetTitle(const nsString& aTitle) +{ + if (nsnull != mPresContext) { + nsISupports* container; + if (NS_OK == mPresContext->GetContainer(&container)) { + if (nsnull != container) { + nsIDocumentObserver* docob; + if (NS_OK == container->QueryInterface(kIDocumentObserverIID, + (void**) &docob)) { + docob->SetTitle(aTitle); + NS_RELEASE(docob); + } + NS_RELEASE(container); + } + } + } + return NS_OK; +} + +void PresShell::BeginUpdate() +{ + mUpdateCount++; +} + +void PresShell::EndUpdate() +{ + NS_PRECONDITION(0 != mUpdateCount, "too many EndUpdate's"); + if (--mUpdateCount == 0) { + // XXX do something here + } +} + +void PresShell::AppendReflowCommand(nsReflowCommand* aReflowCommand) +{ + mReflowCommands.AppendElement(aReflowCommand); +} + +void PresShell::ProcessReflowCommands() +{ + if (0 != mReflowCommands.Count()) { + nsReflowMetrics desiredSize; + + while (0 != mReflowCommands.Count()) { + nsReflowCommand* rc = (nsReflowCommand*) mReflowCommands.ElementAt(0); + mReflowCommands.RemoveElementAt(0); + + // Dispatch the reflow command + nsSize maxSize(mRootFrame->GetWidth(), mRootFrame->GetHeight()); + rc->Dispatch(desiredSize, maxSize); + delete rc; + } + + // Place and size the root frame + mRootFrame->SizeTo(desiredSize.width, desiredSize.height); +#ifdef NS_DEBUG + mRootFrame->VerifyTree(); +#endif + } +} + +void PresShell::ContentChanged(nsIContent* aContent, + nsISubContent* aSubContent, + PRInt32 aChangeType) +{ +} + +void PresShell::ContentAppended(nsIContent* aContainer) +{ + NS_PRECONDITION(nsnull != mRootFrame, "null root frame"); + nsReflowCommand* rc = new nsReflowCommand(mPresContext, + FindFrameWithContent(aContainer), + nsReflowCommand::ContentAppended, + aContainer); + AppendReflowCommand(rc); + ProcessReflowCommands(); +} + +void PresShell::ContentInserted(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) +{ + NS_PRECONDITION(nsnull != mRootFrame, "null root frame"); + nsReflowCommand* rc = new nsReflowCommand(mPresContext, + FindFrameWithContent(aContainer), + nsReflowCommand::ContentInserted, + aContainer, aChild, + aIndexInContainer); + AppendReflowCommand(rc); + ProcessReflowCommands(); +} + +void PresShell::ContentReplaced(nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer) +{ + NS_PRECONDITION(nsnull != mRootFrame, "null root frame"); + nsReflowCommand* rc = new nsReflowCommand(mPresContext, + FindFrameWithContent(aContainer), + nsReflowCommand::ContentReplaced, + aContainer, aOldChild, aNewChild, + aIndexInContainer); + AppendReflowCommand(rc); + ProcessReflowCommands(); +} + +// XXX keep this? +void PresShell::ContentWillBeRemoved(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) +{ +} + +void PresShell::ContentHasBeenRemoved(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) +{ + NS_PRECONDITION(nsnull != mRootFrame, "null root frame"); + nsReflowCommand* rc = new nsReflowCommand(mPresContext, + FindFrameWithContent(aContainer), + nsReflowCommand::ContentDeleted, + aContainer, aChild, + aIndexInContainer); + AppendReflowCommand(rc); + ProcessReflowCommands(); +} + +void PresShell::StyleSheetAdded(nsIStyleSheet* aStyleSheet) +{ +} + +static nsIFrame* FindFrameWithContent(nsIFrame* aFrame, nsIContent* aContent) +{ + nsIContent* frameContent = aFrame->GetContent(); + if (frameContent == aContent) { + NS_RELEASE(frameContent); + return aFrame; + } + NS_RELEASE(frameContent); + + aFrame = aFrame->FirstChild(); + while (aFrame) { + nsIFrame* result = FindFrameWithContent(aFrame, aContent); + + if (result) { + return result; + } + + aFrame = aFrame->GetNextSibling(); + } + + return nsnull; +} + +nsIFrame* PresShell::FindFrameWithContent(nsIContent* aContent) +{ + // For the time being do a brute force depth-first search of + // the frame tree + return ::FindFrameWithContent(mRootFrame, aContent); +} + +void PresShell::PutCachedData(nsIFrame* aKeyFrame, void* aData) +{ + void* oldData = mCache->Put(aKeyFrame, aData); + NS_ASSERTION(nsnull == oldData, "bad cached data usage"); +} + +void* PresShell::GetCachedData(nsIFrame* aKeyFrame) +{ + return mCache->Get(aKeyFrame); +} + +void* PresShell::RemoveCachedData(nsIFrame* aKeyFrame) +{ + return mCache->Remove(aKeyFrame); +} + +//---------------------------------------------------------------------- + +NS_LAYOUT nsresult +NS_NewPresShell(nsIPresShell** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + PresShell* it = new PresShell(); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIPresShellIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/layout/base/src/nsPrintPreviewContext.cpp b/mozilla/layout/base/src/nsPrintPreviewContext.cpp new file mode 100644 index 00000000000..f0de71f8815 --- /dev/null +++ b/mozilla/layout/base/src/nsPrintPreviewContext.cpp @@ -0,0 +1,102 @@ +/* -*- 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 "nsPresContext.h" +#include "nsIDeviceContext.h" +#include "nsUnitConversion.h" +#include "nsIView.h" +#include "nsIWidget.h" +#include "nsGfxCIID.h" + +static NS_DEFINE_IID(kIPresContextIID, NS_IPRESCONTEXT_IID); + +class PrintPreviewContext : public nsPresContext { +public: + PrintPreviewContext(); + ~PrintPreviewContext(); + + virtual PRBool IsPaginated(); + virtual nscoord GetPageWidth(); + virtual nscoord GetPageHeight(); +}; + +PrintPreviewContext::PrintPreviewContext() +{ + nsresult res; + + static NS_DEFINE_IID(kDeviceContextCID, NS_DEVICE_CONTEXT_CID); + static NS_DEFINE_IID(kDeviceContextIID, NS_IDEVICE_CONTEXT_IID); + + res = NSRepository::CreateInstance(kDeviceContextCID, nsnull, kDeviceContextIID, (void **)&mDeviceContext); + + if (NS_OK == res) + { + mDeviceContext->Init(); + + mDeviceContext->SetDevUnitsToAppUnits(mDeviceContext->GetDevUnitsToTwips()); + mDeviceContext->SetAppUnitsToDevUnits(mDeviceContext->GetTwipsToDevUnits()); + + NS_ADDREF(mDeviceContext); + } +} + +PrintPreviewContext::~PrintPreviewContext() +{ + NS_IF_RELEASE(mDeviceContext); +} + +PRBool PrintPreviewContext::IsPaginated() +{ + return PR_TRUE; +} + +// XXX assumes a 1/2 margin around all sides +nscoord PrintPreviewContext::GetPageWidth() +{ +#if 0 + return (nscoord) NS_INCHES_TO_TWIPS(7.5); +#else + // For testing purposes make the page width 95% of the visible area + return mVisibleArea.width * 95 / 100; +#endif +} + +nscoord PrintPreviewContext::GetPageHeight() +{ +#if 0 + return (nscoord) NS_INCHES_TO_TWIPS(10); +#else + // For testing purposes make the page height 60% of the visible area + return mVisibleArea.height * 60 / 100; +#endif +} + +NS_LAYOUT nsresult +NS_NewPrintPreviewContext(nsIPresContext** aInstancePtrResult) +{ + if (aInstancePtrResult == nsnull) { + return NS_ERROR_NULL_POINTER; + } + + PrintPreviewContext *it = new PrintPreviewContext(); + + if (it == nsnull) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(kIPresContextIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/layout/base/src/nsReflowCommand.cpp b/mozilla/layout/base/src/nsReflowCommand.cpp new file mode 100644 index 00000000000..e27420e6bb8 --- /dev/null +++ b/mozilla/layout/base/src/nsReflowCommand.cpp @@ -0,0 +1,238 @@ +/* -*- 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 "nsReflowCommand.h" +#include "nsIPresContext.h" +#include "nsIPresShell.h" +#include "nsIContent.h" +#include "nsIRunaround.h" + +static NS_DEFINE_IID(kIRunaroundIID, NS_IRUNAROUND_IID); + +// Construct a reflow command given a presentation context, target frame, +// and a reflow command type +nsReflowCommand::nsReflowCommand(nsIPresContext* aPresContext, + nsIFrame* aTargetFrame, + ReflowType aReflowType, + PRInt32 aIndex) + : mType(aReflowType), mTargetFrame(aTargetFrame), mPresContext(aPresContext), + mIndex(aIndex), + mContainer(nsnull), + mChild(nsnull), + mOldChild(nsnull) +{ + NS_PRECONDITION(mTargetFrame != nsnull, "null target frame"); + aPresContext->AddRef(); +} + +nsReflowCommand::nsReflowCommand(nsIPresContext* aPresContext, + nsIFrame* aTargetFrame, + ReflowType aReflowType, + nsIContent* aContainer) + : mType(aReflowType), mTargetFrame(aTargetFrame), mPresContext(aPresContext), + mIndex(-1), + mContainer(aContainer), + mChild(nsnull), + mOldChild(nsnull) +{ + NS_PRECONDITION(mTargetFrame != nsnull, "null target frame"); + NS_PRECONDITION(mContainer != nsnull, "null container"); + NS_ADDREF(aPresContext); + NS_ADDREF(aContainer); +} + +nsReflowCommand::nsReflowCommand(nsIPresContext* aPresContext, + nsIFrame* aTargetFrame, + ReflowType aReflowType, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInParent) + : mType(aReflowType), mTargetFrame(aTargetFrame), mPresContext(aPresContext), + mIndex(aIndexInParent), + mContainer(aContainer), + mChild(aChild), + mOldChild(nsnull) +{ + NS_PRECONDITION(mTargetFrame != nsnull, "null target frame"); + NS_PRECONDITION(mContainer != nsnull, "null container"); + NS_PRECONDITION(mChild != nsnull, "null child"); + NS_ADDREF(aPresContext); + NS_ADDREF(aContainer); + NS_ADDREF(aChild); +} + +nsReflowCommand::nsReflowCommand(nsIPresContext* aPresContext, + nsIFrame* aTargetFrame, + ReflowType aReflowType, + nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInParent) + : mType(aReflowType), mTargetFrame(aTargetFrame), mPresContext(aPresContext), + mIndex(aIndexInParent), + mContainer(aContainer), + mChild(aNewChild), + mOldChild(aOldChild) +{ + NS_PRECONDITION(mTargetFrame != nsnull, "null target frame"); + NS_PRECONDITION(mContainer != nsnull, "null container"); + NS_PRECONDITION(mChild != nsnull, "null new child"); + NS_PRECONDITION(mOldChild != nsnull, "null old child"); + NS_ADDREF(aPresContext); + NS_ADDREF(aContainer); + NS_ADDREF(aNewChild); + NS_ADDREF(aOldChild); +} + +nsReflowCommand::~nsReflowCommand() +{ + NS_IF_RELEASE(mPresContext); + NS_IF_RELEASE(mContainer); + NS_IF_RELEASE(mChild); + NS_IF_RELEASE(mOldChild); +} + +void nsReflowCommand::Dispatch(nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize) +{ + // Special handling for content tree change commands + nsIPresShell* shell; + switch (mType) { + case nsReflowCommand::ContentAppended: + shell = mPresContext->GetShell(); + mTargetFrame->ContentAppended(shell, mPresContext, mContainer); + NS_RELEASE(shell); + return; + + case nsReflowCommand::ContentInserted: + shell = mPresContext->GetShell(); + mTargetFrame->ContentInserted(shell, mPresContext, mContainer, + mChild, mIndex); + NS_RELEASE(shell); + return; + + case nsReflowCommand::ContentReplaced: + shell = mPresContext->GetShell(); + mTargetFrame->ContentReplaced(shell, mPresContext, mContainer, + mOldChild, mChild, mIndex); + NS_RELEASE(shell); + return; + + case nsReflowCommand::ContentDeleted: + shell = mPresContext->GetShell(); + mTargetFrame->ContentDeleted(shell, mPresContext, mContainer, + mChild, mIndex); + NS_RELEASE(shell); + return; + } + + // Build the path from the target frame (index 0) to the root frame + mPath.Clear(); + for (nsIFrame* f = (nsIFrame*)mTargetFrame; nsnull != f; + f = f->GetGeometricParent()) { + mPath.AppendElement((void*)f); + } + + // Send an incremental reflow notification to the root frame + nsIFrame* root = (nsIFrame*)mPath[mPath.Count() - 1]; + +#ifdef NS_DEBUG + shell = mPresContext->GetShell(); + if (nsnull != shell) { + NS_ASSERTION(shell->GetRootFrame() == root, "bad root frame"); + NS_RELEASE(shell); + } +#endif + + if (nsnull != root) { + mPath.RemoveElementAt(mPath.Count() - 1); + root->IncrementalReflow(mPresContext, aDesiredSize, aMaxSize, *this); + } +} + +// Pass the reflow command to the next frame in the hierarchy +nsIFrame::ReflowStatus nsReflowCommand::Next(nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsIFrame*& aNextFrame) +{ + PRInt32 count = mPath.Count(); + nsIFrame::ReflowStatus result = nsIFrame::frComplete; + + NS_ASSERTION(count > 0, "empty path vector"); + if (count > 0) { + aNextFrame = (nsIFrame*)mPath[count - 1]; + + NS_ASSERTION(nsnull != aNextFrame, "null frame"); + mPath.RemoveElementAt(count - 1); + result = aNextFrame->IncrementalReflow(mPresContext, aDesiredSize, aMaxSize, + *this); + } else { + aNextFrame = nsnull; + } + + return result; +} + +// Pass the reflow command to the next frame in the hierarchy. Check +// whether it wants to use nsIRunaround or nsIFrame +nsIFrame::ReflowStatus nsReflowCommand::Next(nsISpaceManager* aSpaceManager, + nsRect& aDesiredRect, + const nsSize& aMaxSize, + nsIFrame*& aNextFrame) +{ + PRInt32 count = mPath.Count(); + nsIFrame::ReflowStatus result = nsIFrame::frComplete; + + NS_ASSERTION(count > 0, "empty path vector"); + if (count > 0) { + aNextFrame = (nsIFrame*)mPath[count - 1]; + + NS_ASSERTION(nsnull != aNextFrame, "null frame"); + mPath.RemoveElementAt(count - 1); + + // Does the frame support nsIRunaround? + nsIRunaround* reflowRunaround; + + if (NS_OK == aNextFrame->QueryInterface(kIRunaroundIID, (void**)&reflowRunaround)) { + reflowRunaround->IncrementalReflow(mPresContext, aSpaceManager, aMaxSize, + aDesiredRect, *this); + } else { + nsReflowMetrics desiredSize; + + result = aNextFrame->IncrementalReflow(mPresContext, desiredSize, aMaxSize, + *this); + aDesiredRect.x = 0; + aDesiredRect.y = 0; + aDesiredRect.width = desiredSize.width; + aDesiredRect.height = desiredSize.height; + } + } else { + aNextFrame = nsnull; + } + + return result; +} + +nsIFrame* nsReflowCommand::GetNext() const +{ + PRInt32 count = mPath.Count(); + nsIFrame* rv = nsnull; + if (count > 0) { + rv = (nsIFrame*) mPath[count - 1]; + } + return nsnull; +} diff --git a/mozilla/layout/base/src/nsReflowCommand.h b/mozilla/layout/base/src/nsReflowCommand.h new file mode 100644 index 00000000000..84deb9c47b4 --- /dev/null +++ b/mozilla/layout/base/src/nsReflowCommand.h @@ -0,0 +1,146 @@ +/* -*- 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. + */ +#ifndef nsReflowCommand_h___ +#define nsReflowCommand_h___ + +#include "nsIFrame.h" +#include "nsVoidArray.h" + +class nsIPresContext; +class nsISpaceManager; + +// A reflow command. +class nsReflowCommand { +public: + enum ReflowType { + // These reflow types are used for pre-processing a content + // append, insert or delete. The target frame is responsible for + // creating frames for the new children (or removing frames for + // delete) and then updating it's children's index-in-parent + // values. After that, the frame is responsible for creating new + // reflow commands to deal with the appended, inserted or deleted + // frames. + ContentAppended, + ContentInserted, + ContentReplaced, + ContentDeleted, + + // These are the reflow commands generated after the previous + // commands have completed. + FrameAppended, + FrameInserted, + FrameDeleted, + + // This reflow command is used when a leaf node's content changes + // (e.g. some text in a text run, an image's source, etc.) + ContentChanged, + + // When an incremental reflow operation affects a next-in-flow, + // these commands are used to get the next-in-flow to update + // itself. + PullupReflow, + PushReflow, + + // This command is used to see if a prev-in-flow wants to pullup + // some children from a next-in-flow that has changed because of + // an incremental reflow. + CheckPullupReflow, + + // Trap door for extensions + UserDefined + }; + + // XXX factory methods? + + nsReflowCommand(nsIPresContext* aPresContext, + nsIFrame* aTargetFrame, + ReflowType aReflowType); + + nsReflowCommand(nsIPresContext* aPresContext, + nsIFrame* aTargetFrame, + ReflowType aReflowType, + PRInt32 aIndexValue); + + nsReflowCommand(nsIPresContext* aPresContext, + nsIFrame* aTargetFrame, + ReflowType aReflowType, + nsIContent* aContainer); + + nsReflowCommand(nsIPresContext* aPresContext, + nsIFrame* aTargetFrame, + ReflowType aReflowType, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInParent); + + nsReflowCommand(nsIPresContext* aPresContext, + nsIFrame* aTargetFrame, + ReflowType aReflowType, + nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInParent); + + virtual ~nsReflowCommand(); + + /** + * Dispatch the reflow command. The command is processed and dispatched + * to the appropriate frame's appropriate method. + */ + void Dispatch(nsReflowMetrics& aDesiredSize, const nsSize& aMaxSize); + + // Pass the reflow command to the next frame in the hierarchy. Returns the + // status and the next frame to which the command was dispatched + nsIFrame::ReflowStatus Next(nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsIFrame*& aNextFrame); + + // Pass the reflow command to the next frame in the hierarchy. Returns the + // status and the next frame to which the command was dispatched + // + // Use this version if you have a space manager. This function will check if + // the caller supports nsIRunaround and call either the nsIFrame or the + // nsIRunaround IncrementalReflow() function + nsIFrame::ReflowStatus Next(nsISpaceManager* aSpaceManager, + nsRect& aDesiredRect, + const nsSize& aMaxSize, + nsIFrame*& aNextFrame); + + nsIFrame* GetNext() const; + + // Get the target of the reflow command + nsIFrame* GetTarget() const { return mTargetFrame; } + + // Get the type of reflow command + ReflowType GetType() const { return mType; } + + // Get the index value + PRInt32 GetIndex() const { return mIndex; } + +private: + nsIPresContext* mPresContext; + ReflowType mType; + nsIContent* mContainer; + nsIContent* mChild; + nsIContent* mOldChild; + PRInt32 mIndex; + nsIFrame* mTargetFrame; + nsVoidArray mPath; +}; + +#endif /* nsReflowCommand_h___ */ diff --git a/mozilla/layout/base/src/nsSpaceManager.cpp b/mozilla/layout/base/src/nsSpaceManager.cpp new file mode 100644 index 00000000000..fc937046036 --- /dev/null +++ b/mozilla/layout/base/src/nsSpaceManager.cpp @@ -0,0 +1,549 @@ +/* -*- 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 "nsSpaceManager.h" +#include "nsPoint.h" +#include "nsRect.h" +#include "nsSize.h" +#include + +static NS_DEFINE_IID(kISpaceManagerIID, NS_ISPACEMANAGER_IID); + +///////////////////////////////////////////////////////////////////////////// +// nsSpaceManager + +SpaceManager::SpaceManager(nsIFrame* aFrame) + : mFrame(aFrame) +{ + NS_INIT_REFCNT(); + mX = mY = 0; +} + +NS_IMPL_ISUPPORTS(SpaceManager, kISpaceManagerIID); + +nsIFrame* SpaceManager::GetFrame() const +{ + return mFrame; +} + +void SpaceManager::Translate(nscoord aDx, nscoord aDy) +{ + mX += aDx; + mY += aDy; +} + +void SpaceManager::GetTranslation(nscoord& aX, nscoord& aY) const +{ + aX = mX; + aY = mY; +} + +nscoord SpaceManager::YMost() const +{ + if (mRectArray.mCount > 0) { + return mRectArray.YMost(); + } else { + return 0; + } +} + +/** + * Internal function that returns the available space within the band + * + * @param aBand the first rect in the band + * @param aIndex aBand's index in the rect array + * @param aY the y-offset in world coordinates + * @param aMaxSize the size to use to constrain the band data + * @param aAvailableBand + */ +PRInt32 SpaceManager::GetBandAvailableSpace(const nsRect* aBand, + PRInt32 aIndex, + nscoord aY, + const nsSize& aMaxSize, + nsBandData& aAvailableSpace) const +{ + PRInt32 numRects = LengthOfBand(aBand, aIndex); + nscoord localY = aY - mY; + nscoord height = PR_MIN(aBand->YMost() - aY, aMaxSize.height); + nsRect* rect = aAvailableSpace.rects; + nscoord rightEdge = mX + aMaxSize.width; + + // Initialize the band data + aAvailableSpace.count = 0; + rect->x = mX; + + // Skip any rectangles that are to the left of the local coordinate space + while (numRects > 0) { + if (aBand->XMost() >= mX) { + break; + } + + // Get the next rect in the band + aBand++; + numRects--; + } + + // Process all the remaining rectangles that are within the clip width + while ((numRects > 0) && (aBand->x < rightEdge)) { + if (aBand->x > rect->x) { + // We found some available space + rect->width = aBand->x - rect->x; + rect->x -= mX; // convert from world to local coordinates + rect->y = localY; + rect->height = height; + + // Move to the next output rect + rect++; + aAvailableSpace.count++; + } + + rect->x = aBand->XMost(); + + // Move to the next rect in the band + numRects--; + aBand++; + } + + // No more rects left in the band. If we haven't yet reached the right edge + // then all the remaining space is available + if (rect->x < rightEdge) { + rect->width = rightEdge - rect->x; + rect->x -= mX; // convert from world to local coordinates + rect->y = localY; + rect->height = height; + aAvailableSpace.count++; + } + + return aAvailableSpace.count; +} + +PRInt32 SpaceManager::GetBandData(nscoord aYOffset, + const nsSize& aMaxSize, + nsBandData& aAvailableSpace) const +{ + // Convert the y-offset to world coordinates + nscoord y = mY + aYOffset; + + // If there are no unavailable rects or the offset is below the bottommost + // band then all the space is available + if ((0 == mRectArray.mCount) || (y >= mRectArray.YMost())) { + aAvailableSpace.count = 1; + aAvailableSpace.rects[0].x = 0; + aAvailableSpace.rects[0].y = aYOffset; + aAvailableSpace.rects[0].width = aMaxSize.width; + aAvailableSpace.rects[0].height = aMaxSize.height; + } else { + // Find the first band that contains the y-offset or is below the y-offset + nsRect* band = mRectArray.mRects; + + for (PRInt32 i = 0; i < mRectArray.mCount; ) { + if (band->y > y) { + // The band is below the y-offset + aAvailableSpace.count = 1; + aAvailableSpace.rects[0].x = 0; + aAvailableSpace.rects[0].y = aYOffset; + aAvailableSpace.rects[0].width = aMaxSize.width; + aAvailableSpace.rects[0].height = PR_MIN(band->y - y, aMaxSize.height); + break; + } else if (y < band->YMost()) { + // The band contains the y-offset + return GetBandAvailableSpace(band, i, y, aMaxSize, aAvailableSpace); + } else { + // Skip to the next band + GetNextBand(band, i); + } + } + } + + return aAvailableSpace.count; +} + +/** + * Skips to the start of the next band. + * + * @param aRect in out paremeter. A rect in the band + * @param aIndex in out parameter. aRect's index in the rect array + * @returns PR_TRUE if successful and PR_FALSE if this is the last band. + * If successful aRect and aIndex are updated to point to the + * next band. If there is no next band then aRect is undefined + * and aIndex is set to the number of rects in the rect array + */ +PRBool SpaceManager::GetNextBand(nsRect*& aRect, PRInt32& aIndex) const +{ + nscoord topOfBand = aRect->y; + + while (++aIndex < mRectArray.mCount) { + // Get the next rect and check whether it's part of the same band + aRect++; + + if (aRect->y != topOfBand) { + // We found the start of the next band + return PR_TRUE; + } + } + + // No bands left + return PR_FALSE; +} + +/** + * Returns the number of rectangles in the band + * + * @param aBand the first rect in the band + * @param aIndex aBand's index in the rect array + */ +PRInt32 SpaceManager::LengthOfBand(const nsRect* aBand, PRInt32 aIndex) const +{ + nscoord topOfBand = aBand->y; + PRInt32 result = 1; + + while (++aIndex < mRectArray.mCount) { + // Get the next rect and check whether it's part of the same band + aBand++; + + if (aBand->y != topOfBand) { + // We found the start of the next band + break; + } + + result++; + } + + return result; +} + +/** + * Tries to coalesce horizontally overlapping rectangles within a band + * + * @param aRect a rect in the band + * @param aIndex aRect's index in the rect array + */ +void SpaceManager::CoalesceBand(nsRect* aRect, PRInt32 aIndex) +{ + while ((aIndex + 1) < mRectArray.mCount) { + // Is there another rect in this band? + nsRect* nextRect = aRect + 1; + + if (nextRect->y == aRect->y) { + // Yes. Do the two rects overlap horizontally? + if (aRect->XMost() > nextRect->x) { + // Yes. Extend the right edge of aRect + aRect->width = nextRect->XMost() - aRect->x; + + // Remove the next rect + mRectArray.RemoveAt(aIndex + 1); + aRect = mRectArray.mRects + aIndex; // memory may have changed... + + } else { + // No. We're all done + break; + } + } else { + // The next rect is part of a different band, so we're all done + break; + } + } +} + +/** + * Divides the current band into two vertically + * + * @param aBand the first rect in the band + * @param aIndex aBand's index in the rect array + * @param aB1Height the height of the new band to create + */ +void SpaceManager::DivideBand(nsRect* aBand, PRInt32 aIndex, nscoord aB1Height) +{ + NS_PRECONDITION(aB1Height < aBand->height, "bad height"); + + PRInt32 numRects = LengthOfBand(aBand, aIndex); + nscoord aB2Height = aBand->height - aB1Height; + + // Index where we'll insert the new band + PRInt32 insertAt = aIndex + numRects; + + while (numRects-- > 0) { + // Insert a new bottom band + nsRect r(aBand->x, aBand->y + aB1Height, aBand->width, aB2Height); + + mRectArray.InsertAt(r, insertAt); + aBand = mRectArray.mRects + aIndex; // memory may have changed... + + // Adjust the height of the top band + aBand->height = aB1Height; + + // Move to the next rect in the band + aBand++; + insertAt++; + } +} + +/** + * Adds a new rect to a band. + * + * @param aBand the first rect in the band + * @param aIndex aBand's index in the rect array + * @param aRect the rect to add to the band + * @returns PR_TRUE if successful and PR_FALSE if this is the last band + */ +void SpaceManager::AddRectToBand(nsRect* aBand, + PRInt32 aIndex, + const nsRect& aRect) +{ + NS_PRECONDITION((aBand->y == aRect.y) && (aBand->height == aRect.height), "bad band"); + + nscoord topOfBand = aBand->y; + + // Figure out where in the band to horizontally insert the rect. Try and + // coalesce it with an existing rect if possible. + do { + // Compare the left edge of the new rect with the left edge of the existing + // rect + if (aRect.x <= aBand->x) { + // The new rect's left edge is to the left of the existing rect's left + // edge. Does the new rect overlap the existing rect? + if (aRect.XMost() >= aBand->x) { + // Yes. Extend the existing rect + if (aRect.XMost() > aBand->XMost()) { + aBand->x = aRect.x; + aBand->width = aRect.width; + + // We're extending the right edge of the existing rect which may + // cause the rect to overlap the remaining rects in the band + CoalesceBand(aBand, aIndex); + } else { + aBand->width = aBand->XMost() - aRect.x; + aBand->x = aRect.x; + } + } else { + // No, it's completely to the left of the existing rect. Insert a new + // rect + mRectArray.InsertAt(aRect, aIndex); + } + return; + + } else if (aRect.x <= aBand->XMost()) { + // The two rects are overlapping or adjoining. Extend the right edge of + // the existing rect + aBand->width = aRect.XMost() - aBand->x; + + // Since we extended the right edge of the existing rect it may now + // overlap the remaining rects in the band + CoalesceBand(aBand, aIndex); + return; + } + + // Move to the next rect in the band + aBand++; aIndex++; + } while ((aIndex < mRectArray.mCount) && (aBand->y == topOfBand)); + + // Insert a new rect + mRectArray.InsertAt(aRect, aIndex); +} + +// When comparing a rect to a band there are seven cases to consider. +// 'R' is the rect and 'B' is the band. +// +// Case 1 Case 2 Case 3 Case 4 +// ------ ------ ------ ------ +// +-----+ +-----+ +-----+ +-----+ +// | R | | R | +-----+ +-----+ | | | | +// +-----+ +-----+ | | | R | | B | | B | +// +-----+ | B | +-----+ | | +-----+ | | +// | | | | +-----+ | R | +-----+ +// | B | +-----+ +-----+ +// | | +// +-----+ +// +// +// +// Case 5 Case 6 Case 7 +// ------ ------ ------ +// +-----+ +-----+ +-----+ +-----+ +// | | | R | | B | | | +-----+ +// | B | +-----+ +-----+ | R | | B | +// | | | | +-----+ +// +-----+ +-----+ +// +-----+ +// | R | +// +-----+ +// +void SpaceManager::AddRectRegion(const nsRect& aUnavailableSpace) +{ + // Convert from local to world coordinates + nsRect rect(aUnavailableSpace.x + mX, aUnavailableSpace.y + mY, + aUnavailableSpace.width, aUnavailableSpace.height); + + // If there are no existing bands or this rect is below the bottommost band, + // then add a new band + if ((0 == mRectArray.mCount) || (rect.y >= mRectArray.YMost())) { + // Append a new bottommost band + mRectArray.Append(rect); + return; + } + + // Examine each band looking for a band that intersects this rect + nsRect* band = mRectArray.mRects; + + for (PRInt32 i = 0; i < mRectArray.mCount; ) { + // Compare the top edge of this rect with the top edge of the band + if (rect.y < band->y) { + // The top edge of the rect is above the top edge of the band. + // Is there any overlap? + if (rect.YMost() <= band->y) { + // Case #1. This rect is completely above the band, so insert a + // new band + mRectArray.InsertAt(rect, i); + break; // we're all done + } + + // Case #2 and case #7. Divide this rect, creating a new rect for the + // part that's above the band + nsRect r1(rect.x, rect.y, rect.width, band->y - rect.y); + + // Insert r1 as a new band + mRectArray.InsertAt(r1, i); + i++; + band = mRectArray.mRects + i; // memory may have changed... + + // Modify rect to exclude the part above the band + rect.height = rect.YMost() - band->y; + rect.y = band->y; + + } else if (rect.y > band->y) { + // The top edge of the rect is below the top edge of the band. Is there + // any overlap? + if (rect.y >= band->YMost()) { + // Case #5. This rect is below the current band. Skip to the next band + GetNextBand(band, i); + continue; + } + + // Case #3 and case #4. Divide the current band into two bands with the + // top band being the part that's above the rect + DivideBand(band, i, rect.y - band->y); + band = mRectArray.mRects + i; // memory may have changed... + + // Skip to the bottom band that we just created + GetNextBand(band, i); + } + + // At this point the rect and the band should have the same y-offset + NS_ASSERTION(rect.y == band->y, "unexpected band"); + + // Is the band higher than the rect? + if (band->height > rect.height) { + // Divide the band into two bands with the top band the same height + // as the rect + DivideBand(band, i, rect.height); + band = mRectArray.mRects + i; // memory may have changed... + } + + if (rect.height == band->height) { + // Add the rect to the band + AddRectToBand(band, i, rect); + break; + + } else { + // Case #4 and case #7. The rect contains the band vertically. Divide + // the rect, creating a new rect for the part that overlaps the band + nsRect r1(rect.x, rect.y, rect.width, band->YMost() - rect.y); + + // Add r1 to the band + AddRectToBand(band, i, r1); + band = mRectArray.mRects + i; // memory may have changed... + + // Modify rect to be the part below the band + rect.height = rect.YMost() - band->YMost(); + rect.y = band->YMost(); + + // Continue with the next band + if (!GetNextBand(band, i)) { + // Append a new bottommost band + mRectArray.Append(rect); + break; + } + } + } +} + +void SpaceManager::ClearRegions() +{ + mRectArray.Clear(); +} + +///////////////////////////////////////////////////////////////////////////// +// RectArray + +SpaceManager::RectArray::RectArray() +{ + mRects = nsnull; + mCount = mMax = 0; +} + +SpaceManager::RectArray::~RectArray() +{ + if (nsnull != mRects) { + free(mRects); + } +} + +nscoord SpaceManager::RectArray::YMost() const +{ + return mRects[mCount - 1].YMost(); +} + +void SpaceManager::RectArray::Append(const nsRect& aRect) +{ + // Ensure there's enough capacity + if (mCount >= mMax) { + mMax += 8; + mRects = (nsRect*)realloc(mRects, mMax * sizeof(nsRect)); + } + + mRects[mCount++] = aRect; +} + +void SpaceManager::RectArray::InsertAt(const nsRect& aRect, PRInt32 aIndex) +{ + NS_PRECONDITION(aIndex <= mCount, "bad index"); // no holes in the array + + // Ensure there's enough capacity + if (mCount >= mMax) { + mMax += 8; + mRects = (nsRect*)realloc(mRects, mMax * sizeof(nsRect)); + } + + memmove(&mRects[aIndex + 1], &mRects[aIndex], (mCount - aIndex) * sizeof(nsRect)); + mRects[aIndex] = aRect; + mCount++; +} + +void SpaceManager::RectArray::RemoveAt(PRInt32 aIndex) +{ + NS_PRECONDITION(aIndex < mCount, "bad index"); + + mCount--; + if (aIndex < mCount) { + memmove(&mRects[aIndex], &mRects[aIndex + 1], (mCount - aIndex) * sizeof(nsRect)); + } +} + +void SpaceManager::RectArray::Clear() +{ + mCount = 0; +} diff --git a/mozilla/layout/base/src/nsSpaceManager.h b/mozilla/layout/base/src/nsSpaceManager.h new file mode 100644 index 00000000000..978d6ae5cf8 --- /dev/null +++ b/mozilla/layout/base/src/nsSpaceManager.h @@ -0,0 +1,91 @@ +/* -*- 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. + */ +#ifndef nsSpaceManager_h___ +#define nsSpaceManager_h___ + +#include "nsISpaceManager.h" + +/** + * Implementation of nsISpaceManager that maintains a region data structure of + * unavailable space + */ +class SpaceManager : public nsISpaceManager { +public: + SpaceManager(nsIFrame* aFrame); + + // nsISupports + NS_DECL_ISUPPORTS + + virtual nsIFrame* GetFrame() const; + + virtual void Translate(nscoord aDx, nscoord aDy); + virtual void GetTranslation(nscoord& aX, nscoord& aY) const; + virtual nscoord YMost() const; + virtual PRInt32 GetBandData(nscoord aYOffset, + const nsSize& aMaxSize, + nsBandData& aAvailableSpace) const; + virtual void AddRectRegion(const nsRect& aUnavailableSpace); + virtual void ClearRegions(); + +protected: + class RectArray { + public: + RectArray(); + ~RectArray(); + + // Functions to add rects + void Append(const nsRect& aRect); + void InsertAt(const nsRect& aRect, PRInt32 aIndex); + void RemoveAt(PRInt32 aIndex); + + // Clear the list of rectangles + void Clear(); + + // Returns the y-most of the bottom band + nscoord YMost() const; + + public: + // Access to the underlying storage + nsRect* mRects; // y-x banded array of rectangles of unavailable space + PRInt32 mCount; // current number of rects + PRInt32 mMax; // capacity of rect array + }; + + nsIFrame* const mFrame; // frame associated with the space manager + nscoord mX, mY; // translation from local to global coordinate space + RectArray mRectArray; // y-x banded array of rectangles of unavailable space + +protected: + PRBool GetNextBand(nsRect*& aRect, PRInt32& aIndex) const; + PRInt32 LengthOfBand(const nsRect* aBand, PRInt32 aIndex) const; + void CoalesceBand(nsRect* aBand, PRInt32 aIndex); + void DivideBand(nsRect* aBand, PRInt32 aIndex, nscoord aB1Height); + void AddRectToBand(nsRect* aBand, PRInt32 aIndex, const nsRect& aRect); + PRInt32 GetBandAvailableSpace(const nsRect* aBand, + PRInt32 aIndex, + nscoord aY, + const nsSize& aMaxSize, + nsBandData& aAvailableSpace) const; + +private: + SpaceManager(const SpaceManager&); // no implementation + void operator=(const SpaceManager&); // no implementation +}; + +#endif /* nsSpaceManager_h___ */ + diff --git a/mozilla/layout/base/src/nsSplittableFrame.cpp b/mozilla/layout/base/src/nsSplittableFrame.cpp new file mode 100644 index 00000000000..15fcce06650 --- /dev/null +++ b/mozilla/layout/base/src/nsSplittableFrame.cpp @@ -0,0 +1,172 @@ +/* -*- 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 "nsSplittableFrame.h" +#include "nsIContent.h" +#include "nsIContentDelegate.h" +#include "nsIPresContext.h" +#include "nsIStyleContext.h" + +nsSplittableFrame::nsSplittableFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) + : nsFrame(aContent, aIndexInParent, aParent) +{ +} + +nsSplittableFrame::~nsSplittableFrame() +{ + // XXX write me +} + +// Flow member functions + +PRBool nsSplittableFrame::IsSplittable() const +{ + return PR_TRUE; +} + +/** + * Creates a continuing frame. The continuing frame is appended to the flow. + * + * @param aPresContext presentation context to use to get the content delegate + * @param aParent the geometric parent to use. Note that it maybe different than + * the receiver's geometric parent + * @return the continuing frame or null if unsuccessful + */ +nsIFrame* nsSplittableFrame::CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent) +{ + nsIContentDelegate* contentDelegate = mContent->GetDelegate(aPresContext); + nsIFrame* continuingFrame = + contentDelegate->CreateFrame(aPresContext, mContent, mIndexInParent, aParent); + NS_RELEASE(contentDelegate); + + // Append the continuing frame to the flow + continuingFrame->AppendToFlow(this); + + // Resolve style for the continuing frame and set its style context. + nsIStyleContext* styleContext = + aPresContext->ResolveStyleContextFor(mContent, aParent); + continuingFrame->SetStyleContext(styleContext); + NS_RELEASE(styleContext); + + return continuingFrame; +} + +nsIFrame* nsSplittableFrame::GetPrevInFlow() const +{ + return mPrevInFlow; +} + +void nsSplittableFrame::SetPrevInFlow(nsIFrame* aFrame) +{ + mPrevInFlow = aFrame; +} + +nsIFrame* nsSplittableFrame::GetNextInFlow() const +{ + return mNextInFlow; +} + +void nsSplittableFrame::SetNextInFlow(nsIFrame* aFrame) +{ + mNextInFlow = aFrame; +} + +nsIFrame* nsSplittableFrame::GetFirstInFlow() const +{ + nsSplittableFrame* firstInFlow; + nsSplittableFrame* prevInFlow = (nsSplittableFrame*)this; + while (nsnull!=prevInFlow) { + firstInFlow = prevInFlow; + prevInFlow = (nsSplittableFrame*)firstInFlow->mPrevInFlow; + } + NS_POSTCONDITION(nsnull!=firstInFlow, "illegal state in flow chain."); + return firstInFlow; +} + +nsIFrame* nsSplittableFrame::GetLastInFlow() const +{ + nsSplittableFrame* lastInFlow; + nsSplittableFrame* nextInFlow = (nsSplittableFrame*)this; + while (nsnull!=nextInFlow) { + lastInFlow = nextInFlow; + nextInFlow = (nsSplittableFrame*)lastInFlow->mNextInFlow; + } + NS_POSTCONDITION(nsnull!=lastInFlow, "illegal state in flow chain."); + return lastInFlow; +} + +// Append this frame to flow after aAfterFrame +void nsSplittableFrame::AppendToFlow(nsIFrame* aAfterFrame) +{ + NS_PRECONDITION(aAfterFrame != nsnull, "null pointer"); + + mPrevInFlow = aAfterFrame; + mNextInFlow = aAfterFrame->GetNextInFlow(); + mPrevInFlow->SetNextInFlow(this); + if (mNextInFlow) { + mNextInFlow->SetPrevInFlow(this); + } +} + +// Prepend this frame to flow before aBeforeFrame +void nsSplittableFrame::PrependToFlow(nsIFrame* aBeforeFrame) +{ + NS_PRECONDITION(aBeforeFrame != nsnull, "null pointer"); + + mPrevInFlow = aBeforeFrame->GetPrevInFlow(); + mNextInFlow = aBeforeFrame; + mNextInFlow->SetPrevInFlow(this); + if (mPrevInFlow) { + mPrevInFlow->SetNextInFlow(this); + } +} + +// Remove this frame from the flow. Connects prev in flow and next in flow +void nsSplittableFrame::RemoveFromFlow() +{ + if (mPrevInFlow) { + mPrevInFlow->SetNextInFlow(mNextInFlow); + } + + if (mNextInFlow) { + mNextInFlow->SetPrevInFlow(mPrevInFlow); + } + + mPrevInFlow = mNextInFlow = nsnull; +} + +// Detach from previous frame in flow +void nsSplittableFrame::BreakFromPrevFlow() +{ + if (mPrevInFlow) { + mPrevInFlow->SetNextInFlow(nsnull); + mPrevInFlow = nsnull; + } +} + +// Detach from next frame in flow +void nsSplittableFrame::BreakFromNextFlow() +{ + if (mNextInFlow) { + mNextInFlow->SetPrevInFlow(nsnull); + mNextInFlow = nsnull; + } +} + diff --git a/mozilla/layout/base/src/nsSplittableFrame.h b/mozilla/layout/base/src/nsSplittableFrame.h new file mode 100644 index 00000000000..221d054f3ad --- /dev/null +++ b/mozilla/layout/base/src/nsSplittableFrame.h @@ -0,0 +1,68 @@ +/* -*- 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. + */ +#ifndef nsSplittableFrame_h___ +#define nsSplittableFrame_h___ + +#include "nsFrame.h" + +// Derived class that allows splitting +class nsSplittableFrame : public nsFrame +{ +public: + // Flow member functions. + + // CreateContinuingFrame() does the default behavior of using the + // content delegate to create a new frame + virtual PRBool IsSplittable() const; + virtual nsIFrame* CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent); + virtual nsIFrame* GetPrevInFlow() const; + virtual void SetPrevInFlow(nsIFrame*); + virtual nsIFrame* GetNextInFlow() const; + virtual void SetNextInFlow(nsIFrame*); + + /** + * Return the first frame in our current flow. + */ + nsIFrame* GetFirstInFlow() const; + + /** + * Return the last frame in our current flow. + */ + nsIFrame* GetLastInFlow() const; + + virtual void AppendToFlow(nsIFrame* aAfterFrame); + virtual void PrependToFlow(nsIFrame* aBeforeFrame); + virtual void RemoveFromFlow(); + virtual void BreakFromPrevFlow(); + virtual void BreakFromNextFlow(); + +protected: + // Constructor. Takes as arguments the content object, the index in parent, + // and the Frame for the content parent + nsSplittableFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + virtual ~nsSplittableFrame(); + + nsIFrame* mPrevInFlow; + nsIFrame* mNextInFlow; +}; + +#endif /* nsSplittableFrame_h___ */ diff --git a/mozilla/layout/base/src/nsStyleConsts.h b/mozilla/layout/base/src/nsStyleConsts.h new file mode 100644 index 00000000000..bbae7e19862 --- /dev/null +++ b/mozilla/layout/base/src/nsStyleConsts.h @@ -0,0 +1,192 @@ +/* -*- 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. + */ +#ifndef nsStyleConsts_h___ +#define nsStyleConsts_h___ + +// Defines for various style related constants + +// See nsStyleMolecule.backgroundAttachment +#define NS_STYLE_BG_ATTACHMENT_FIXED 0x01 +#define NS_STYLE_BG_ATTACHMENT_SCROLL 0x02 + +// See nsStyleMolecule.backgroundFlags +#define NS_STYLE_BG_COLOR_TRANSPARENT 0x01 +#define NS_STYLE_BG_IMAGE_NONE 0x02 +#define NS_STYLE_BG_X_POSITION_PCT 0x04 +#define NS_STYLE_BG_X_POSITION_LENGTH 0x08 +#define NS_STYLE_BG_Y_POSITION_PCT 0x10 +#define NS_STYLE_BG_Y_POSITION_LENGTH 0x20 + +// See nsStyleMolecule.backgroundRepeat +#define NS_STYLE_BG_REPEAT_OFF 0x00 +#define NS_STYLE_BG_REPEAT_X 0x01 +#define NS_STYLE_BG_REPEAT_Y 0x02 +#define NS_STYLE_BG_REPEAT_XY 0x03 + +// See nsStyleMolecule.borderSizeFlags +#define NS_STYLE_BORDER_WIDTH_THIN 0 +#define NS_STYLE_BORDER_WIDTH_MEDIUM 1 +#define NS_STYLE_BORDER_WIDTH_THICK 2 +#define NS_STYLE_BORDER_WIDTH_LENGTH_VALUE 3 + +// See nsStyleMolecule.borderStyle +#define NS_STYLE_BORDER_STYLE_NONE 0 +#define NS_STYLE_BORDER_STYLE_GROOVE 1 +#define NS_STYLE_BORDER_STYLE_RIDGE 2 +#define NS_STYLE_BORDER_STYLE_DOTTED 3 +#define NS_STYLE_BORDER_STYLE_DASHED 4 +#define NS_STYLE_BORDER_STYLE_SOLID 5 +#define NS_STYLE_BORDER_STYLE_DOUBLE 6 +#define NS_STYLE_BORDER_STYLE_BLANK 7 +#define NS_STYLE_BORDER_STYLE_INSET 8 +#define NS_STYLE_BORDER_STYLE_OUTSET 9 + +// See nsStyleMolecule.clear +#define NS_STYLE_CLEAR_NONE 0x0 +#define NS_STYLE_CLEAR_LEFT 0x1 +#define NS_STYLE_CLEAR_RIGHT 0x2 +#define NS_STYLE_CLEAR_BOTH 0x3 + +// See nsStyleMolecule.clipFlags +#define NS_STYLE_CLIP_AUTO 0 + +// See nsStyleMolecule.cursor +#define NS_STYLE_CURSOR_INHERIT 0 +#define NS_STYLE_CURSOR_DEFAULT 1 +#define NS_STYLE_CURSOR_HAND 2 +#define NS_STYLE_CURSOR_IBEAM 3 + +// See nsStyleMolecule.direction +#define NS_STYLE_DIRECTION_LTR 0 +#define NS_STYLE_DIRECTION_RTL 1 + +// See nsStyleMolecule.display +#define NS_STYLE_DISPLAY_NONE 0 +#define NS_STYLE_DISPLAY_BLOCK 1 +#define NS_STYLE_DISPLAY_INLINE 2 +#define NS_STYLE_DISPLAY_LIST_ITEM 3 + +// See nsStyleMolecule.floats +#define NS_STYLE_FLOAT_NONE 0 +#define NS_STYLE_FLOAT_LEFT 1 +#define NS_STYLE_FLOAT_RIGHT 2 + +// See nsStyleMolecule.fontStyle +#define NS_STYLE_FONT_STYLE_NORMAL 0 +#define NS_STYLE_FONT_STYLE_ITALIC 1 +#define NS_STYLE_FONT_STYLE_OBLIQUE 2 + +// See nsStyleMolecule.fontVariant +#define NS_STYLE_FONT_VARIANT_NORMAL 0 +#define NS_STYLE_FONT_VARIANT_SMALL_CAPS 1 + +// See nsStyleMolecule.fontWeight +#define NS_STYLE_FONT_WEIGHT_NORMAL 400 +#define NS_STYLE_FONT_WEIGHT_BOLD 700 +#define NS_STYLE_FONT_WEIGHT_BOLDER 100 +#define NS_STYLE_FONT_WEIGHT_LIGHTER -100 + +// See nsStyleMolecule.fontSize +#define NS_STYLE_FONT_SIZE_XXSMALL 0 +#define NS_STYLE_FONT_SIZE_XSMALL 1 +#define NS_STYLE_FONT_SIZE_SMALL 2 +#define NS_STYLE_FONT_SIZE_MEDIUM 3 +#define NS_STYLE_FONT_SIZE_LARGE 4 +#define NS_STYLE_FONT_SIZE_XLARGE 5 +#define NS_STYLE_FONT_SIZE_XXLARGE 6 +#define NS_STYLE_FONT_SIZE_LARGER 7 +#define NS_STYLE_FONT_SIZE_SMALLER 8 + +#define NS_STYLE_HEIGHT_AUTO 0 + +#define NS_STYLE_LEFT_AUTO 0 + +#define NS_STYLE_LINE_HEIGHT_NORMAL 0 + +#define NS_STYLE_LIST_STYLE_IMAGE_NONE 0 + +#define NS_STYLE_LIST_STYLE_NONE 0 +#define NS_STYLE_LIST_STYLE_DISC 1 +#define NS_STYLE_LIST_STYLE_CIRCLE 2 +#define NS_STYLE_LIST_STYLE_SQUARE 3 +#define NS_STYLE_LIST_STYLE_DECIMAL 4 +#define NS_STYLE_LIST_STYLE_LOWER_ROMAN 5 +#define NS_STYLE_LIST_STYLE_UPPER_ROMAN 6 +#define NS_STYLE_LIST_STYLE_LOWER_ALPHA 7 +#define NS_STYLE_LIST_STYLE_UPPER_ALPHA 8 +#define NS_STYLE_LIST_STYLE_BASIC 9 // not in css + +#define NS_STYLE_LIST_STYLE_POSITION_INSIDE 0 +#define NS_STYLE_LIST_STYLE_POSITION_OUTSIDE 1 + +#define NS_STYLE_MARGIN_SIZE_AUTO 0 + +#define NS_STYLE_OVERFLOW_VISIBLE 0 +#define NS_STYLE_OVERFLOW_HIDDEN 1 +#define NS_STYLE_OVERFLOW_SCROLL 2 +#define NS_STYLE_OVERFLOW_AUTO 3 + +#define NS_STYLE_POSITION_STATIC 0 +#define NS_STYLE_POSITION_RELATIVE 1 +#define NS_STYLE_POSITION_ABSOLUTE 2 + +#define NS_STYLE_SPACING_NORMAL 0 + +#define NS_STYLE_TEXT_ALIGN_LEFT 0 +#define NS_STYLE_TEXT_ALIGN_RIGHT 1 +#define NS_STYLE_TEXT_ALIGN_CENTER 2 +#define NS_STYLE_TEXT_ALIGN_JUSTIFY 3 + +#define NS_STYLE_TEXT_DECORATION_NONE 0 +#define NS_STYLE_TEXT_DECORATION_UNDERLINE 0x1 +#define NS_STYLE_TEXT_DECORATION_OVERLINE 0x2 +#define NS_STYLE_TEXT_DECORATION_LINE_THROUGH 0x4 +#define NS_STYLE_TEXT_DECORATION_BLINK 0x8 + +#define NS_STYLE_TEXT_TRANSFORM_NONE 0 +#define NS_STYLE_TEXT_TRANSFORM_CAPITALIZE 1 +#define NS_STYLE_TEXT_TRANSFORM_LOWERCASE 2 +#define NS_STYLE_TEXT_TRANSFORM_UPPERCASE 3 + +#define NS_STYLE_TOP_AUTO 0 + +// Note: these values pickup after the text-align values because there +// are a few html cases where an object can have both types of +// alignment applied with a single attribute +#define NS_STYLE_VERTICAL_ALIGN_BASELINE 10 +#define NS_STYLE_VERTICAL_ALIGN_SUB 11 +#define NS_STYLE_VERTICAL_ALIGN_SUPER 12 +#define NS_STYLE_VERTICAL_ALIGN_TOP 13 +#define NS_STYLE_VERTICAL_ALIGN_TEXT_TOP 14 +#define NS_STYLE_VERTICAL_ALIGN_MIDDLE 15 +#define NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM 16 +#define NS_STYLE_VERTICAL_ALIGN_BOTTOM 17 +#define NS_STYLE_VERTICAL_ALIGN_LENGTH 18 +#define NS_STYLE_VERTICAL_ALIGN_PCT 19 + +#define NS_STYLE_VISIBILITY_INHERIT 0 +#define NS_STYLE_VISIBILITY_VISIBLE 1 +#define NS_STYLE_VISIBILITY_HIDDEN 2 + +#define NS_STYLE_WIDTH_AUTO 0 + +#define NS_STYLE_WHITESPACE_NORMAL 0 +#define NS_STYLE_WHITESPACE_PRE 1 +#define NS_STYLE_WHITESPACE_NOWRAP 2 + +#endif /* nsStyleConsts_h___ */ diff --git a/mozilla/layout/base/src/nsStyleContext.cpp b/mozilla/layout/base/src/nsStyleContext.cpp new file mode 100644 index 00000000000..bf44521a48e --- /dev/null +++ b/mozilla/layout/base/src/nsStyleContext.cpp @@ -0,0 +1,613 @@ +/* -*- 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 "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsString.h" +#include "nsUnitConversion.h" +#include "nsIContent.h" +#include "nsIPresContext.h" +#include "nsIStyleRule.h" +#include "nsISupportsArray.h" +#include "nsCRT.h" + +#include "nsIFrame.h" + + +#ifdef NS_DEBUG +static PRBool gsDebug = PR_FALSE; +#else +static const PRBool gsDebug = PR_FALSE; +#endif + + +static NS_DEFINE_IID(kStyleFontSID, NS_STYLEFONT_SID); +static NS_DEFINE_IID(kStyleColorSID, NS_STYLECOLOR_SID); +static NS_DEFINE_IID(kStyleListSID, NS_STYLELIST_SID); +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); + +static NS_DEFINE_IID(kIStyleContextIID, NS_ISTYLECONTEXT_IID); + +nsStyleFont::nsStyleFont(const nsFont& aFont) + : mFont(aFont) +{ +} + +nsStyleFont::~nsStyleFont(void) +{ +} + +struct StyleFontImpl : public nsStyleFont { + StyleFontImpl(const nsFont& aFont) + : nsStyleFont(aFont) + {} + ~StyleFontImpl() + {} + + virtual const nsID& GetID(void) + { return kStyleFontSID; } + + virtual void InheritFrom(const nsStyleFont& aCopy); + +private: // These are not allowed + StyleFontImpl(const StyleFontImpl& aOther); + StyleFontImpl& operator=(const StyleFontImpl& aOther); +}; + +void StyleFontImpl::InheritFrom(const nsStyleFont& aCopy) +{ + mFont = aCopy.mFont; + mThreeD = aCopy.mThreeD; +} + +struct StyleColorImpl: public nsStyleColor { + StyleColorImpl(void) + { + mBackgroundAttachment = NS_STYLE_BG_ATTACHMENT_SCROLL; + mBackgroundFlags = NS_STYLE_BG_COLOR_TRANSPARENT; + mBackgroundRepeat = NS_STYLE_BG_REPEAT_OFF; + + mBackgroundColor = NS_RGB(192,192,192); + } + + ~StyleColorImpl(void) + {} + + virtual const nsID& GetID(void) + { return kStyleColorSID; } + + virtual void InheritFrom(const nsStyleColor& aCopy); + +private: // These are not allowed + StyleColorImpl(const StyleColorImpl& aOther); + StyleColorImpl& operator=(const StyleColorImpl& aOther); +}; + +void StyleColorImpl::InheritFrom(const nsStyleColor& aCopy) +{ + mColor = aCopy.mColor; + + mBackgroundFlags = NS_STYLE_BG_COLOR_TRANSPARENT; +} + + +struct StyleListImpl: public nsStyleList { + StyleListImpl(void) + { + mListStyleType = NS_STYLE_LIST_STYLE_BASIC; + mListStylePosition = NS_STYLE_LIST_STYLE_POSITION_OUTSIDE; + } + + ~StyleListImpl(void) + { + } + + virtual const nsID& GetID(void) + { return kStyleListSID; } + + virtual void InheritFrom(const nsStyleList& aCopy); +}; + +void StyleListImpl::InheritFrom(const nsStyleList& aCopy) +{ + mListStyleType = aCopy.mListStyleType; + mListStyleImage = aCopy.mListStyleImage; + mListStylePosition = aCopy.mListStylePosition; +} + +nsStyleMolecule::nsStyleMolecule() +{ +} + +nsStyleMolecule::~nsStyleMolecule() +{ +} + +struct StyleMoleculeImpl : public nsStyleMolecule { + StyleMoleculeImpl(void) + {} + ~StyleMoleculeImpl(void) + {} + + virtual const nsID& GetID(void) + { return kStyleMoleculeSID; } + + virtual void InheritFrom(const nsStyleMolecule& aCopy); + +private: // These are not allowed + StyleMoleculeImpl(const StyleMoleculeImpl& aOther); + StyleMoleculeImpl& operator=(const StyleMoleculeImpl& aOther); +}; + +void StyleMoleculeImpl::InheritFrom(const nsStyleMolecule& aCopy) +{ + cursor = aCopy.cursor; + direction = aCopy.direction; + + textDecoration = aCopy.textDecoration; + + textAlign = aCopy.textAlign; + whiteSpace = aCopy.whiteSpace; + +// lineHeight = aCopy.lineHeight; +} + + +//---------------------------------------------------------------------- + +class StyleContextImpl : public nsIStyleContext { +public: + StyleContextImpl(nsIStyleContext* aParent, nsISupportsArray* aRules, nsIPresContext* aPresContext); + ~StyleContextImpl(); + + void* operator new(size_t sz) { + void* rv = new char[sz]; + nsCRT::zero(rv, sz); + return rv; + } + + NS_DECL_ISUPPORTS + + virtual nsIStyleContext* GetParent(void) const; + virtual nsISupportsArray* GetStyleRules(void) const; + + virtual PRBool Equals(const nsIStyleContext* aOther) const; + virtual PRUint32 HashValue(void) const; + + virtual nsStyleStruct* GetData(const nsIID& aSID); + + virtual void InheritFrom(const StyleContextImpl& aParent); + + virtual void HackStyleFor(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aFrame); + + nsIStyleContext* mParent; + PRUint32 mHashValid: 1; + PRUint32 mHashValue: 31; + nsISupportsArray* mRules; + + // the style data... + StyleFontImpl mFont; + StyleColorImpl mColor; + StyleListImpl mList; +// xxx backward support hack + StyleMoleculeImpl mMolecule; +}; + +StyleContextImpl::StyleContextImpl(nsIStyleContext* aParent, nsISupportsArray* aRules, + nsIPresContext* aPresContext) + : mParent(aParent), // weak ref + mRules(aRules), + mFont(aPresContext->GetDefaultFont()), + mColor(), + mList(), + mMolecule() +{ + NS_INIT_REFCNT(); + NS_IF_ADDREF(mRules); + + if (nsnull != aParent) { + InheritFrom((StyleContextImpl&)*aParent); + } + + if (nsnull != mRules) { + PRInt32 index = mRules->Count(); + while (0 < index) { + nsIStyleRule* rule = (nsIStyleRule*)mRules->ElementAt(--index); + rule->MapStyleInto(this, aPresContext); + NS_RELEASE(rule); + } + } +} + +StyleContextImpl::~StyleContextImpl() +{ + mParent = nsnull; // weak ref + NS_IF_RELEASE(mRules); +} + +NS_IMPL_ISUPPORTS(StyleContextImpl, kIStyleContextIID) + +nsIStyleContext* StyleContextImpl::GetParent(void) const +{ + NS_IF_ADDREF(mParent); + return mParent; +} + +nsISupportsArray* StyleContextImpl::GetStyleRules(void) const +{ + NS_IF_ADDREF(mRules); + return mRules; +} + + +PRBool StyleContextImpl::Equals(const nsIStyleContext* aOther) const +{ + PRBool result = PR_TRUE; + const StyleContextImpl* other = (StyleContextImpl*)aOther; + + if (other != this) { + if (mParent != other->mParent) { + result = PR_FALSE; + } + else { + if ((nsnull != mRules) && (nsnull != other->mRules)) { + result = mRules->Equals(other->mRules); + } + else { + result = PRBool((nsnull == mRules) && (nsnull == other->mRules)); + } + } + } + return result; +} + +PRUint32 StyleContextImpl::HashValue(void) const +{ + if (0 == mHashValid) { + ((StyleContextImpl*)this)->mHashValue = ((nsnull != mParent) ? mParent->HashValue() : 0); + if (nsnull != mRules) { + PRInt32 index = mRules->Count(); + while (0 <= --index) { + nsIStyleRule* rule = (nsIStyleRule*)mRules->ElementAt(index); + PRUint32 hash = rule->HashValue(); + ((StyleContextImpl*)this)->mHashValue ^= (hash & 0x7FFFFFFF); + NS_RELEASE(rule); + } + } + ((StyleContextImpl*)this)->mHashValid = 1; + } + return mHashValue; +} + + +nsStyleStruct* StyleContextImpl::GetData(const nsIID& aSID) +{ + if (aSID.Equals(kStyleFontSID)) { + return &mFont; + } + if (aSID.Equals(kStyleColorSID)) { + return &mColor; + } + if (aSID.Equals(kStyleListSID)) { + return &mList; + } + if (aSID.Equals(kStyleMoleculeSID)) { + return &mMolecule; + } + return nsnull; +} + +void StyleContextImpl::InheritFrom(const StyleContextImpl& aParent) +{ + mFont.InheritFrom(aParent.mFont); + mColor.InheritFrom(aParent.mColor); + mList.InheritFrom(aParent.mList); + mMolecule.InheritFrom(aParent.mMolecule); +} + +void StyleContextImpl::HackStyleFor(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame) +{ +/* + mColor.mColor = NS_RGB(0, 0, 0); +*/ + + mMolecule.display = NS_STYLE_DISPLAY_BLOCK; + mMolecule.whiteSpace = NS_STYLE_WHITESPACE_NORMAL; + mMolecule.verticalAlign = NS_STYLE_VERTICAL_ALIGN_BASELINE; + mMolecule.textAlign = NS_STYLE_TEXT_ALIGN_LEFT; + + mMolecule.positionFlags = NS_STYLE_POSITION_STATIC; + mMolecule.floats = 0; + + // XXX If it's a B guy then make it inline + nsIAtom* tag = aContent->GetTag(); + nsAutoString buf; + if (tag != nsnull) { + tag->ToString(buf); + NS_RELEASE(tag); + if (buf.EqualsIgnoreCase("B")) { +// float p2t = aPresContext->GetPixelsToTwips(); + mMolecule.display = NS_STYLE_DISPLAY_INLINE; +// mColor.mBackgroundColor = NS_RGB(128, 128, 255); +// mColor.mBackgroundFlags = 0; +// mMolecule.border.top = nscoord(5 * p2t); +// mMolecule.border.right = nscoord(5 * p2t); +// mMolecule.border.bottom = nscoord(5 * p2t); +// mMolecule.border.left = nscoord(5 * p2t); +// for (int i = 0; i < 4; i++) { +// mMolecule.borderStyle[i] = NS_STYLE_BORDER_STYLE_INSET; +// mMolecule.borderColor[i] = NS_RGB(128, 128, 128); +// } + } else if (buf.EqualsIgnoreCase("A")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + mMolecule.cursor = NS_STYLE_CURSOR_HAND; + } else if (buf.EqualsIgnoreCase("BR")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + nsString align("CLEAR"); + nsString value; + if (eContentAttr_HasValue == aContent->GetAttribute(align, value)) { + if (0 == value.Compare("left", PR_TRUE)) { + mMolecule.clear = NS_STYLE_CLEAR_LEFT; + } else if (0 == value.Compare("right", PR_TRUE)) { + mMolecule.clear = NS_STYLE_CLEAR_RIGHT; + } else if (0 == value.Compare("all", PR_TRUE)) { + mMolecule.clear = NS_STYLE_CLEAR_BOTH; + } + } + } else if (buf.EqualsIgnoreCase("SPACER")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + } else if (buf.EqualsIgnoreCase("WBR")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + } else if (buf.EqualsIgnoreCase("INPUT")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + } else if (buf.EqualsIgnoreCase("I")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + } else if (buf.EqualsIgnoreCase("S")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + } else if (buf.EqualsIgnoreCase("PRE")) { + mMolecule.whiteSpace = NS_STYLE_WHITESPACE_PRE; + mMolecule.margin.top = NS_POINTS_TO_TWIPS_INT(3); + mMolecule.margin.bottom = NS_POINTS_TO_TWIPS_INT(3); +// mColor.mBackgroundImage = "resource:/res/gear1.gif"; +// mColor.mBackgroundRepeat = NS_STYLE_BG_REPEAT_XY; + } else if (buf.EqualsIgnoreCase("U")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + } else if (buf.EqualsIgnoreCase("FONT")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + } else if (buf.EqualsIgnoreCase("THREED")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + mFont.mThreeD = 1; + } else if (buf.EqualsIgnoreCase("TT")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; +// mFont.mFont.name.SetLength(0); +// mFont.mFont.name.Append("Courier"); +// mMolecule.positionFlags = NS_STYLE_POSITION_RELATIVE; +// mMolecule.left = -50; +// mMolecule.top = -50; + } else if (buf.EqualsIgnoreCase("IMG")) { + float p2t = aPresContext->GetPixelsToTwips(); + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + mMolecule.padding.top = nscoord(2 * p2t); + mMolecule.padding.right = nscoord(2 * p2t); + mMolecule.padding.bottom = nscoord(2 * p2t); + mMolecule.padding.left = nscoord(2 * p2t); + nsString align("ALIGN"); + nsString value; + if (eContentAttr_HasValue == aContent->GetAttribute(align, value)) { + if (0 == value.Compare("left", PR_TRUE)) { + mMolecule.floats = NS_STYLE_FLOAT_LEFT; + } else if (0 == value.Compare("right", PR_TRUE)) { + mMolecule.floats = NS_STYLE_FLOAT_RIGHT; + } + } + } else if (buf.EqualsIgnoreCase("P")) { + // mMolecule.textAlign = NS_STYLE_TEXT_ALIGN_CENTER; + mMolecule.margin.top = NS_POINTS_TO_TWIPS_INT(2); + mMolecule.margin.bottom = NS_POINTS_TO_TWIPS_INT(2); + } else if (buf.EqualsIgnoreCase("BODY")) { + float p2t = aPresContext->GetPixelsToTwips(); +// mColor.mBackgroundColor = NS_RGB(255, 255, 255); +// mColor.mBackgroundFlags = 0; + //mColor.mBackgroundFlags = 0; + //mColor.mBackgroundImage = "resource:/res/rock_gra.gif"; + //mColor.mBackgroundRepeat = NS_STYLE_BG_REPEAT_XY; + mMolecule.padding.top = nscoord(5 * p2t); + mMolecule.padding.right = nscoord(5 * p2t); + mMolecule.padding.bottom = nscoord(5 * p2t); + mMolecule.padding.left = nscoord(5 * p2t); + mMolecule.border.top = nscoord(1 * p2t); + mMolecule.border.right = nscoord(1 * p2t); + mMolecule.border.bottom = nscoord(1 * p2t); + mMolecule.border.left = nscoord(1 * p2t); + for (int i = 0; i < 4; i++) { + mMolecule.borderStyle[i] = NS_STYLE_BORDER_STYLE_SOLID; + mMolecule.borderColor[i] = NS_RGB(0, 255, 0); + } + } else if (buf.EqualsIgnoreCase("LI")) { + mMolecule.display = NS_STYLE_DISPLAY_LIST_ITEM; + } else if (buf.EqualsIgnoreCase("UL") || buf.EqualsIgnoreCase("OL")) { + float p2t = aPresContext->GetPixelsToTwips(); + mMolecule.padding.left = nscoord(40 * p2t); + mMolecule.margin.top = NS_POINTS_TO_TWIPS_INT(5); + mMolecule.margin.bottom = NS_POINTS_TO_TWIPS_INT(5); + } else if (buf.EqualsIgnoreCase("TABLE")) { // TABLE + mMolecule.border.top = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.border.bottom = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.border.right = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.border.left = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.borderStyle[0] = mMolecule.borderStyle[1] = + mMolecule.borderStyle[2] = mMolecule.borderStyle[3] = NS_STYLE_BORDER_STYLE_SOLID; + mMolecule.fixedWidth = -1; + mMolecule.proportionalWidth = 100; + nsString align("ALIGN"); + nsString value; + if (eContentAttr_HasValue == aContent->GetAttribute(align, value)) { + if (0 == value.Compare("left", PR_TRUE)) { + mMolecule.floats = NS_STYLE_FLOAT_LEFT; + } else if (0 == value.Compare("right", PR_TRUE)) { + mMolecule.floats = NS_STYLE_FLOAT_RIGHT; + } + } + } else if (buf.EqualsIgnoreCase("CAPTION")) { // CAPTION + mMolecule.verticalAlign = NS_STYLE_VERTICAL_ALIGN_TOP; + } else if (buf.EqualsIgnoreCase("TBODY")) { // TBODY + mMolecule.padding.top = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.padding.bottom = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.padding.right = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.padding.left = NS_POINTS_TO_TWIPS_INT(1); + } else if (buf.EqualsIgnoreCase("TR")) { // TROW + mMolecule.padding.top = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.padding.bottom = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.padding.right = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.padding.left = NS_POINTS_TO_TWIPS_INT(1); + } else if (buf.EqualsIgnoreCase("TD")) { // TD + float p2t = aPresContext->GetPixelsToTwips(); + + + // Set padding to twenty for testing purposes + int cellPadding = 1; + if (gsDebug==PR_TRUE) + cellPadding = 20; + mMolecule.verticalAlign = NS_STYLE_VERTICAL_ALIGN_MIDDLE; + + mMolecule.padding.top = NS_POINTS_TO_TWIPS_INT(cellPadding); + mMolecule.padding.bottom = NS_POINTS_TO_TWIPS_INT(cellPadding); + mMolecule.padding.right = NS_POINTS_TO_TWIPS_INT(cellPadding); + mMolecule.padding.left = NS_POINTS_TO_TWIPS_INT(cellPadding); +// mColor.mBackgroundColor = NS_RGB(255, 255, 0); +// mColor.mBackgroundFlags = 0; + mMolecule.border.top = nscoord(1 * p2t); + mMolecule.border.right = nscoord(1 * p2t); + mMolecule.border.bottom = nscoord(1 * p2t); + mMolecule.border.left = nscoord(1 * p2t); + for (int i = 0; i < 4; i++) { + mMolecule.borderStyle[i] = NS_STYLE_BORDER_STYLE_SOLID; + mMolecule.borderColor[i] = NS_RGB(128, 128, 128); + } + mMolecule.fixedWidth = -1; + mMolecule.proportionalWidth = -1; + mMolecule.fixedHeight = -1; + mMolecule.proportionalHeight = -1; + + } else if (buf.EqualsIgnoreCase("COL")) { + mMolecule.fixedWidth = -1; + mMolecule.proportionalWidth = -1; + mMolecule.fixedHeight = -1; + mMolecule.proportionalHeight = -1; + } + } else { + // It's text (!) + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + mMolecule.cursor = NS_STYLE_CURSOR_IBEAM; + nsIContent* content = aParentFrame->GetContent(); + nsIAtom* parentTag = content->GetTag(); + parentTag->ToString(buf); + NS_RELEASE(content); + NS_RELEASE(parentTag); + if (buf.EqualsIgnoreCase("B")) { +// mFont.mFont.size = NS_POINTS_TO_TWIPS_INT(18); +// mFont.mFont.weight = NS_FONT_WEIGHT_BOLD; + } else if (buf.EqualsIgnoreCase("A")) { +// mColor.mColor = NS_RGB(0,0,255); +// mFont.mFont.decorations = NS_FONT_DECORATION_UNDERLINE; + // This simulates a
text inheritance rule
+      // Check the parent of the A
+      nsIFrame* parentParentFrame = aParentFrame->GetGeometricParent();
+      if (nsnull != parentParentFrame) {
+        nsIContent* parentParentContent = parentParentFrame->GetContent();
+        nsIAtom* parentParentTag = parentParentContent->GetTag();
+        parentParentTag->ToString(buf);
+        NS_RELEASE(parentParentTag);
+        NS_RELEASE(parentParentContent);
+        if (buf.EqualsIgnoreCase("PRE")) {
+          mMolecule.whiteSpace = NS_STYLE_WHITESPACE_PRE;
+//          mFont.mFont.name.SetLength(0);
+//          mFont.mFont.name.Append("Courier");
+        }
+      }
+    } else if (buf.EqualsIgnoreCase("THREED")) {
+//      mFont.mFont.size = NS_POINTS_TO_TWIPS_INT(18);
+//      mFont.mFont.weight = NS_FONT_WEIGHT_BOLD;
+      mFont.mThreeD = 1;
+    } else if (buf.EqualsIgnoreCase("I")) {
+//      mFont.mFont.style = NS_FONT_STYLE_ITALIC;
+    } else if (buf.EqualsIgnoreCase("BLINK")) {
+//      mFont.mFont.decorations |= NS_STYLE_TEXT_DECORATION_BLINK;
+    } else if (buf.EqualsIgnoreCase("TT")) {
+//      mFont.mFont.name.SetLength(0);
+//      mFont.mFont.name.Append("Courier");
+    } else if (buf.EqualsIgnoreCase("S")) {
+//      mFont.mFont.decorations = NS_FONT_DECORATION_LINE_THROUGH;
+    } else if (buf.EqualsIgnoreCase("U")) {
+//      mFont.mFont.decorations = NS_FONT_DECORATION_UNDERLINE;
+    } else if (buf.EqualsIgnoreCase("PRE")) {
+      mMolecule.whiteSpace = NS_STYLE_WHITESPACE_PRE;
+//      mFont.mFont.name.SetLength(0);
+//      mFont.mFont.name.Append("Courier");
+    }
+  }
+
+#if 0
+  if ((NS_STYLE_DISPLAY_BLOCK == mMolecule.display) ||
+      (NS_STYLE_DISPLAY_LIST_ITEM == mMolecule.display)) {
+    // Always justify text (take that ie)
+    mMolecule.textAlign = NS_STYLE_TEXT_ALIGN_JUSTIFY;
+  }
+#endif
+
+  mMolecule.borderPadding.top =
+    mMolecule.border.top + mMolecule.padding.top;
+  mMolecule.borderPadding.right =
+    mMolecule.border.right + mMolecule.padding.right;
+  mMolecule.borderPadding.bottom =
+    mMolecule.border.bottom + mMolecule.padding.bottom;
+  mMolecule.borderPadding.left =
+    mMolecule.border.left + mMolecule.padding.left;
+
+}
+
+NS_LAYOUT nsresult
+NS_NewStyleContext(nsIStyleContext** aInstancePtrResult,
+                   nsISupportsArray* aRules,
+                   nsIPresContext* aPresContext,
+                   nsIContent* aContent,
+                   nsIFrame* aParentFrame)
+{
+  NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr");
+  if (nsnull == aInstancePtrResult) {
+    return NS_ERROR_NULL_POINTER;
+  }
+
+  nsIStyleContext* parent = nsnull;
+  if (nsnull != aParentFrame) {
+    parent = aParentFrame->GetStyleContext(aPresContext);
+    NS_ASSERTION(nsnull != parent, "parent frame must have style context");
+  }
+
+  StyleContextImpl* context = new StyleContextImpl(parent, aRules, aPresContext);
+  NS_IF_RELEASE(parent);
+  if (nsnull == context) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  context->HackStyleFor(aPresContext, aContent, aParentFrame);
+
+  return context->QueryInterface(kIStyleContextIID, (void **) aInstancePtrResult);
+}
diff --git a/mozilla/layout/base/src/nsStyleSet.cpp b/mozilla/layout/base/src/nsStyleSet.cpp
new file mode 100644
index 00000000000..156e68bea3c
--- /dev/null
+++ b/mozilla/layout/base/src/nsStyleSet.cpp
@@ -0,0 +1,530 @@
+/* -*- 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 "nsIStyleSet.h"
+#include "nsIStyleSheet.h"
+#include "nsIStyleRule.h"
+#include "nsIStyleContext.h"
+#include "nsISupportsArray.h"
+#include "nsIFrame.h"
+#include "nsHashtable.h"
+
+
+static NS_DEFINE_IID(kIStyleSetIID, NS_ISTYLE_SET_IID);
+
+class ContextKey : public nsHashKey {
+public:
+  ContextKey(nsIStyleContext* aContext);
+  ContextKey(nsIStyleContext* aParent, nsISupportsArray* aRules);
+  ~ContextKey(void);
+
+  void        SetContext(nsIStyleContext* aContext);
+
+  PRBool      Equals(const nsHashKey* aOther) const;
+  PRUint32    HashValue(void) const;
+  nsHashKey*  Clone(void) const;
+
+private:
+  ContextKey(void);
+  ContextKey(const ContextKey& aCopy);
+  ContextKey& operator=(const ContextKey& aCopy) const;
+
+protected:
+  nsIStyleContext* mContext;
+  nsIStyleContext* mParent;
+  nsISupportsArray* mRules;
+};
+
+ContextKey::ContextKey(nsIStyleContext* aContext)
+  : mContext(aContext),
+    mParent(nsnull),
+    mRules(nsnull)
+{
+  NS_IF_ADDREF(mContext);
+}
+
+ContextKey::ContextKey(nsIStyleContext* aParent, nsISupportsArray* aRules)
+  : mContext(nsnull),
+    mParent(aParent),
+    mRules(aRules)
+{
+  NS_IF_ADDREF(mParent);
+  NS_IF_ADDREF(mRules);
+}
+
+ContextKey::ContextKey(const ContextKey& aCopy)
+  : mContext(aCopy.mContext),
+    mParent(aCopy.mParent),
+    mRules(aCopy.mRules)
+{
+  NS_IF_ADDREF(mContext);
+  NS_IF_ADDREF(mParent);
+  NS_IF_ADDREF(mRules);
+}
+
+ContextKey::~ContextKey(void)
+{
+  NS_IF_RELEASE(mContext);
+  NS_IF_RELEASE(mParent);
+  NS_IF_RELEASE(mRules);
+}
+
+void ContextKey::SetContext(nsIStyleContext* aContext)
+{
+  if (aContext != mContext) {
+    NS_IF_RELEASE(mContext);
+    mContext = aContext;
+    NS_IF_ADDREF(mContext);
+  }
+  NS_IF_RELEASE(mParent);
+  NS_IF_RELEASE(mRules);
+}
+
+PRBool ContextKey::Equals(const nsHashKey* aOther) const
+{
+  PRBool result = PR_TRUE;
+  const ContextKey* other = (const ContextKey*)aOther;
+
+  if (other != this) {
+    if ((nsnull == mContext) || (nsnull == other->mContext) || (mContext != other->mContext)) {
+      nsIStyleContext* otherParent = other->mParent;
+      if ((nsnull == otherParent) && (nsnull != other->mContext)) {
+        otherParent = other->mContext->GetParent();
+      }
+      else {
+        NS_IF_ADDREF(otherParent);  // simulate the above addref
+      }
+
+      if (mParent == otherParent) {
+        nsISupportsArray* otherRules = other->mRules;
+        if ((nsnull == otherRules) && (nsnull != other->mContext)) {
+          otherRules = other->mContext->GetStyleRules();
+        }
+        else {
+          NS_IF_ADDREF(otherRules); // simulate the above addref
+        }
+        if ((nsnull != mRules) && (nsnull != otherRules)) {
+          result = mRules->Equals(otherRules);
+        }
+        else {
+          result = PRBool((nsnull == mRules) && (nsnull == otherRules));
+        }
+        NS_IF_RELEASE(otherRules);
+      }
+      else {
+        result = PR_FALSE;
+      }
+      NS_IF_RELEASE(otherParent);
+    }
+  }
+  return result;
+}
+
+PRUint32 ContextKey::HashValue(void) const
+{
+  if (nsnull != mContext) {
+    return mContext->HashValue();
+  }
+  // we don't have a context yet, compute it like it would
+  PRUint32 hashValue = ((nsnull != mParent) ? mParent->HashValue() : 0);
+  if (nsnull != mRules) {
+    PRInt32 index = mRules->Count();
+    while (0 <= --index) {
+      nsIStyleRule* rule = (nsIStyleRule*)mRules->ElementAt(index);
+      PRUint32 hash = rule->HashValue();
+      hashValue ^= (hash & 0x7FFFFFFF);
+      NS_RELEASE(rule);
+    }
+  }
+  return hashValue;
+}
+
+nsHashKey* ContextKey::Clone(void) const
+{
+  return new ContextKey(*this);
+}
+
+
+class StyleSetImpl : public nsIStyleSet {
+public:
+  StyleSetImpl();
+
+  NS_DECL_ISUPPORTS
+
+  virtual void AppendOverrideStyleSheet(nsIStyleSheet* aSheet);
+  virtual void InsertOverrideStyleSheetAfter(nsIStyleSheet* aSheet,
+                                             nsIStyleSheet* aAfterSheet);
+  virtual void InsertOverrideStyleSheetBefore(nsIStyleSheet* aSheet,
+                                              nsIStyleSheet* aBeforeSheet);
+  virtual void RemoveOverrideStyleSheet(nsIStyleSheet* aSheet);
+  virtual PRInt32 GetNumberOfOverrideStyleSheets();
+  virtual nsIStyleSheet* GetOverrideStyleSheetAt(PRInt32 aIndex);
+
+  virtual void AppendDocStyleSheet(nsIStyleSheet* aSheet);
+  virtual void InsertDocStyleSheetAfter(nsIStyleSheet* aSheet,
+                                        nsIStyleSheet* aAfterSheet);
+  virtual void InsertDocStyleSheetBefore(nsIStyleSheet* aSheet,
+                                         nsIStyleSheet* aBeforeSheet);
+  virtual void RemoveDocStyleSheet(nsIStyleSheet* aSheet);
+  virtual PRInt32 GetNumberOfDocStyleSheets();
+  virtual nsIStyleSheet* GetDocStyleSheetAt(PRInt32 aIndex);
+
+  virtual void AppendBackstopStyleSheet(nsIStyleSheet* aSheet);
+  virtual void InsertBackstopStyleSheetAfter(nsIStyleSheet* aSheet,
+                                             nsIStyleSheet* aAfterSheet);
+  virtual void InsertBackstopStyleSheetBefore(nsIStyleSheet* aSheet,
+                                              nsIStyleSheet* aBeforeSheet);
+  virtual void RemoveBackstopStyleSheet(nsIStyleSheet* aSheet);
+  virtual PRInt32 GetNumberOfBackstopStyleSheets();
+  virtual nsIStyleSheet* GetBackstopStyleSheetAt(PRInt32 aIndex);
+
+  virtual nsIStyleContext* ResolveStyleFor(nsIPresContext* aPresContext,
+                                           nsIContent* aContent,
+                                           nsIFrame* aParentFrame);
+
+  // xxx style rules enumeration
+
+  virtual void List(FILE* out = stdout, PRInt32 aIndent = 0);
+
+private:
+  // These are not supported and are not implemented!
+  StyleSetImpl(const StyleSetImpl& aCopy);
+  StyleSetImpl& operator=(const StyleSetImpl& aCopy);
+
+protected:
+  virtual ~StyleSetImpl();
+  PRBool EnsureArray(nsISupportsArray** aArray);
+  PRInt32 RulesMatching(nsISupportsArray* aSheets,
+                        nsIPresContext* aPresContext,
+                        nsIContent* aContent,
+                        nsIFrame* aParentFrame,
+                        nsISupportsArray* aResults);
+  void  List(FILE* out, PRInt32 aIndent, nsISupportsArray* aSheets);
+
+  nsISupportsArray* mOverrideSheets;
+  nsISupportsArray* mDocSheets;
+  nsISupportsArray* mBackstopSheets;
+  nsHashtable mStyleContexts;
+};
+
+
+StyleSetImpl::StyleSetImpl()
+  : mOverrideSheets(nsnull),
+    mDocSheets(nsnull),
+    mBackstopSheets(nsnull)
+{
+  NS_INIT_REFCNT();
+}
+
+PRBool ReleaseContext(nsHashKey *aKey, void *aData)
+{
+  ((nsIStyleContext*)aData)->Release();
+  return PR_TRUE;
+}
+
+StyleSetImpl::~StyleSetImpl()
+{
+  NS_IF_RELEASE(mOverrideSheets);
+  NS_IF_RELEASE(mDocSheets);
+  NS_IF_RELEASE(mBackstopSheets);
+  mStyleContexts.Enumerate(ReleaseContext);
+}
+
+NS_IMPL_ISUPPORTS(StyleSetImpl, kIStyleSetIID)
+
+PRBool StyleSetImpl::EnsureArray(nsISupportsArray** aArray)
+{
+  if (nsnull == *aArray) {
+    if (NS_OK != NS_NewISupportsArray(aArray)) {
+      return PR_FALSE;
+    }
+  }
+  return PR_TRUE;
+}
+
+// ----- Override sheets
+
+void StyleSetImpl::AppendOverrideStyleSheet(nsIStyleSheet* aSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null arg");
+  if (EnsureArray(&mOverrideSheets)) {
+    mOverrideSheets->AppendElement(aSheet);
+  }
+}
+
+void StyleSetImpl::InsertOverrideStyleSheetAfter(nsIStyleSheet* aSheet,
+                                                 nsIStyleSheet* aAfterSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null arg");
+  if (EnsureArray(&mOverrideSheets)) {
+    PRInt32 index = mOverrideSheets->IndexOf(aAfterSheet);
+    mOverrideSheets->InsertElementAt(aSheet, ++index);
+  }
+}
+
+void StyleSetImpl::InsertOverrideStyleSheetBefore(nsIStyleSheet* aSheet,
+                                                  nsIStyleSheet* aBeforeSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null arg");
+  if (EnsureArray(&mOverrideSheets)) {
+    PRInt32 index = mOverrideSheets->IndexOf(aBeforeSheet);
+    mOverrideSheets->InsertElementAt(aSheet, ((-1 < index) ? index : 0));
+  }
+}
+
+void StyleSetImpl::RemoveOverrideStyleSheet(nsIStyleSheet* aSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null arg");
+
+  if (nsnull != mOverrideSheets) {
+    mOverrideSheets->RemoveElement(aSheet);
+  }
+}
+
+PRInt32 StyleSetImpl::GetNumberOfOverrideStyleSheets()
+{
+  if (nsnull != mOverrideSheets) {
+    return mOverrideSheets->Count();
+  }
+  return 0;
+}
+
+nsIStyleSheet* StyleSetImpl::GetOverrideStyleSheetAt(PRInt32 aIndex)
+{
+  nsIStyleSheet* sheet = nsnull;
+  if (nsnull == mOverrideSheets) {
+    sheet = (nsIStyleSheet*)mOverrideSheets->ElementAt(aIndex);
+  }
+  return sheet;
+}
+
+// -------- Doc Sheets
+
+void StyleSetImpl::AppendDocStyleSheet(nsIStyleSheet* aSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null arg");
+  if (EnsureArray(&mDocSheets)) {
+    mDocSheets->AppendElement(aSheet);
+  }
+}
+
+void StyleSetImpl::InsertDocStyleSheetAfter(nsIStyleSheet* aSheet,
+                                         nsIStyleSheet* aAfterSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null arg");
+  if (EnsureArray(&mDocSheets)) {
+    PRInt32 index = mDocSheets->IndexOf(aAfterSheet);
+    mDocSheets->InsertElementAt(aSheet, ++index);
+  }
+}
+
+void StyleSetImpl::InsertDocStyleSheetBefore(nsIStyleSheet* aSheet,
+                                          nsIStyleSheet* aBeforeSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null arg");
+  if (EnsureArray(&mDocSheets)) {
+    PRInt32 index = mDocSheets->IndexOf(aBeforeSheet);
+    mDocSheets->InsertElementAt(aSheet, ((-1 < index) ? index : 0));
+  }
+}
+
+void StyleSetImpl::RemoveDocStyleSheet(nsIStyleSheet* aSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null arg");
+
+  if (nsnull != mDocSheets) {
+    mDocSheets->RemoveElement(aSheet);
+  }
+}
+
+PRInt32 StyleSetImpl::GetNumberOfDocStyleSheets()
+{
+  if (nsnull != mDocSheets) {
+    return mDocSheets->Count();
+  }
+  return 0;
+}
+
+nsIStyleSheet* StyleSetImpl::GetDocStyleSheetAt(PRInt32 aIndex)
+{
+  nsIStyleSheet* sheet = nsnull;
+  if (nsnull == mDocSheets) {
+    sheet = (nsIStyleSheet*)mDocSheets->ElementAt(aIndex);
+  }
+  return sheet;
+}
+
+// ------ backstop sheets
+
+void StyleSetImpl::AppendBackstopStyleSheet(nsIStyleSheet* aSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null arg");
+  if (EnsureArray(&mBackstopSheets)) {
+    mBackstopSheets->AppendElement(aSheet);
+  }
+}
+
+void StyleSetImpl::InsertBackstopStyleSheetAfter(nsIStyleSheet* aSheet,
+                                                 nsIStyleSheet* aAfterSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null arg");
+  if (EnsureArray(&mBackstopSheets)) {
+    PRInt32 index = mBackstopSheets->IndexOf(aAfterSheet);
+    mBackstopSheets->InsertElementAt(aSheet, ++index);
+  }
+}
+
+void StyleSetImpl::InsertBackstopStyleSheetBefore(nsIStyleSheet* aSheet,
+                                                  nsIStyleSheet* aBeforeSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null arg");
+  if (EnsureArray(&mBackstopSheets)) {
+    PRInt32 index = mBackstopSheets->IndexOf(aBeforeSheet);
+    mBackstopSheets->InsertElementAt(aSheet, ((-1 < index) ? index : 0));
+  }
+}
+
+void StyleSetImpl::RemoveBackstopStyleSheet(nsIStyleSheet* aSheet)
+{
+  NS_PRECONDITION(nsnull != aSheet, "null arg");
+
+  if (nsnull != mBackstopSheets) {
+    mBackstopSheets->RemoveElement(aSheet);
+  }
+}
+
+PRInt32 StyleSetImpl::GetNumberOfBackstopStyleSheets()
+{
+  if (nsnull != mBackstopSheets) {
+    return mBackstopSheets->Count();
+  }
+  return 0;
+}
+
+nsIStyleSheet* StyleSetImpl::GetBackstopStyleSheetAt(PRInt32 aIndex)
+{
+  nsIStyleSheet* sheet = nsnull;
+  if (nsnull == mBackstopSheets) {
+    sheet = (nsIStyleSheet*)mBackstopSheets->ElementAt(aIndex);
+  }
+  return sheet;
+}
+
+PRInt32 StyleSetImpl::RulesMatching(nsISupportsArray* aSheets,
+                                    nsIPresContext* aPresContext,
+                                    nsIContent* aContent,
+                                    nsIFrame* aParentFrame,
+                                    nsISupportsArray* aResults)
+{
+  PRInt32 ruleCount = 0;
+
+  if (nsnull != aSheets) {
+    PRInt32 sheetCount = aSheets->Count();
+    PRInt32 index;
+    for (index = 0; index < sheetCount; index++) {
+      nsIStyleSheet* sheet = (nsIStyleSheet*)aSheets->ElementAt(index);
+      ruleCount += sheet->RulesMatching(aPresContext, aContent, aParentFrame,
+                                        aResults);
+      NS_RELEASE(sheet);
+    }
+  }
+  return ruleCount;
+}
+
+nsIStyleContext* StyleSetImpl::ResolveStyleFor(nsIPresContext* aPresContext,
+                                               nsIContent* aContent,
+                                               nsIFrame* aParentFrame)
+{
+  nsIStyleContext*  result = nsnull;
+
+  nsIStyleContext* parentContext = nsnull;
+  
+  if (nsnull != aParentFrame) {
+    parentContext = aParentFrame->GetStyleContext(aPresContext);
+    NS_ASSERTION(nsnull != parentContext, "parent must have style context");
+  }
+
+  // want to check parent frame's context for cached child context first
+
+  // then do a brute force rule search
+
+  nsISupportsArray*  rules = nsnull;
+  if (NS_OK == NS_NewISupportsArray(&rules)) {
+    PRInt32 ruleCount = RulesMatching(mOverrideSheets, aPresContext, aContent, aParentFrame, rules);
+    ruleCount += RulesMatching(mDocSheets, aPresContext, aContent, aParentFrame, rules);
+    ruleCount += RulesMatching(mBackstopSheets, aPresContext, aContent, aParentFrame, rules);
+
+    // then check for cached ruleSet to context or create
+    ContextKey tempKey(parentContext, rules);
+    result = (nsIStyleContext*)mStyleContexts.Get(&tempKey);
+    if (nsnull == result) {
+      if (NS_OK == NS_NewStyleContext(&result, rules, aPresContext, aContent, aParentFrame)) {
+        tempKey.SetContext(result);
+        mStyleContexts.Put(&tempKey, result);  // hashtable clones key, so this is OK (table gets first ref)
+        NS_ADDREF(result);  // add ref for the caller
+//fprintf(stdout, "+");
+      }
+    }
+    else {
+      NS_ADDREF(result);
+//fprintf(stdout, "-");
+    }
+    NS_RELEASE(rules);
+  }
+
+  NS_IF_RELEASE(parentContext);
+
+  return result;
+}
+
+// xxx style rules enumeration
+
+void StyleSetImpl::List(FILE* out, PRInt32 aIndent, nsISupportsArray* aSheets)
+{
+  PRInt32 count = ((nsnull != aSheets) ? aSheets->Count() : 0);
+
+  for (PRInt32 index = 0; index < count; index++) {
+    nsIStyleSheet* sheet = (nsIStyleSheet*)aSheets->ElementAt(index);
+    sheet->List(out, aIndent);
+    fputs("\n", out);
+    NS_RELEASE(sheet);
+  }
+}
+
+void StyleSetImpl::List(FILE* out, PRInt32 aIndent)
+{
+  List(out, aIndent, mOverrideSheets);
+  List(out, aIndent, mDocSheets);
+  List(out, aIndent, mBackstopSheets);
+}
+
+
+NS_LAYOUT nsresult
+NS_NewStyleSet(nsIStyleSet** aInstancePtrResult)
+{
+  if (aInstancePtrResult == nsnull) {
+    return NS_ERROR_NULL_POINTER;
+  }
+
+  StyleSetImpl  *it = new StyleSetImpl();
+
+  if (nsnull == it) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  return it->QueryInterface(kIStyleSetIID, (void **) aInstancePtrResult);
+}
diff --git a/mozilla/layout/base/tests/Makefile b/mozilla/layout/base/tests/Makefile
new file mode 100644
index 00000000000..12358087090
--- /dev/null
+++ b/mozilla/layout/base/tests/Makefile
@@ -0,0 +1,22 @@
+#!gmake
+#
+# 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.
+
+DEPTH = ../../..
+
+include $(DEPTH)/config/config.mk
+
+include $(DEPTH)/config/rules.mk
diff --git a/mozilla/layout/base/tests/TestContainerFrame.cpp b/mozilla/layout/base/tests/TestContainerFrame.cpp
new file mode 100644
index 00000000000..de6a9b11616
--- /dev/null
+++ b/mozilla/layout/base/tests/TestContainerFrame.cpp
@@ -0,0 +1,665 @@
+/* -*- 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 
+#include "nscore.h"
+#include "nsCRT.h"
+#include "nscoord.h"
+#include "nsContainerFrame.h"
+#include "nsIContent.h"
+
+static NS_DEFINE_IID(kIContentIID, NS_ICONTENT_IID);
+
+///////////////////////////////////////////////////////////////////////////////
+// Helper functions
+
+// Compute the number of frames in the list
+static PRInt32
+LengthOf(nsIFrame* aChildList)
+{
+  PRInt32 result = 0;
+
+  while (nsnull != aChildList) {
+    aChildList = aChildList->GetNextSibling();
+    result++;
+  }
+
+  return result;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+
+class SimpleContent : public nsIContent {
+public:
+  SimpleContent();
+
+  nsIDocument* GetDocument() const {return mDocument;}
+  void         SetDocument(nsIDocument* aDocument) {mDocument = aDocument;}
+
+  nsIContent* GetParent() const { return nsnull; }
+  void SetParent(nsIContent* aParent) {}
+
+  PRBool       CanContainChildren() const {return PR_FALSE;}
+  PRInt32      ChildCount() const {return 0;}
+  nsIContent*  ChildAt(PRInt32 aIndex) const {return nsnull;}
+  PRInt32      IndexOf(nsIContent* aPossibleChild) const {return -1;}
+  PRBool       InsertChildAt(nsIContent* aKid, PRInt32 aIndex) {return PR_FALSE;}
+  PRBool       ReplaceChildAt(nsIContent* aKid, PRInt32 aIndex) {return PR_FALSE;}
+  PRBool       AppendChild(nsIContent* aKid) {return PR_FALSE;}
+  PRBool       RemoveChildAt(PRInt32 aIndex) {return PR_FALSE;}
+
+  nsIAtom* GetTag() const {return nsnull;}
+  void     SetAttribute(const nsString& aName,const nsString& aValue) {;}
+  nsContentAttr GetAttribute(const nsString& aName, nsString& aRet) const {return eContentAttr_NotThere;}
+
+  nsIContentDelegate* GetDelegate(nsIPresContext* aCX) {return nsnull;}
+
+  void List(FILE* out = stdout, PRInt32 aIndent = 0) const {;}
+  PRUint32 SizeOf(nsISizeofHandler* aHandler) const { return 0; }
+
+  NS_DECL_ISUPPORTS
+
+protected:
+  nsIDocument*  mDocument;
+};
+
+SimpleContent::SimpleContent()
+{
+}
+
+NS_IMPL_ISUPPORTS(SimpleContent, kIContentIID);
+
+///////////////////////////////////////////////////////////////////////////////
+//
+
+class SimpleContainer : public nsContainerFrame
+{
+public:
+  SimpleContainer(nsIContent* aContent, PRInt32 aIndexInParent);
+
+  ReflowStatus IncrementalReflow(nsIPresContext*  aPresContext,
+                                 nsReflowMetrics& aDesiredSize,
+                                 const nsSize&    aMaxSize,
+                                 nsReflowCommand& aReflowCommand);
+
+  void      SetFirstChild(nsIFrame* aChild, PRInt32 aChildCount);
+  nsIFrame* GetOverflowList() {return mOverflowList;}
+  void      SetOverflowList(nsIFrame* aChildList) {mOverflowList = aChildList;}
+
+  // Allow public access to protected member functions
+  void PushChildren(nsIFrame* aFromChild, nsIFrame* aPrevSibling, PRBool aLastIsComplete);
+  PRBool DeleteChildsNextInFlow(nsIFrame* aChild);
+};
+
+SimpleContainer::SimpleContainer(nsIContent* aContent, PRInt32 aIndexInParent)
+  : nsContainerFrame(aContent, aIndexInParent, nsnull)
+{
+}
+
+nsIFrame::ReflowStatus
+SimpleContainer::IncrementalReflow(nsIPresContext*  aPresContext,
+                                   nsReflowMetrics& aDesiredSize,
+                                   const nsSize&    aMaxSize,
+                                   nsReflowCommand& aReflowCommand)
+{
+  NS_NOTYETIMPLEMENTED("incremental reflow");
+  return frComplete;
+}
+
+// Sets mFirstChild and mChildCount, but not mContentOffset, mContentLength,
+// or mLastContentIsComplete
+void SimpleContainer::SetFirstChild(nsIFrame* aChild, PRInt32 aChildCount)
+{
+  mFirstChild = aChild;
+  mChildCount = aChildCount;
+  NS_ASSERTION(LengthOf(mFirstChild) == aChildCount, "bad child count argument");
+}
+
+void SimpleContainer::PushChildren(nsIFrame* aFromChild, nsIFrame* aPrevSibling, PRBool aLastIsComplete)
+{
+  nsContainerFrame::PushChildren(aFromChild, aPrevSibling, aLastIsComplete);
+}
+
+PRBool SimpleContainer::DeleteChildsNextInFlow(nsIFrame* aChild)
+{
+  return nsContainerFrame::DeleteChildsNextInFlow(aChild);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+
+class SimpleSplittableFrame : public nsSplittableFrame {
+public:
+  SimpleSplittableFrame(nsIContent* aContent,
+                        PRInt32     aIndexInParent,
+                        nsIFrame*   aParent);
+};
+
+SimpleSplittableFrame::SimpleSplittableFrame(nsIContent* aContent,
+                                             PRInt32     aIndexInParent,
+                                             nsIFrame*   aParent)
+  : nsSplittableFrame(aContent, aIndexInParent, aParent)
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+
+// Basic test of the child enumeration member functions
+static PRBool
+TestChildEnumeration()
+{
+  // Create a simple test container
+  SimpleContainer* f = new SimpleContainer(new SimpleContent(), 0);
+
+  // Add three child frames
+  SimpleContent* childContent = new SimpleContent();
+  nsFrame*       c1;
+  nsFrame*       c2;
+  nsFrame*       c3;
+
+  nsFrame::NewFrame((nsIFrame**)&c1, childContent, 0, f);
+  nsFrame::NewFrame((nsIFrame**)&c2, childContent, 1, f);
+  nsFrame::NewFrame((nsIFrame**)&c3, childContent, 2, f);
+
+  c1->SetNextSibling(c2);
+  c2->SetNextSibling(c3);
+  f->SetFirstChild(c1, 3);
+  f->SetLastContentOffset(2);
+
+  // Make sure the child count is correct
+  if (f->ChildCount() != 3) {
+    printf("ChildEnumeration: wrong child count: %d\n", f->ChildCount());
+    return PR_FALSE;
+  }
+
+  // Test indexing of child frames. nsnull should be returned for index
+  // values that are out of range
+  if (nsnull != f->ChildAt(-1)) {
+    printf("ChildEnumeration: child index failed for index < 0\n");
+    return PR_FALSE;
+  }
+  if (c1 != f->ChildAt(0)) {
+    printf("ChildEnumeration: wrong child at index: %d\n", 0);
+    return PR_FALSE;
+  }
+  if (c2 != f->ChildAt(1)) {
+    printf("ChildEnumeration: wrong child at index: %d\n", 1);
+    return PR_FALSE;
+  }
+  if (c3 != f->ChildAt(2)) {
+    printf("ChildEnumeration: wrong child at index: %d\n", 2);
+    return PR_FALSE;
+  }
+  if (nsnull != f->ChildAt(3)) {
+    printf("ChildEnumeration: child index failed for index >= child countn");
+    return PR_FALSE;
+  }
+
+  // Test first and last child member functions
+  if (f->FirstChild() != c1) {
+    printf("ChildEnumeration: wrong first child\n");
+    return PR_FALSE;
+  }
+  if (f->LastChild() != c3) {
+    printf("ChildEnumeration: wrong last child\n");
+    return PR_FALSE;
+  }
+
+  // Test IndexOf()
+  if ((f->IndexOf(c1) != 0) || (f->IndexOf(c2) != 1) || (f->IndexOf(c3) != 2)) {
+    printf("ChildEnumeration: index of failed\n");
+    return PR_FALSE;
+  }
+
+  return PR_TRUE;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+
+// Test the push children method
+//
+// This tests the following:
+// 1. pushing children to the overflow list when there's no next-in-flow
+// 2. pushing to a next-in-flow that's empty
+// 3. pushing to a next-in-flow that isn't empty
+static PRBool
+TestPushChildren()
+{
+  // Create a simple test container
+  SimpleContainer* f = new SimpleContainer(new SimpleContent(), 0);
+
+  // Add five child frames
+  SimpleContent* childContent = new SimpleContent();
+  nsFrame*       c1;
+  nsFrame*       c2;
+  nsFrame*       c3;
+  nsFrame*       c4;
+  nsFrame*       c5;
+
+  nsFrame::NewFrame((nsIFrame**)&c1, childContent, 0, f);
+  nsFrame::NewFrame((nsIFrame**)&c2, childContent, 1, f);
+  nsFrame::NewFrame((nsIFrame**)&c3, childContent, 2, f);
+  nsFrame::NewFrame((nsIFrame**)&c4, childContent, 3, f);
+  nsFrame::NewFrame((nsIFrame**)&c5, childContent, 4, f);
+
+  c1->SetNextSibling(c2);
+  c2->SetNextSibling(c3);
+  c3->SetNextSibling(c4);
+  c4->SetNextSibling(c5);
+  f->SetFirstChild(c1, 5);
+  f->SetLastContentOffset(4);
+
+  ///////////////////////////////////////////////////////////////////////////
+  // #1
+
+  // Push the last two children. Since there's no next-in-flow the children
+  // should be placed on the overflow list
+  f->PushChildren(c4, c3, PR_TRUE);
+
+  // Verify that the next sibling pointer of c3 has been cleared
+  if (nsnull != c3->GetNextSibling()) {
+    printf("PushChildren: sibling pointer isn't null\n");
+    return PR_FALSE;
+  }
+
+  // Verify that there are two frames on the overflow list
+  nsIFrame* overflowList = f->GetOverflowList();
+  if ((nsnull == overflowList) || (LengthOf(overflowList) != 2)) {
+    printf("PushChildren: bad overflow list\n");
+    return PR_FALSE;
+  }
+
+  // and that the children on the overflow still have the same geometric parent
+  while (nsnull != overflowList) {
+    if (f != overflowList->GetGeometricParent()) {
+      printf("PushChildren: bad geometric parent\n");
+      return PR_FALSE;
+    }
+
+    overflowList = overflowList->GetNextSibling();
+  }
+
+  ///////////////////////////////////////////////////////////////////////////
+  // #2
+
+  // Link the overflow list back into the child list
+  c3->SetNextSibling(f->GetOverflowList());
+  f->SetOverflowList(nsnull);
+
+  // Create a continuing frame
+  SimpleContainer* f1 = new SimpleContainer(f->GetContent(), 0);
+
+  // Link it into the flow
+  f->SetNextInFlow(f1);
+  f1->SetPrevInFlow(f);
+
+  // Push the last two children to the next-in-flow which is empty.
+  f->PushChildren(c4, c3, PR_TRUE);
+
+  // Verify there are two children in f1
+  if (f1->ChildCount() != 2) {
+    printf("PushChildren: continuing frame bad child count: %d\n", f1->ChildCount());
+    return PR_FALSE;
+  }
+
+  // Verify the content offsets are correct
+  if ((f1->GetFirstContentOffset() != 3) || (f1->GetLastContentOffset() != 4)) {
+    printf("PushChildren: continuing frame bad mapping\n");
+    return PR_FALSE;
+  }
+
+  // Verify that the first child is correct
+  if (c4 != f1->FirstChild()) {
+    printf("PushChildren: continuing frame first child is wrong\n");
+    return PR_FALSE;
+  }
+
+  // Verify that the next sibling pointer of c3 has been cleared
+  if (nsnull != c3->GetNextSibling()) {
+    printf("PushChildren: sibling pointer isn't null\n");
+    return PR_FALSE;
+  }
+
+  // Verify that the geometric parent and content parent have been changed
+  nsIFrame* firstChild = f1->FirstChild();
+  while (nsnull != firstChild) {
+    if (f1 != firstChild->GetGeometricParent()) {
+      printf("PushChildren: bad geometric parent\n");
+      return PR_FALSE;
+    }
+
+    if (f1 != firstChild->GetContentParent()) {
+      printf("PushChildren: bad content parent\n");
+      return PR_FALSE;
+    }
+
+    firstChild = firstChild->GetNextSibling();
+  }
+
+  ///////////////////////////////////////////////////////////////////////////
+  // #3
+
+  // Test pushing two children to a next-in-flow that already has children
+  f->PushChildren(c2, c1, PR_TRUE);
+
+  // Verify there are four children in f1
+  if (f1->ChildCount() != 4) {
+    printf("PushChildren: continuing frame bad child count: %d\n", f1->ChildCount());
+    return PR_FALSE;
+  }
+
+  // Verify the content offset/length are correct
+  if ((f1->GetFirstContentOffset() != 1) || (f1->GetLastContentOffset() != 4)) {
+    printf("PushChildren: continuing frame bad mapping\n");
+    return PR_FALSE;
+  }
+
+  // Verify that the first child is correct
+  if (c2 != f1->FirstChild()) {
+    printf("PushChildren: continuing frame first child is wrong\n");
+    return PR_FALSE;
+  }
+
+  // Verify that c3 points to c4
+  if (c4 != c3->GetNextSibling()) {
+    printf("PushChildren: bad sibling pointers\n");
+    return PR_FALSE;
+  }
+
+  return PR_TRUE;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+
+// Test the delete child's next-in-flow method
+//
+// This tests the following:
+// 1. one next-in-flow in same geometric parent
+//   a) next-in-flow is parent's last child
+//   b) next-in-flow is not the parent's last child
+// 2. one next-in-flow in different geometric parents
+//   a) next-in-flow is parent's first and last child
+//   b) next-in-flow is not the parent's last child
+// 3. multiple next-in-flow frames
+static PRBool
+TestDeleteChildsNext()
+{
+  // Create two simple test containers
+  SimpleContainer* f = new SimpleContainer(new SimpleContent(), 0);
+
+  // Create two child frames
+  SimpleContent* childContent = new SimpleContent();
+  nsFrame*       c1 = new SimpleSplittableFrame(childContent, 0, f);
+  nsFrame*       c11 = new SimpleSplittableFrame(childContent, 0, f);
+
+  ///////////////////////////////////////////////////////////////////////////
+  // #1a
+
+  // Make the child frames siblings and in the same flow
+  c1->SetNextSibling(c11);
+  c11->AppendToFlow(c1);
+  f->SetFirstChild(c1, 2);
+
+  // Delete the next-in-flow
+  f->DeleteChildsNextInFlow(c1);
+
+  // Verify the child count
+  if (f->ChildCount() != 1) {
+    printf("DeleteNextInFlow: bad child count (#1a): %d\n", f->ChildCount());
+    return PR_FALSE;
+  }
+
+  // Verify the sibling pointer is null
+  if (nsnull != c1->GetNextSibling()) {
+    printf("DeleteNextInFlow: bad sibling pointer (#1a):\n");
+    return PR_FALSE;
+  }
+
+  // Verify the next-in-flow pointer is null
+  if (nsnull != c1->GetNextInFlow()) {
+    printf("DeleteNextInFlow: bad next-in-flow (#1a)\n");
+    return PR_FALSE;
+  }
+
+  // Verify the first/last content offsets are still 0
+  if ((f->GetFirstContentOffset() != 0) || (f->GetLastContentOffset() != 0)) {
+    printf("DeleteNextInFlow: bad content mapping (#1a)\n");
+    return PR_FALSE;
+  }
+
+  ///////////////////////////////////////////////////////////////////////////
+  // #2a
+
+  // Create a second container frame
+  SimpleContainer* f1 = new SimpleContainer(new SimpleContent(), 0);
+
+  // Re-create the continuing child frame
+  c11 = new SimpleSplittableFrame(childContent, 0, f1);
+
+  // Put the first child in the first container and the continuing child frame in
+  // the second container
+  c11->AppendToFlow(c1);
+  f->SetFirstChild(c1, 1);
+  f->SetLastContentOffset(0);
+  f1->SetFirstChild(c11, 1);
+
+  // Link the containers together
+  f1->AppendToFlow(f);
+
+  // Delete the next-in-flow
+  f->DeleteChildsNextInFlow(c1);
+
+  // Verify that the second container frame is empty
+  if ((f1->ChildCount() != 0) || (f1->FirstChild() != nsnull)) {
+    printf("DeleteNextInFlow: continuing frame not empty (#2a)\n");
+    return PR_FALSE;
+  }
+
+  // Verify the next-in-flow pointer is null
+  if (nsnull != c1->GetNextInFlow()) {
+    printf("DeleteNextInFlow: bad next-in-flow (#1b)\n");
+    return PR_FALSE;
+  }
+
+  ///////////////////////////////////////////////////////////////////////////
+  // #1b
+
+  // Re-create the continuing child frame
+  c11 = new SimpleSplittableFrame(childContent, 0, f);
+
+  // Create a third child frame
+  nsFrame*  c2 = new SimpleSplittableFrame(childContent, 1, f);
+
+  c1->SetNextSibling(c11);
+  c11->AppendToFlow(c1);
+  c11->SetNextSibling(c2);
+  f->SetFirstChild(c1, 3);
+  f->SetLastContentOffset(1);
+
+  // Delete the next-in-flow
+  f->DeleteChildsNextInFlow(c1);
+
+  // Verify the child count
+  if (f->ChildCount() != 2) {
+    printf("DeleteNextInFlow: bad child count (#1b): %d\n", f->ChildCount());
+    return PR_FALSE;
+  }
+
+  // Verify the sibling pointer is correct
+  if (c1->GetNextSibling() != c2) {
+    printf("DeleteNextInFlow: bad sibling pointer (#1b):\n");
+    return PR_FALSE;
+  }
+
+  // Verify the next-in-flow pointer is correct
+  if (nsnull != c1->GetNextInFlow()) {
+    printf("DeleteNextInFlow: bad next-in-flow (#1b)\n");
+    return PR_FALSE;
+  }
+
+  // Verify the first/last content offsets are correct
+  if ((f->GetFirstContentOffset() != 0) || (f->GetLastContentOffset() != 1)) {
+    printf("DeleteNextInFlow: bad content mapping (#1a)\n");
+    return PR_FALSE;
+  }
+
+  ///////////////////////////////////////////////////////////////////////////
+  // #2b
+
+  // Re-create the continuing frame and the third child frame
+  c11 = new SimpleSplittableFrame(childContent, 0, f1);
+  c2 = new SimpleSplittableFrame(childContent, 1, f1);
+
+  // Put the first child in the first container, and the continuing child frame
+  // and the third frame in the second container
+  c1->SetNextSibling(nsnull);
+  c11->AppendToFlow(c1);
+  f->SetFirstChild(c1, 1);
+  f->SetLastContentOffset(0);
+
+  c11->SetNextSibling(c2);
+  f1->SetFirstChild(c11, 2);
+  f1->SetFirstContentOffset(0);
+  f1->SetLastContentOffset(1);
+
+  // Link the containers together
+  f1->AppendToFlow(f);
+
+  // Delete the next-in-flow
+  f->DeleteChildsNextInFlow(c1);
+
+  // Verify the next-in-flow pointer is null
+  if (nsnull != c1->GetNextInFlow()) {
+    printf("DeleteNextInFlow: bad next-in-flow (#2b)\n");
+    return PR_FALSE;
+  }
+
+  // Verify that the second container frame has one child
+  if (f1->ChildCount() != 1) {
+    printf("DeleteNextInFlow: continuing frame bad child count (#2b): %d\n", f1->ChildCount());
+    return PR_FALSE;
+  }
+
+  // Verify that the second container's first child is correct
+  if (f1->FirstChild() != c2) {
+    printf("DeleteNextInFlow: continuing frame bad first child (#2b)\n");
+    return PR_FALSE;
+  }
+
+  // Verify the second container's first content offset
+  if (f1->GetFirstContentOffset() != 1) {
+    printf("DeleteNextInFlow: continuing frame bad first content offset (#2b): %d\n",
+           f1->GetFirstContentOffset());
+    return PR_FALSE;
+  }
+
+  ///////////////////////////////////////////////////////////////////////////
+  // #3
+
+  // Re-create the continuing frame and the third child frame
+  c11 = new SimpleSplittableFrame(childContent, 0, f);
+  c2 = new SimpleSplittableFrame(childContent, 1, f);
+
+  // Create a second continuing frame
+  SimpleSplittableFrame*  c12 = new SimpleSplittableFrame(childContent, 0, f);
+
+  // Put all the child frames in the first container
+  c1->SetNextSibling(c11);
+  c11->SetNextSibling(c12);
+  c12->SetNextSibling(c2);
+  c11->AppendToFlow(c1);
+  c12->AppendToFlow(c11);
+  f->SetFirstChild(c1, 4);
+  f->SetLastContentOffset(1);
+
+  // Delete the next-in-flow
+  f->DeleteChildsNextInFlow(c1);
+
+  // Verify the next-in-flow pointer is null
+  if (nsnull != c1->GetNextInFlow()) {
+    printf("DeleteNextInFlow: bad next-in-flow (#3)\n");
+    return PR_FALSE;
+  }
+
+  // Verify the child count is correct
+  if (f->ChildCount() != 2) {
+    printf("DeleteNextInFlow: bad child count (#3): %d\n", f->ChildCount());
+    return PR_FALSE;
+  }
+
+  // and the last content offset is still correct
+  if (f->GetLastContentOffset() != 1) {
+    printf("DeleteNextInFlow: bad last content offset (#3): %d\n", f->GetLastContentOffset());
+    return PR_FALSE;
+  }
+
+  // Verify the sibling list is correct
+  if ((c1->GetNextSibling() != c2) || (c2->GetNextSibling()!= nsnull)) {
+    printf("DeleteNextInFlow: bad sibling list (#3)\n");
+    return PR_FALSE;
+  }
+
+  // Verify the next-in-flow pointer is null
+  if (nsnull != c1->GetNextInFlow()) {
+    printf("DeleteNextInFlow: bad next-in-flow (#3)\n");
+    return PR_FALSE;
+  }
+
+  return PR_TRUE;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+
+// Test the container frame being used as a pseudo frame
+static PRBool
+TestAsPseudo()
+{
+  return PR_TRUE;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+
+int main(int argc, char** argv)
+{
+  // Test the child frame enumeration member functions
+  if (!TestChildEnumeration()) {
+    return -1;
+  }
+
+  // Test the push children method
+  if (!TestPushChildren()) {
+    return -1;
+  }
+
+  // Test the push children method
+  if (!TestDeleteChildsNext()) {
+    return -1;
+  }
+
+  // Test being used as a pseudo frame
+  if (!TestAsPseudo()) {
+    return -1;
+  }
+
+  return 0;
+}
diff --git a/mozilla/layout/base/tests/makefile.win b/mozilla/layout/base/tests/makefile.win
new file mode 100644
index 00000000000..c09afa47309
--- /dev/null
+++ b/mozilla/layout/base/tests/makefile.win
@@ -0,0 +1,56 @@
+#!nmake
+#
+# 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.
+
+DEPTH=..\..\..
+IGNORE_MANIFEST=1
+
+MAKE_OBJ_TYPE	= EXE
+PROG1 = .\$(OBJDIR)\TestContainerFrame.exe
+PROGRAMS = $(PROG1)
+
+LINCS=-I$(PUBLIC)\xpcom -I$(PUBLIC)\raptor -I..\src
+LLIBS=				\
+ $(DIST)\lib\raptorlayout_s.lib	\
+ $(DIST)\lib\raptorgfx.lib	\
+ $(DIST)\lib\raptorbase.lib	\
+ $(DIST)\lib\xpcom32.lib	\
+ $(DIST)\lib\jsdom.lib		        \
+ $(LIBNSPR)			\
+ $(DIST)\lib\libplc21.lib
+
+include <$(DEPTH)\config\rules.mak>
+
+install:: $(PROGRAMS)
+	$(MAKE_INSTALL) $(PROG1) $(DIST)\bin
+
+# Move this into config/obj.inc when it's allowed
+.cpp{.\$(OBJDIR)\}.exe:
+    -$(CC) @<<$(CFGFILE)
+        $(CFLAGS)
+        $(LCFLAGS)
+        $(LINCS)
+        $(LINCS_1)
+        $(INCS)
+        $(LLIBS)
+        $(OS_LIBS)
+        -Fd$(PBDFILE)
+        -Fe.\$(OBJDIR)\
+        -Fo.\$(OBJDIR)\
+        $(CURDIR)$(*B).cpp
+<
+
+install:: $(DLL)
+	$(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).dll $(DIST)\bin
+	$(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).lib $(DIST)\lib
+
+clobber::
+	rm -f $(DIST)\bin\$(DLLNAME).dll
+	rm -f $(DIST)\lib\$(DLLNAME).lib
diff --git a/mozilla/layout/generic/nsBlockFrame.cpp b/mozilla/layout/generic/nsBlockFrame.cpp
new file mode 100644
index 00000000000..de26654f45d
--- /dev/null
+++ b/mozilla/layout/generic/nsBlockFrame.cpp
@@ -0,0 +1,2030 @@
+/* -*- 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 "nsBlockFrame.h"
+#include "nsSize.h"
+#include "nsIAnchoredItems.h"
+#include "nsIContent.h"
+#include "nsIContentDelegate.h"
+#include "nsISpaceManager.h"
+#include "nsIStyleContext.h"
+#include "nsStyleConsts.h"
+#include "nsIPresContext.h"
+#include "nsMargin.h"
+#include "nsHTMLIIDs.h"
+#include "nsCSSLayout.h"
+#include "nsCRT.h"
+#include "nsIPresShell.h"
+#include "nsReflowCommand.h"
+#include "nsPlaceholderFrame.h"
+#include "nsHTMLAtoms.h"
+#include "nsHTMLValue.h"
+#include "nsIHTMLContent.h"
+
+#ifdef NS_DEBUG
+#undef NOISY
+#undef NOISY_FLOW
+#else
+#undef NOISY
+#undef NOISY_FLOW
+#endif
+
+static NS_DEFINE_IID(kIRunaroundIID, NS_IRUNAROUND_IID);
+static NS_DEFINE_IID(kIFloaterContainerIID, NS_IFLOATERCONTAINER_IID);
+static NS_DEFINE_IID(kIAnchoredItemsIID, NS_IANCHOREDITEMS_IID);
+static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID);
+static NS_DEFINE_IID(kStyleFontSID, NS_STYLEFONT_SID);
+
+struct BlockBandData : public nsBandData {
+  nsRect  data[5];
+
+  BlockBandData() {size = 5; rects = data;}
+};
+
+// XXX Bugs
+// 1. right to left reflow can generate negative x coordinates.
+
+// XXX Speedup idea (all containers)
+
+// If I reflow a child and it gives back not-complete status then
+// there is no sense in trying to pullup children. For blocks, it's a
+// little more complicated unless the child is a block - if the child
+// is a block, then we must be out of room hence we should stop. If
+// the child is not a block then our line should be flushed (see #2
+// below) if our line is already empty then we must be out of room.
+
+// For inline frames and column frames, if we reflow a child and get
+// back not-complete status then we should bail immediately because we
+// are out of room.
+
+// XXX Speedup ideas:
+// 1. change pullup code to use line information from next in flow
+// 2. we can advance to next line immediately after reflowing something
+//    and noticing that it's not complete.
+// 3. pass down last child information in aState so that pullup, etc.,
+//    don't need to recompute it
+
+// XXX TODO:
+// 0. Move justification into line flushing code
+
+// 1. To get ebina margins I need "auto" information from the style
+//    system margin's. A bottom/top margin of auto will then be computed like
+//    ebina computes it [however the heck that is].
+
+// 2. kicking out floaters and talking with floater container to adjust
+//    left and right margins
+
+nsBlockReflowState::nsBlockReflowState()
+{
+}
+
+void nsBlockReflowState::Init(const nsSize& aMaxSize,
+                              nsSize* aMaxElementSize,
+                              nsStyleFont* aFont,
+                              nsStyleMolecule* aMol,
+                              nsISpaceManager* aSpaceManager)
+{
+  firstLine = PR_TRUE;
+  allowLeadingWhitespace = PR_FALSE;
+  breakAfterChild = PR_FALSE;
+  breakBeforeChild = PR_FALSE;
+  firstChildIsInsideBullet = PR_FALSE;
+  nextListOrdinal = -1;
+  column = 0;
+
+  spaceManager = aSpaceManager;
+  currentBand = new BlockBandData;
+  font = aFont;
+  mol = aMol;
+  availSize.width = aMaxSize.width;
+  availSize.height = aMaxSize.height;
+  maxElementSize = aMaxElementSize;
+  if (nsnull != aMaxElementSize) {
+    aMaxElementSize->width = 0;
+    aMaxElementSize->height = 0;
+  }
+
+  kidXMost = 0;
+  x = 0;
+  y = 0;
+
+  isInline = PR_FALSE;
+  currentLineNumber = 0;
+  lineStart = nsnull;
+  lineLength = 0;
+  ascents = ascentBuf;
+  maxAscent = 0;
+  maxDescent = 0;
+  lineWidth = 0;
+  maxPosBottomMargin = 0;
+  maxNegBottomMargin = 0;
+  lineMaxElementSize.width = 0;
+  lineMaxElementSize.height = 0;
+  lastContentIsComplete = PR_TRUE;
+
+  maxAscents = sizeof(ascentBuf) / sizeof(ascentBuf[0]);
+  needRelativePos = PR_FALSE;
+
+  prevLineLastFrame = nsnull;
+  prevLineHeight = 0;
+  topMargin = 0;
+  prevMaxPosBottomMargin = 0;
+  prevMaxNegBottomMargin = 0;
+  prevLineLastContentIsComplete = PR_TRUE;
+
+  unconstrainedWidth = PRBool(aMaxSize.width == NS_UNCONSTRAINEDSIZE);
+  unconstrainedHeight = PRBool(aMaxSize.height == NS_UNCONSTRAINEDSIZE);
+
+  justifying = (NS_STYLE_TEXT_ALIGN_JUSTIFY == mol->textAlign) &&
+    (NS_STYLE_WHITESPACE_PRE != mol->whiteSpace);
+  reflowStatus = nsIFrame::frNotComplete;
+}
+
+nsBlockReflowState::~nsBlockReflowState()
+{
+  if (ascents != ascentBuf) {
+    delete ascents;
+  }
+  delete currentBand;
+}
+
+void nsBlockReflowState::AddAscent(nscoord aAscent)
+{
+  NS_PRECONDITION(lineLength <= maxAscents, "bad line length");
+  if (lineLength == maxAscents) {
+    maxAscents *= 2;
+    nscoord* newAscents = new nscoord[maxAscents];
+    if (nsnull != newAscents) {
+      nsCRT::memcpy(newAscents, ascents, sizeof(nscoord) * lineLength);
+      if (ascents != ascentBuf) {
+        delete ascents;
+      }
+      ascents = newAscents;
+    } else {
+      // Yikes! Out of memory!
+      return;
+    }
+  }
+  ascents[lineLength] = aAscent;
+}
+
+void nsBlockReflowState::AdvanceToNextLine(nsIFrame* aPrevLineLastFrame,
+                                           nscoord   aPrevLineHeight)
+{
+  firstLine = PR_FALSE;
+  allowLeadingWhitespace = PR_FALSE;
+  column = 0;
+  breakAfterChild = PR_FALSE;
+  breakBeforeChild = PR_FALSE;
+  lineStart = nsnull;
+  lineLength = 0;
+  currentLineNumber++;
+  maxAscent = 0;
+  maxDescent = 0;
+  lineWidth = 0;
+  needRelativePos = PR_FALSE;
+
+  prevLineLastFrame = aPrevLineLastFrame;
+  prevLineHeight = aPrevLineHeight;
+  prevMaxPosBottomMargin = maxPosBottomMargin;
+  prevMaxNegBottomMargin = maxNegBottomMargin;
+
+  // Remember previous line's lastContentIsComplete
+  prevLineLastContentIsComplete = lastContentIsComplete;
+  lastContentIsComplete = PR_TRUE;
+
+  topMargin = 0;
+  maxPosBottomMargin = 0;
+  maxNegBottomMargin = 0;
+}
+
+#ifdef NS_DEBUG
+void nsBlockReflowState::DumpLine()
+{
+  nsIFrame* f = lineStart;
+  PRInt32 ll = lineLength;
+  while (--ll >= 0) {
+    printf("  ");
+    ((nsFrame*)f)->ListTag(stdout);/* XXX */
+    printf("\n");
+    f = f->GetNextSibling();
+  }
+}
+
+void nsBlockReflowState::DumpList()
+{
+  nsIFrame* f = lineStart;
+  while (nsnull != f) {
+    printf("  ");
+    ((nsFrame*)f)->ListTag(stdout);/* XXX */
+    printf("\n");
+    f = f->GetNextSibling();
+  }
+}
+#endif
+
+//----------------------------------------------------------------------
+
+nsresult nsBlockFrame::NewFrame(nsIFrame** aInstancePtrResult,
+                                nsIContent* aContent,
+                                PRInt32     aIndexInParent,
+                                nsIFrame*   aParent)
+{
+  NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr");
+  if (nsnull == aInstancePtrResult) {
+    return NS_ERROR_NULL_POINTER;
+  }
+  nsIFrame* it = new nsBlockFrame(aContent, aIndexInParent, aParent);
+  if (nsnull == it) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  *aInstancePtrResult = it;
+  return NS_OK;
+}
+
+nsBlockFrame::nsBlockFrame(nsIContent* aContent,
+                           PRInt32     aIndexInParent,
+                           nsIFrame*   aParent)
+  : nsHTMLContainerFrame(aContent, aIndexInParent, aParent)
+{
+}
+
+nsBlockFrame::~nsBlockFrame()
+{
+  if (nsnull != mLines) {
+    delete mLines;
+  }
+}
+
+nsresult
+nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
+{
+  NS_PRECONDITION(0 != aInstancePtr, "null ptr");
+  if (NULL == aInstancePtr) {
+    return NS_ERROR_NULL_POINTER;
+  }
+  if (aIID.Equals(kIHTMLFrameTypeIID)) {
+    *aInstancePtr = (void*) ((nsIHTMLFrameType*) this);
+    return NS_OK;
+  } else if (aIID.Equals(kIRunaroundIID)) {
+    *aInstancePtr = (void*) ((nsIRunaround*) this);
+    return NS_OK;
+  } else if (aIID.Equals(kIFloaterContainerIID)) {
+    *aInstancePtr = (void*) ((nsIFloaterContainer*) this);
+    return NS_OK;
+  }
+  return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr);
+}
+
+// Computes the top margin to use for this child frames based on its display
+// type and the display type of the previous child frame.
+//
+// Adjacent vertical margins between block-level elements are collapsed.
+nscoord nsBlockFrame::GetTopMarginFor(nsIPresContext*    aCX,
+                                      nsBlockReflowState& aState,
+                                      nsStyleMolecule*   aKidMol,
+                                      PRBool aIsInline)
+{
+  if (aIsInline) {
+    // Just use whatever the previous bottom margin was
+    return aState.prevMaxPosBottomMargin - aState.prevMaxNegBottomMargin;
+  } else {
+    nscoord maxNegTopMargin = 0;
+    nscoord maxPosTopMargin = 0;
+    if (aKidMol->margin.top < 0) {
+      maxNegTopMargin = -aKidMol->margin.top;
+    } else {
+      maxPosTopMargin = aKidMol->margin.top;
+    }
+  
+    nscoord maxPos = PR_MAX(aState.prevMaxPosBottomMargin, maxPosTopMargin);
+    nscoord maxNeg = PR_MAX(aState.prevMaxNegBottomMargin, maxNegTopMargin);
+    return maxPos - maxNeg;
+  }
+}
+
+void nsBlockFrame::PlaceBelowCurrentLineFloaters(nsIPresContext* aCX,
+                                                 nsBlockReflowState& aState,
+                                                 nscoord aY)
+{
+  NS_PRECONDITION(aState.floaterToDo.Count() > 0, "no floaters");
+
+  // XXX Factor this code with PlaceFloater()...
+  PRInt32   numFloaters = aState.floaterToDo.Count();
+  
+  for (PRInt32 i = 0; i < numFloaters; i++) {
+    nsIFrame* floater = (nsIFrame*)aState.floaterToDo[i];
+    nsRect    region;
+
+    // Get the band of available space
+    // XXX This is inefficient to do this inside the loop...
+    GetAvailableSpaceBand(aState, aY);
+
+    // Get the type of floater
+    nsIStyleContext*  styleContext = floater->GetStyleContext(aCX);
+    nsStyleMolecule*  mol = (nsStyleMolecule*)styleContext->GetData(kStyleMoleculeSID);
+    NS_RELEASE(styleContext);
+  
+    floater->GetRect(region);
+    region.y = mCurrentState->currentBand->rects[0].y;
+
+    if (NS_STYLE_FLOAT_LEFT == mol->floats) {
+      region.x = mCurrentState->currentBand->rects[0].x;
+    } else {
+      NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == mol->floats, "bad float type");
+      region.x = mCurrentState->currentBand->rects[0].XMost() - region.width;
+    }
+
+    // XXX Don't forget the floater's margins...
+    mCurrentState->spaceManager->Translate(mCurrentState->borderPadding.left, 0);
+    mCurrentState->spaceManager->AddRectRegion(region);
+
+    // Set the origin of the floater in world coordinates
+    nscoord worldX, worldY;
+
+    mCurrentState->spaceManager->GetTranslation(worldX, worldY);
+    floater->MoveTo(region.x + worldX, region.y + worldY);
+    mCurrentState->spaceManager->Translate(-mCurrentState->borderPadding.left, 0);
+  }
+  aState.floaterToDo.Clear();
+}
+
+/**
+ * Flush a line out. Return true if the line fits in our available
+ * height. If the line does not fit then return false. When the line
+ * fits we advance the y coordinate, reset the x coordinate and
+ * prepare the nsBlockReflowState for the next line.
+ */
+PRBool nsBlockFrame::AdvanceToNextLine(nsIPresContext* aCX,
+                                       nsBlockReflowState& aState)
+{
+  NS_PRECONDITION(aState.lineLength > 0, "bad line");
+  NS_PRECONDITION(nsnull != aState.lineStart, "bad line");
+
+  nscoord y = aState.y + aState.topMargin;
+  nscoord lineHeight;
+
+  if (aState.isInline) {
+    // Vertically align the children on this line, returning the height of
+    // the line upon completion.
+    lineHeight = nsCSSLayout::VerticallyAlignChildren(aCX, this, aState.font, y,
+                                                      aState.lineStart, aState.lineLength,
+                                                      aState.ascents, aState.maxAscent);
+
+    // Any below current line floaters to place?
+    if (aState.floaterToDo.Count() > 0) {
+      PlaceBelowCurrentLineFloaters(aCX, aState, y + lineHeight);
+      // XXX Factor in the height of the floaters as well when considering
+      // whether the line fits.
+      // The default policy is that if there isn't room for the floaters then
+      // both the line and the floaters are pushed to the next-in-flow...
+    }
+  } else {
+    lineHeight = aState.lineStart->GetHeight();
+  }
+
+  // The first line always fits
+  if (aState.currentLineNumber > 0) {
+    nscoord yb = aState.borderPadding.top + aState.availSize.height;
+    if (y + lineHeight > yb) {
+      // After vertical alignment of the children and factoring in the
+      // proper margin, the line doesn't fit.
+      return PR_FALSE;
+    }
+  }
+
+  if (aState.isInline) {
+    // Check if the right-edge of the line exceeds our running x-most
+    nscoord xMost = aState.borderPadding.left + aState.lineWidth;
+    if (xMost > aState.kidXMost) {
+      aState.kidXMost = xMost;
+    }
+  }
+
+  // Advance the y coordinate to the new position where the next
+  // line or block element will go.
+  aState.y = y + lineHeight;
+  aState.x = 0;
+
+  // Now that the vertical alignment is done we can perform horizontal
+  // alignment and relative positioning. Skip all of these if we are
+  // doing an unconstrained (in x) reflow. There's no point in doing
+  // the work if we *know* we are going to reflowed again.
+  if (!aState.unconstrainedWidth) {
+    nsCSSLayout::HorizontallyPlaceChildren(aCX, this, aState.mol,
+                                           aState.lineStart, aState.lineLength,
+                                           aState.lineWidth,
+                                           aState.availSize.width);
+
+    // Finally, now that the in-flow positions of the line's frames are
+    // known we can apply relative positioning if any of them need it.
+    if (!aState.justifying) { 
+      nsCSSLayout::RelativePositionChildren(aCX, this, aState.mol,
+                                            aState.lineStart,
+                                            aState.lineLength);
+    }
+  }
+
+  // Record line length
+  aState.lineLengths.AppendElement((void*)aState.lineLength);
+
+  // Find the last frame in the line
+  // XXX keep this as running state in the nsBlockReflowState
+  nsIFrame* lastFrame = aState.lineStart;
+  PRInt32 lineLen = aState.lineLength - 1;
+  while (--lineLen >= 0) {
+    lastFrame = lastFrame->GetNextSibling();
+  }
+
+  // Update maxElementSize
+  if (nsnull != aState.maxElementSize) {
+    nsSize& lineMax = aState.lineMaxElementSize;
+    nsSize* maxMax = aState.maxElementSize;
+    if (lineMax.width > maxMax->width) {
+      maxMax->width = lineMax.width;
+    }
+    if (lineMax.height > maxMax->height) {
+      maxMax->height = lineMax.height;
+    }
+    aState.lineMaxElementSize.width = 0;
+    aState.lineMaxElementSize.height = 0;
+  }
+
+  // Advance to the next line
+  aState.AdvanceToNextLine(lastFrame, lineHeight);
+
+  return PR_TRUE;
+}
+
+/**
+ * Add an inline  child to the current line. Advance various running
+ * values after placement.
+ */
+void nsBlockFrame::AddInlineChildToLine(nsIPresContext* aCX,
+                                        nsBlockReflowState& aState,
+                                        nsIFrame* aKidFrame,
+                                        nsReflowMetrics& aKidSize,
+                                        nsSize* aKidMaxElementSize,
+                                        nsStyleMolecule* aKidMol)
+{
+  NS_PRECONDITION(nsnull != aState.lineStart, "bad line");
+
+  PRIntn direction = aState.mol->direction;
+  if (NS_STYLE_POSITION_RELATIVE == aKidMol->positionFlags) {
+    aState.needRelativePos = PR_TRUE;
+  }
+
+  // Place and size the child
+  // XXX add in left margin from kid
+  nsRect r;
+  r.y = aState.y;
+  r.width = aKidSize.width;
+  r.height = aKidSize.height;
+  if (NS_STYLE_DIRECTION_LTR == aState.mol->direction) {
+    // Left to right positioning.
+    r.x = aState.borderPadding.left + aState.x + aKidMol->margin.left;
+    aState.x += aKidSize.width + aKidMol->margin.left + aKidMol->margin.right;
+  } else {
+    // Right to left positioning
+    // XXX what should we do when aState.x goes negative???
+    r.x = aState.x - aState.borderPadding.right - aKidMol->margin.right - aKidSize.width;
+    aState.x -= aKidSize.width + aKidMol->margin.right + aKidMol->margin.left;
+  }
+  aKidFrame->SetRect(r);
+  aState.AddAscent(aKidSize.ascent);
+  aState.lineWidth += aKidSize.width;
+  aState.lineLength++;
+
+  // Update maximums for the line
+  if (aKidSize.ascent > aState.maxAscent) {
+    aState.maxAscent = aKidSize.ascent;
+  }
+  if (aKidSize.descent > aState.maxDescent) {
+    aState.maxDescent = aKidSize.descent;
+  }
+  // Update running margin maximums
+  if (aState.firstChildIsInsideBullet && (aKidFrame == mFirstChild)) {
+    // XXX temporary code. Since the molecule for the bullet frame
+    // is the same as the LI frame, we get bad style information.
+    // ignore it.
+  } else {
+    nscoord margin;
+#if 0
+    // XXX CSS2 spec says that top/bottom margin don't affect line height
+    // calculation. We're waiting for clarification on this issue...
+    if ((margin = aKidMol->margin.top) < 0) {
+      margin = -margin;
+      if (margin > aState.maxNegTopMargin) {
+        aState.maxNegTopMargin = margin;
+      }
+    } else {
+      if (margin > aState.maxPosTopMargin) {
+        aState.maxPosTopMargin = margin;
+      }
+    }
+#endif
+    if ((margin = aKidMol->margin.bottom) < 0) {
+      margin = -margin;
+      if (margin > aState.maxNegBottomMargin) {
+        aState.maxNegBottomMargin = margin;
+      }
+    } else {
+      if (margin > aState.maxPosBottomMargin) {
+        aState.maxPosBottomMargin = margin;
+      }
+    }
+  }
+
+  // Update line max element size
+  nsSize& mes = aState.lineMaxElementSize;
+  if (nsnull != aKidMaxElementSize) {
+    if (aKidMaxElementSize->width > mes.width) {
+      mes.width = aKidMaxElementSize->width;
+    }
+    if (aKidMaxElementSize->height > mes.height) {
+      mes.height = aKidMaxElementSize->height;
+    }
+  }
+}
+
+// Places and sizes the block-level element, and advances the line.
+// The rect is in the local coordinate space of the kid frame.
+void nsBlockFrame::AddBlockChild(nsIPresContext* aCX,
+                                 nsBlockReflowState& aState,
+                                 nsIFrame* aKidFrame,
+                                 nsRect& aKidRect,
+                                 nsSize* aKidMaxElementSize,
+                                 nsStyleMolecule* aKidMol)
+{
+  NS_PRECONDITION(nsnull != aState.lineStart, "bad line");
+
+  if (NS_STYLE_POSITION_RELATIVE == aKidMol->positionFlags) {
+    aState.needRelativePos = PR_TRUE;
+  }
+
+  // Translate from the kid's coordinate space to our coordinate space
+  aKidRect.x += aState.borderPadding.left + aKidMol->margin.left;
+  aKidRect.y += aState.y + aState.topMargin;
+
+  // Place and size the child
+  aKidFrame->SetRect(aKidRect);
+
+  aState.AddAscent(aKidRect.height);
+  aState.lineLength++;
+
+  // Is this the widest child frame?
+  nscoord xMost = aKidRect.XMost() + aKidMol->margin.right;
+  if (xMost > aState.kidXMost) {
+    aState.kidXMost = xMost;
+  }
+
+  // Update the max element size
+  if (nsnull != aKidMaxElementSize) {
+    if (aKidMaxElementSize->width > aState.maxElementSize->width) {
+      aState.maxElementSize->width = aKidMaxElementSize->width;
+    }
+    if (aKidMaxElementSize->height > aState.maxElementSize->height) {
+      aState.maxElementSize->height = aKidMaxElementSize->height;
+    }
+  }
+
+  // and the bottom line margin information which we'll use when placing
+  // the next child
+  if (aKidMol->margin.bottom < 0) {
+    aState.maxNegBottomMargin = -aKidMol->margin.bottom;
+  } else {
+    aState.maxPosBottomMargin = aKidMol->margin.bottom;
+  }
+
+  // Update the running y-offset
+  aState.y += aKidRect.height + aState.topMargin;
+
+  // Apply relative positioning if necessary
+  nsCSSLayout::RelativePositionChildren(aCX, this, aState.mol, aKidFrame, 1);
+
+  // Advance to the next line
+  aState.AdvanceToNextLine(aKidFrame, aKidRect.height);
+}
+
+/**
+ * Compute the available size for reflowing the given child at the
+ * current x,y position in the state. Note that this may return
+ * negative or zero width/height's if we are out of room.
+ */
+void nsBlockFrame::GetAvailSize(nsSize& aResult,
+                                nsBlockReflowState& aState,
+                                nsStyleMolecule* aKidMol,
+                                PRBool aIsInline)
+{
+  // Determine the maximum available reflow height for the child
+  nscoord yb = aState.borderPadding.top + aState.availSize.height;
+  aResult.height = aState.unconstrainedHeight ? NS_UNCONSTRAINEDSIZE :
+                                                yb - aState.y - aState.topMargin;
+
+  // Determine the maximum available reflow width for the child
+  if (aState.unconstrainedWidth) {
+    aResult.width = NS_UNCONSTRAINEDSIZE;
+  } else if (aIsInline) {
+    if (NS_STYLE_DIRECTION_LTR == aState.mol->direction) {
+      aResult.width = aState.currentBand->rects[0].XMost() - aState.x;
+    } else {
+      aResult.width = aState.x - aState.currentBand->rects[0].x;
+    }
+  } else {
+    // It's a block
+    aResult.width = aState.availSize.width - aKidMol->margin.left -
+                    aKidMol->margin.right;
+  }
+}
+
+/**
+ * Push all of the kids that we have not reflowed, starting at
+ * aState.lineStart. aPrevKid is the kid previous to aState.lineStart
+ * and is also our last child. Note that line length is NOT a
+ * reflection of the number of children we are actually pushing
+ * (because we don't break the sibling list as we add children to the
+ * line).
+ */
+void nsBlockFrame::PushKids(nsBlockReflowState& aState)
+{
+  nsIFrame* prevFrame = aState.prevLineLastFrame;
+  NS_PRECONDITION(nsnull != prevFrame, "pushing all kids");
+  NS_PRECONDITION(prevFrame->GetNextSibling() == aState.lineStart,
+                  "bad prev line");
+
+#ifdef NS_DEBUG
+  PRInt32 numKids = LengthOf(mFirstChild);
+  NS_ASSERTION(numKids == mChildCount, "bad child count");
+#endif
+
+#ifdef NOISY
+  ListTag(stdout);
+  printf(": push kids (childCount=%d)\n", mChildCount);
+  DumpFlow();
+#endif
+
+  PushChildren(aState.lineStart, prevFrame, mLastContentIsComplete);
+  SetLastContentOffset(prevFrame);
+
+  // Set mLastContentIsComplete to the previous lines last content is
+  // complete now that the previous line's last child is our last
+  // child.
+  mLastContentIsComplete = aState.prevLineLastContentIsComplete;
+
+  // Fix up child count
+  // XXX is there a better way? aState.lineLength doesn't work because
+  // we might be pushing more than just the pending line.
+  nsIFrame* kid = mFirstChild;
+  PRInt32 kids = 0;
+  while (nsnull != kid) {
+    kids++;
+    kid = kid->GetNextSibling();
+  }
+  mChildCount = kids;
+
+  // Make sure we have no lingering line data
+  aState.lineLength = 0;
+  aState.lineStart = nsnull;
+
+#ifdef NOISY
+  ListTag(stdout);
+  printf(": push kids done (childCount=%d) [%c]\n", mChildCount,
+         (mLastContentIsComplete ? 'T' : 'F'));
+  DumpFlow();
+#endif
+}
+
+/**
+ * Gets a band of available space starting at the specified y-offset. Assumes
+ * the local coordinate space is currently set to the upper-left origin of the
+ * bounding rect
+ *
+ * Updates "currentBand" and "x" member data of the block reflow state
+ */
+void nsBlockFrame::GetAvailableSpaceBand(nsBlockReflowState& aState, nscoord aY)
+{
+  // Gets a band of available space.
+  aState.spaceManager->Translate(aState.borderPadding.left, 0);
+  aState.spaceManager->GetBandData(aY, aState.availSize, *aState.currentBand);
+
+  // XXX This is hack code that needs to change when the space manager interface
+  // changes to return both the available and unavailable space
+  //
+  // We'll get back anywhere between 1 and 3 rects depending on how many floaters
+  // there are. Actually the way it currently works we could get back zero rects
+  // if there are overlapping left and right floaters occupying all the space
+  if (aState.currentBand->count > 1) {
+    // If there are three rects then let's assume that there are floaters on the
+    // left and right and that only the middle rect is available
+    if (aState.currentBand->count == 3) {
+      aState.currentBand->rects[0] = aState.currentBand->rects[1];
+    } else {
+      // There are two rects. That means either a left or right floater. Just use
+      // whichever space is larger.
+      if (aState.currentBand->rects[1].width > aState.currentBand->rects[0].width) {
+        aState.currentBand->rects[0] = aState.currentBand->rects[1];
+      }
+    }
+  }
+  aState.spaceManager->Translate(-aState.borderPadding.left, 0);
+  aState.x = aState.currentBand->rects[0].x;
+}
+
+void nsBlockFrame::ClearFloaters(nsBlockReflowState& aState, PRUint32 aClear)
+{
+  // Translate the coordinate space
+  aState.spaceManager->Translate(aState.borderPadding.left, 0);
+
+getBand:
+  nscoord y = aState.y + aState.topMargin;
+  PRBool  isLeftFloater = PR_FALSE;
+  PRBool  isRightFloater = PR_FALSE;
+
+  // Get a band of available space
+  aState.spaceManager->GetBandData(y, aState.availSize, *aState.currentBand);
+
+  if (aState.currentBand->count == 1) {
+    if (aState.currentBand->rects[0].width != aState.availSize.width) {
+      // Some of the space is taken up by floaters
+      if (aState.currentBand->rects[0].x > 0) {
+        isLeftFloater = PR_TRUE;
+      }
+
+      if (aState.currentBand->rects[0].XMost() < aState.availSize.width) {
+        isRightFloater = PR_TRUE;
+      }
+    }
+  } else if (aState.currentBand->count == 2) {
+    if (aState.currentBand->rects[0].width > aState.currentBand->rects[1].width) {
+      isRightFloater = PR_TRUE;
+    } else {
+      isLeftFloater = PR_TRUE;
+
+      // There may also be a right floater
+      if (aState.currentBand->rects[1].XMost() < aState.availSize.width) {
+        isRightFloater = PR_TRUE;
+      }
+    }
+  } else {
+    // Must be both left and right floaters
+    isLeftFloater = PR_TRUE;
+    isRightFloater = PR_TRUE;
+  }
+
+  if (isLeftFloater) {
+    if ((aClear == NS_STYLE_CLEAR_LEFT) || (aClear == NS_STYLE_CLEAR_BOTH)) {
+      aState.y += aState.currentBand->rects[0].height;
+      goto getBand;
+    }
+  }
+  if (isRightFloater) {
+    if ((aClear == NS_STYLE_CLEAR_RIGHT) || (aClear == NS_STYLE_CLEAR_BOTH)) {
+      aState.y += aState.currentBand->rects[0].height;
+      goto getBand;
+    }
+  }
+
+  aState.spaceManager->Translate(-aState.borderPadding.left, 0);
+}
+
+// Bit's for PlaceAndReflowChild return value
+#define PLACE_FIT    0x1
+#define PLACE_FLOWED 0x2
+
+PRIntn
+nsBlockFrame::PlaceAndReflowChild(nsIPresContext* aCX,
+                                  nsBlockReflowState& aState,
+                                  nsIFrame* kidFrame,
+                                  nsStyleMolecule* aKidMol)
+{
+  nsSize kidMaxElementSize;
+  nsSize* pKidMaxElementSize =
+    (nsnull != aState.maxElementSize) ? &kidMaxElementSize : nsnull;
+
+  // Get line start setup if we are at the start of a new line
+  if (nsnull == aState.lineStart) {
+    NS_ASSERTION(0 == aState.lineLength, "bad line length");
+    aState.lineStart = kidFrame;
+  }
+
+  // Get kid and its style
+  // XXX How is this any different than what was passed in to us as aKidMol?
+  nsIContent* kid = kidFrame->GetContent();
+  nsIStyleContext* kidSC = kidFrame->GetStyleContext(aCX);
+  nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID);
+  NS_RELEASE(kid);
+
+  // Figure out if kid is a block element or not
+  PRBool isInline = PR_TRUE;
+  PRIntn display = kidMol->display;
+  if (aState.firstChildIsInsideBullet && (mFirstChild == kidFrame)) {
+    // XXX Special hack for properly reflowing bullets that have the
+    // inside value for list-style-position.
+    display = NS_STYLE_DISPLAY_INLINE;
+  }
+  if ((NS_STYLE_DISPLAY_BLOCK == display) ||
+      (NS_STYLE_DISPLAY_LIST_ITEM == display)) {
+    // Block elements always end up on the next line (unless they are
+    // already at the start of the line).
+    isInline = PR_FALSE;
+    if (aState.lineLength > 0) {
+      aState.breakAfterChild = PR_TRUE;
+    }
+  }
+
+  // Handle forced break first
+  if (aState.breakAfterChild) {
+    NS_ASSERTION(aState.lineStart != kidFrame, "bad line");
+
+    // Get the last child in the current line
+    nsIFrame* lastFrame = aState.lineStart;
+    PRInt32   lineLen = aState.lineLength - 1;
+    while (--lineLen >= 0) {
+      lastFrame = lastFrame->GetNextSibling();
+    }
+
+    if (!AdvanceToNextLine(aCX, aState)) {
+      // The previous line didn't fit.
+      return 0;
+    }
+    aState.lineStart = kidFrame;
+
+    // Get the style for the last child, and see if it wanted to clear floaters.
+    // This handles the BR tag, which is the only inline element for which clear
+    // applies
+    nsIStyleContext* lastChildSC = lastFrame->GetStyleContext(aCX);
+    nsStyleMolecule* lastChildMol = (nsStyleMolecule*)lastChildSC->GetData(kStyleMoleculeSID); 
+    if (lastChildMol->clear != NS_STYLE_CLEAR_NONE) {
+      ClearFloaters(aState, lastChildMol->clear);
+    }
+    NS_RELEASE(lastChildSC);
+  }
+
+  // Now that we've handled force breaks (and maybe called AdvanceToNextLine()
+  // which checks), remember whether it's an inline frame
+  aState.isInline = isInline;
+
+  // If we're at the beginning of a line then compute the top margin that we
+  // should use
+  if (aState.lineStart == kidFrame) {
+    // Compute the top margin to use for this line
+    aState.topMargin = GetTopMarginFor(aCX, aState, kidMol, aState.isInline);
+
+    // If it's an inline element then get a band of available space
+    //
+    // XXX If we have a current band and there's unused space in that band
+    // then avoid this call to get a band...
+    if (aState.isInline) {
+      GetAvailableSpaceBand(aState, aState.y + aState.topMargin);
+    }
+  }
+
+  // Compute the available space to reflow the child into and then
+  // reflow it into that space.
+  nsSize kidAvailSize;
+  GetAvailSize(kidAvailSize, aState, kidMol, aState.isInline);
+  if ((aState.currentLineNumber > 0) && (kidAvailSize.height <= 0)) {
+    // No more room
+    return 0;
+  }
+
+  ReflowStatus    status;
+
+  if (aState.isInline) {
+    nsReflowMetrics kidSize;
+
+    // Inline elements are never passed the space manager
+    status = ReflowChild(kidFrame, aCX, kidSize, kidAvailSize,
+                         pKidMaxElementSize);
+
+    // For first children, we skip all the fit checks because we must
+    // fit at least one child for a parent to figure what to do with us.
+    if ((aState.currentLineNumber > 0) || (aState.lineLength > 0)) {
+      NS_ASSERTION(nsnull != aState.lineStart, "bad line start");
+
+      if (kidFrame == aState.lineStart) {
+        // Width always fits when we are at the logical left margin.
+        // Just check the height.
+        //
+        // XXX This height check isn't correct now that we have bands of
+        // available space...
+        if (kidSize.height > kidAvailSize.height) {
+          // It's too tall
+          return PLACE_FLOWED;
+        }
+      } else {
+        // Examine state and if the breakBeforeChild is set and we
+        // aren't already on the new line, do the forcing now.
+        // XXX Why aren't we doing this check BEFORE we resize reflow the child?
+        if (aState.breakBeforeChild) {
+          aState.breakBeforeChild = PR_FALSE;
+          if (kidFrame != aState.lineStart) {
+            if (!AdvanceToNextLine(aCX, aState)) {
+              // Flushing out the line failed.
+              return PLACE_FLOWED;
+            }
+            aState.lineStart = kidFrame;
+
+            // Get a band of available space
+            GetAvailableSpaceBand(aState, aState.y + aState.topMargin);
+
+            // Reflow child now that it has the line to itself
+            GetAvailSize(kidAvailSize, aState, kidMol, PR_TRUE);
+            status = ReflowChild(kidFrame, aCX, kidSize, kidAvailSize,
+                                 pKidMaxElementSize);
+          }
+        }
+
+        // When we are not at the logical left margin then we need
+        // to check the width first. If we are too wide then advance
+        // to the next line and try reflowing again.
+        if (kidSize.width > kidAvailSize.width) {
+          // Too wide. Try next line
+          if (!AdvanceToNextLine(aCX, aState)) {
+            // Flushing out the line failed.
+            return PLACE_FLOWED;
+          }
+          aState.lineStart = kidFrame;
+
+          // Get a band of available space
+          GetAvailableSpaceBand(aState, aState.y + aState.topMargin);
+
+          // Reflow splittable children
+          if (kidFrame->IsSplittable()) {
+            // Update size info now that we are on the next line. Then
+            // reflow the child into the new available space.
+            GetAvailSize(kidAvailSize, aState, kidMol, PR_TRUE);
+            status = ReflowChild(kidFrame, aCX, kidSize, kidAvailSize,
+                                 pKidMaxElementSize);
+
+            // If we just reflowed our last child then update the
+            // mLastContentIsComplete state.
+            if (nsnull == kidFrame->GetNextSibling()) {
+              // Use state from the reflow we just did
+              mLastContentIsComplete = PRBool(status == frComplete);
+            }
+          }
+
+          // XXX This height check isn't correct now that we have bands of
+          // available space...
+          if (kidSize.height > kidAvailSize.height) {
+            // It's too tall on the next line
+            return PLACE_FLOWED;
+          }
+          // It's ok if it's too wide on the next line.
+        }
+      }
+    }
+
+    // Add child to the line
+    AddInlineChildToLine(aCX, aState, kidFrame, kidSize, pKidMaxElementSize, kidMol);
+  
+  } else {
+    nsRect  kidRect;
+
+    // Does the block-level element want to clear any floaters that impact
+    // it? Note that the clear property only applies to block-level elements
+    // and the BR tag
+    if (aKidMol->clear != NS_STYLE_CLEAR_NONE) {
+      ClearFloaters(aState, aKidMol->clear);
+      GetAvailSize(kidAvailSize, aState, kidMol, PR_FALSE);
+      if ((aState.currentLineNumber > 0) && (kidAvailSize.height <= 0)) {
+        // No more room
+        return 0;
+      }
+    }
+
+    // Give the block its own local coordinate space.
+    //
+    // XXX This is wrong to have the parent try and account for the kid's
+    // left margin here, because we have to wait until we know what the
+    // left edge is and that means resolving any floaters that impact the
+    // block. If the kid wants to interact with the space manager then it
+    // will have to deal with left/right margins itself
+    nscoord tx = aState.borderPadding.left + aKidMol->margin.left;
+    nscoord ty = aState.y + aState.topMargin;
+
+    // Give the block-level element the opportunity to use the space manager
+    aState.spaceManager->Translate(tx, ty);
+    status = ReflowChild(kidFrame, aCX, aState.spaceManager, kidAvailSize,
+                         kidRect, pKidMaxElementSize);
+    aState.spaceManager->Translate(-tx, -ty);
+
+    // For first children, we skip all the fit checks because we must
+    // fit at least one child for a parent to figure what to do with us.
+    if ((aState.currentLineNumber > 0) || (aState.lineLength > 0)) {
+      // Block elements always fit horizontally (because they are
+      // always placed at the logical left margin). Check to see if
+      // the block fits vertically
+      if (kidRect.YMost() > kidAvailSize.height) {
+        // Nope
+        return PLACE_FLOWED;
+      }
+    }
+
+    // Add block child
+    AddBlockChild(aCX, aState, kidFrame, kidRect, pKidMaxElementSize, kidMol);
+  }
+
+  // If we just reflowed our last child then update the
+  // mLastContentIsComplete state.
+  if (nsnull == kidFrame->GetNextSibling()) {
+    // Use state from the reflow we just did
+    mLastContentIsComplete = PRBool(status == frComplete);
+  }
+
+  aState.lastContentIsComplete = PRBool(status == frComplete);
+  if (aState.isInline && (frNotComplete == status)) {
+    // Since the inline child didn't complete its reflow we *know*
+    // that a continuation of it can't possibly fit on the current
+    // line. Therefore, set a flag in the state that will cause the
+    // a line break before the next frame is placed.
+    aState.breakAfterChild = PR_TRUE;
+  }
+  NS_RELEASE(kidSC);
+
+  aState.reflowStatus = status;
+  return PLACE_FLOWED | PLACE_FIT;
+}
+
+/**
+ * Reflow the existing frames.
+ *
+ * @param   aCX presentation context to use
+ * @param   aState in out parameter which tracks the state of
+ *            reflow for the block frame.
+ * @return  true if we successfully reflowed all the mapped children and false
+ *            otherwise, e.g. we pushed children to the next in flow
+ */
+PRBool
+nsBlockFrame::ReflowMappedChildren(nsIPresContext* aCX,
+                                   nsBlockReflowState& aState)
+{
+#ifdef NS_DEBUG
+  VerifyLastIsComplete();
+#endif
+#ifdef NOISY
+  ListTag(stdout);
+  printf(": reflow mapped (childCount=%d) [%d,%d,%c]\n",
+         mChildCount,
+         mFirstContentOffset, mLastContentOffset,
+         (mLastContentIsComplete ? 'T' : 'F'));
+  DumpFlow();
+#endif
+
+  PRBool result = PR_TRUE;
+  nsIFrame* kidFrame;
+  nsIFrame* prevKidFrame = nsnull;
+
+  for (kidFrame = mFirstChild; nsnull != kidFrame; ) {
+    nsIContent* kid = kidFrame->GetContent();
+    nsIStyleContext* kidSC = aCX->ResolveStyleContextFor(kid, this);
+    nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID);
+    NS_RELEASE(kid);
+
+    // Attempt to place and reflow the child
+
+    // XXX if child is not splittable and it fits just place it where
+    // it is, otherwise advance to the next line and place it there if
+    // possible
+
+    PRIntn placeStatus = PlaceAndReflowChild(aCX, aState, kidFrame, kidMol);
+    ReflowStatus status = aState.reflowStatus;
+    NS_RELEASE(kidSC);
+    if (0 == (placeStatus & PLACE_FIT)) {
+      // The child doesn't fit. Push it and any remaining children.
+      PushKids(aState);
+      result = PR_FALSE;
+      goto push_done;
+    }
+
+    // Is the child complete?
+    if (frComplete == status) {
+      // Yes, the child is complete
+      NS_ASSERTION(nsnull == kidFrame->GetNextInFlow(), "bad child flow list");
+    } else {
+      // No the child isn't complete
+      nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow();
+      if (nsnull == kidNextInFlow) {
+        // The child doesn't have a next-in-flow so create a continuing
+        // frame. This hooks the child into the flow
+        nsIFrame* continuingFrame =
+          kidFrame->CreateContinuingFrame(aCX, this);
+        NS_ASSERTION(nsnull != continuingFrame, "frame creation failed");
+
+        // Add the continuing frame to the sibling list
+        nsIFrame* nextSib = kidFrame->GetNextSibling();
+        continuingFrame->SetNextSibling(nextSib);
+        kidFrame->SetNextSibling(continuingFrame);
+        mChildCount++;
+      }
+
+      // Unlike the inline frame code we can't assume that we used
+      // up all of our space because the child's reflow status is
+      // frNotComplete. Instead, the child is probably split and
+      // we need to reflow the continuations as well.
+    }
+
+    // Get the next child frame
+    prevKidFrame = kidFrame;
+    kidFrame = kidFrame->GetNextSibling();
+  }
+
+ push_done:;
+  // Update the child count member data
+  NS_POSTCONDITION(LastChild()->GetIndexInParent() == mLastContentOffset, "bad last content offset");
+
+#ifdef NS_DEBUG
+  PRInt32 len = LengthOf(mFirstChild);
+  NS_POSTCONDITION(len == mChildCount, "bad child count");
+  VerifyLastIsComplete();
+#endif
+
+#ifdef NOISY
+  ListTag(stdout);
+  printf(": reflow mapped %sok (childCount=%d) [%d,%d,%c]\n",
+         (result ? "" : "NOT "),
+         mChildCount,
+         mFirstContentOffset, mLastContentOffset,
+         (mLastContentIsComplete ? 'T' : 'F'));
+  DumpFlow();
+#endif
+  return result;
+}
+
+PRBool nsBlockFrame::MoreToReflow(nsIPresContext* aCX)
+{
+  PRBool rv = PR_FALSE;
+  if (IsPseudoFrame()) {
+    // Get the next content object that we would like to reflow
+    PRInt32 kidIndex = NextChildOffset();
+    nsIContent* kid = mContent->ChildAt(kidIndex);
+    if (nsnull != kid) {
+      // Resolve style for the kid
+      nsIStyleContext* kidSC = aCX->ResolveStyleContextFor(kid, this);
+      nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID);
+      switch (kidMol->display) {
+      case NS_STYLE_DISPLAY_BLOCK:
+      case NS_STYLE_DISPLAY_LIST_ITEM:
+        // Block pseudo-frames do not contain other block elements
+        break;
+
+      default:
+        rv = PR_TRUE;
+        break;
+      }
+      NS_RELEASE(kidSC);
+      NS_RELEASE(kid);
+    }
+  } else {
+    if (NextChildOffset() < mContent->ChildCount()) {
+      rv = PR_TRUE;
+    }
+  }
+  return rv;
+}
+
+/**
+ * Create new frames for content we haven't yet mapped
+ *
+ * @param   aCX presentation context to use
+ * @return  frComplete if all content has been mapped and frNotComplete
+ *            if we should be continued
+ */
+nsIFrame::ReflowStatus
+nsBlockFrame::ReflowAppendedChildren(nsIPresContext* aCX,
+                                     nsBlockReflowState& aState)
+{
+#ifdef NS_DEBUG
+  VerifyLastIsComplete();
+#endif
+  nsIFrame*    kidPrevInFlow = nsnull;
+  ReflowStatus result = frNotComplete;
+
+  // If we have no children and we have a prev-in-flow then we need to pick
+  // up where it left off. If we have children, e.g. we're being resized, then
+  // our content offset should already be set correctly...
+  if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) {
+    nsBlockFrame* prev = (nsBlockFrame*) mPrevInFlow;
+    NS_ASSERTION(prev->mLastContentOffset >= prev->mFirstContentOffset, "bad prevInFlow");
+    mFirstContentOffset = prev->NextChildOffset();
+    if (PR_FALSE == prev->mLastContentIsComplete) {
+      // Our prev-in-flow's last child is not complete
+      kidPrevInFlow = prev->LastChild();
+    }
+  }
+
+  // Place our children, one at a time until we are out of children
+  PRInt32 kidIndex = NextChildOffset();
+  nsIFrame* prevKidFrame = LastChild();
+  nsIFrame* kidFrame = nsnull;
+  for (;;) {
+    // Get the next content object
+    nsIContent* kid = mContent->ChildAt(kidIndex);
+    if (nsnull == kid) {
+      result = frComplete;
+      break;
+    }
+
+    // Resolve style for the kid
+    nsIStyleContext* kidSC = aCX->ResolveStyleContextFor(kid, this);
+    nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID);
+
+    // Is it a floater?
+    if (kidMol->floats != NS_STYLE_FLOAT_NONE) {
+      PlaceholderFrame::NewFrame(&kidFrame, kid, kidIndex, this);
+      kidFrame->SetStyleContext(kidSC);
+    } else if (nsnull == kidPrevInFlow) {
+      // Create initial frame for the child
+      nsIContentDelegate* kidDel;
+      nsresult fr;
+      switch (kidMol->display) {
+      case NS_STYLE_DISPLAY_BLOCK:
+      case NS_STYLE_DISPLAY_LIST_ITEM:
+        // Pseudo block frames do not contain other block elements
+        // unless the block element would be the first child.
+        if (IsPseudoFrame()) {
+          // If we're being used as a pseudo frame, i.e. we map the same
+          // content as our parent then we want to indicate we're complete;
+          // otherwise we'll be continued and go on mapping children...
+
+          // It better be true that we are not being asked to flow a
+          // block element as our first child. That means the body
+          // decided it needed a pseudo-frame when it shouldn't have.
+          NS_ASSERTION(nsnull != mFirstChild, "bad body");
+
+          NS_RELEASE(kidSC);
+          NS_RELEASE(kid);
+          result = frComplete;
+          goto done;
+        }
+        // FALL THROUGH (and create frame)
+
+      case NS_STYLE_DISPLAY_INLINE:
+        kidDel = kid->GetDelegate(aCX);
+        kidFrame = kidDel->CreateFrame(aCX, kid, kidIndex, this);
+        NS_RELEASE(kidDel);
+        break;
+
+      default:
+        NS_ASSERTION(nsnull == kidPrevInFlow, "bad prev in flow");
+        fr = nsFrame::NewFrame(&kidFrame, kid, kidIndex, this);
+        break;
+      }
+      kidFrame->SetStyleContext(kidSC);
+    } else {
+      // Since kid has a prev-in-flow, use that to create the next
+      // frame.
+      kidFrame = kidPrevInFlow->CreateContinuingFrame(aCX, this);
+    }
+
+    // Link child frame into the list of children. If the frame ends
+    // up not fitting and getting pushed, the PushKids code will fixup
+    // the child count for us.
+    if (nsnull != prevKidFrame) {
+      NS_ASSERTION(nsnull == prevKidFrame->GetNextSibling(), "bad append");
+      prevKidFrame->SetNextSibling(kidFrame);
+    } else {
+      NS_ASSERTION(nsnull == mFirstChild, "bad create");
+      mFirstChild = kidFrame;
+      SetFirstContentOffset(kidFrame);
+    }
+    prevKidFrame = kidFrame;
+    mChildCount++;
+
+    // Reflow child frame as many times as necessary until it is
+    // complete.
+    ReflowStatus status;
+    do {
+      PRIntn placeStatus = PlaceAndReflowChild(aCX, aState, kidFrame, kidMol);
+      status = aState.reflowStatus;
+      if (0 == (placeStatus & PLACE_FIT)) {
+        // We ran out of room.
+        mLastContentIsComplete = PRBool(nsnull == kidFrame->GetNextInFlow());
+        PushKids(aState);
+
+        NS_RELEASE(kid);
+        NS_RELEASE(kidSC);
+        goto push_done;
+      }
+
+      // Did the child complete?
+      prevKidFrame = kidFrame;
+      if (frNotComplete == status) {
+        // Child didn't complete so create a continuing frame
+        kidPrevInFlow = kidFrame;
+        nsIFrame* continuingFrame = kidFrame->CreateContinuingFrame(aCX, this);
+
+        // Add the continuing frame to the sibling list
+        continuingFrame->SetNextSibling(kidFrame->GetNextSibling());
+        kidFrame->SetNextSibling(continuingFrame);
+        kidFrame = continuingFrame;
+        mChildCount++;
+
+        // Switch to new kid style
+        NS_RELEASE(kidSC);
+        kidSC = kidFrame->GetStyleContext(aCX);
+        kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID);
+      }
+      NS_ASSERTION(nsnull == kidFrame->GetNextInFlow(), "huh?");
+    } while (frNotComplete == status);
+    NS_RELEASE(kid);
+    NS_RELEASE(kidSC);
+
+    // The child that we just reflowed is complete
+    NS_ASSERTION(nsnull == kidFrame->GetNextInFlow(), "bad child flow list");
+    kidIndex++;
+    kidPrevInFlow = nsnull;
+  }
+
+ done:
+  // To get here we either completely reflowed all our appended
+  // children OR we are a pseudo-frame and we ran into a block
+  // element. In either case our last content MUST be complete.
+  NS_ASSERTION(PR_TRUE == aState.lastContentIsComplete, "bad state");
+
+  NS_ASSERTION(LastChild() == prevKidFrame, "bad last child");
+  SetLastContentOffset(prevKidFrame);
+
+ push_done:
+#ifdef NS_DEBUG
+  PRInt32 len = LengthOf(mFirstChild);
+  NS_ASSERTION(len == mChildCount, "bad child count");
+  VerifyLastIsComplete();
+#endif
+  return result;
+}
+
+/**
+ * Pullup frames from our next in flow and try to place them. Before
+ * this is called our previously mapped children, if any have been
+ * reflowed which means that the block reflow state's x and y
+ * coordinates and other data are ready to go.
+ *
+ * Return true if we pulled everything up.
+ */
+PRBool
+nsBlockFrame::PullUpChildren(nsIPresContext* aCX,
+                             nsBlockReflowState& aState)
+{
+#ifdef NS_DEBUG
+  VerifyLastIsComplete();
+#endif
+#ifdef NOISY
+  ListTag(stdout);
+  printf(": pullup (childCount=%d) [%d,%d,%c]\n",
+         mChildCount,
+         mFirstContentOffset, mLastContentOffset,
+         (mLastContentIsComplete ? 'T' : 'F'));
+  DumpFlow();
+#endif
+
+  PRBool result = PR_TRUE;
+  nsBlockFrame* nextInFlow = (nsBlockFrame*) mNextInFlow;
+  nsIFrame* prevKidFrame = LastChild();
+  while (nsnull != nextInFlow) {
+    // Get first available frame from the next-in-flow
+    nsIFrame* kidFrame = PullUpOneChild(nextInFlow, prevKidFrame);
+    if (nsnull == kidFrame) {
+      // We've pulled up all the children from that next-in-flow, so
+      // move to the next next-in-flow.
+      nextInFlow = (nsBlockFrame*) nextInFlow->mNextInFlow;
+      continue;
+    }
+
+    // Get style information for the pulled up kid
+    nsIContent* kid = kidFrame->GetContent();
+    nsIStyleContext* kidSC = aCX->ResolveStyleContextFor(kid, this);
+    nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID);
+
+    ReflowStatus status;
+    do {
+      PRIntn placeStatus = PlaceAndReflowChild(aCX, aState, kidFrame, kidMol);
+      status = aState.reflowStatus;
+      if (0 == (placeStatus & PLACE_FIT)) {
+        // Push the kids that didn't fit back down to the next-in-flow
+        mLastContentIsComplete = PRBool(nsnull == kidFrame->GetNextInFlow());
+        PushKids(aState);
+
+        result = PR_FALSE;
+        NS_RELEASE(kid);
+        NS_RELEASE(kidSC);
+        goto push_done;
+      }
+
+      if (frNotComplete == status) {
+        // Child is not complete
+        nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow();
+        if (nsnull == kidNextInFlow) {
+          // Create a continuing frame for the incomplete child
+          nsIFrame* continuingFrame =
+            kidFrame->CreateContinuingFrame(aCX, this);
+
+          // Add the continuing frame to our sibling list.
+          continuingFrame->SetNextSibling(kidFrame->GetNextSibling());
+          kidFrame->SetNextSibling(continuingFrame);
+          prevKidFrame = kidFrame;
+          kidFrame = continuingFrame;
+          mChildCount++;
+
+          // Switch to new kid style
+          NS_RELEASE(kidSC);
+          kidSC = kidFrame->GetStyleContext(aCX);
+          kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID);
+        } else {
+          // The child has a next-in-flow, but it's not one of ours.
+          // It *must* be in one of our next-in-flows. Collect it
+          // then.
+          NS_ASSERTION(kidNextInFlow->GetGeometricParent() != this,
+                       "busted kid next-in-flow");
+          break;
+        }
+      }
+    } while (frNotComplete == status);
+    NS_RELEASE(kid);
+    NS_RELEASE(kidSC);
+
+    prevKidFrame = kidFrame;
+  }
+
+  if (nsnull != prevKidFrame) {
+    // The only way we can get here is by pulling up every last child
+    // in our next-in-flows (and reflowing any continunations they
+    // have). Therefore we KNOW that our last child is complete.
+    NS_ASSERTION(PR_TRUE == aState.lastContentIsComplete, "bad state");
+    NS_ASSERTION(LastChild() == prevKidFrame, "bad last child");
+    SetLastContentOffset(prevKidFrame);
+  }
+
+ push_done:;
+
+  if (result == PR_FALSE) {
+    // If our next-in-flow is empty OR our next next-in-flow is empty
+    // then adjust the offsets of all of the empty next-in-flows.
+    nextInFlow = (nsBlockFrame*) mNextInFlow;
+    if ((0 == nextInFlow->mChildCount) ||
+        ((nsnull != nextInFlow->mNextInFlow) &&
+         (0 == ((nsBlockFrame*)(nextInFlow->mNextInFlow))->mChildCount))) {
+      // We didn't pullup everything and we need to fixup one of our
+      // next-in-flows content offsets.
+      AdjustOffsetOfEmptyNextInFlows();
+    }
+  }
+
+
+#ifdef NS_DEBUG
+  PRInt32 len = LengthOf(mFirstChild);
+  NS_ASSERTION(len == mChildCount, "bad child count");
+  VerifyLastIsComplete();
+#endif
+#ifdef NOISY
+  ListTag(stdout);
+  printf(": pullup %sok (childCount=%d) [%d,%d,%c]\n",
+         (result ? "" : "NOT "),
+         mChildCount,
+         mFirstContentOffset, mLastContentOffset,
+         (mLastContentIsComplete ? 'T' : 'F'));
+  DumpFlow();
+#endif
+  return result;
+}
+
+void nsBlockFrame::SetupState(nsIPresContext* aCX,
+                              nsBlockReflowState& aState,
+                              const nsSize& aMaxSize,
+                              nsSize* aMaxElementSize,
+                              nsISpaceManager* aSpaceManager)
+{
+  // Setup reflow state
+  nsStyleMolecule* mol =
+    (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID);
+  nsStyleFont* font =
+    (nsStyleFont*)mStyleContext->GetData(kStyleFontSID);
+  aState.Init(aMaxSize, aMaxElementSize, font, mol, aSpaceManager);
+
+  // Apply border and padding adjustments for regular frames only
+  if (PR_FALSE == IsPseudoFrame()) {
+    aState.borderPadding = mol->borderPadding;
+    aState.y = mol->borderPadding.top;
+    aState.availSize.width -=
+      (mol->borderPadding.left + mol->borderPadding.right);
+    aState.availSize.height -=
+      (mol->borderPadding.top + mol->borderPadding.bottom);
+  } else {
+    aState.borderPadding.SizeTo(0, 0, 0, 0);
+  }
+
+  // Setup initial list ordinal value
+  nsIAtom* tag = mContent->GetTag();
+  if ((tag == nsHTMLAtoms::ul) || (tag == nsHTMLAtoms::ol) ||
+      (tag == nsHTMLAtoms::menu) || (tag == nsHTMLAtoms::dir)) {
+    nsHTMLValue value;
+    if (eContentAttr_HasValue ==
+        ((nsIHTMLContent*)mContent)->GetAttribute(nsHTMLAtoms::start, value)) {
+      if (eHTMLUnit_Absolute == value.GetUnit()) {
+        aState.nextListOrdinal = value.GetIntValue();
+      }
+    }
+  }
+  NS_RELEASE(tag);
+
+  mCurrentState = &aState;
+}
+
+#include "nsUnitConversion.h"/* XXX */
+nsIFrame::ReflowStatus
+nsBlockFrame::ResizeReflow(nsIPresContext* aCX,
+                           nsISpaceManager* aSpaceManager,
+                           const nsSize& aMaxSize,
+                           nsRect& aDesiredRect,
+                           nsSize* aMaxElementSize)
+{
+  nsBlockReflowState state;
+  SetupState(aCX, state, aMaxSize, aMaxElementSize, aSpaceManager);
+  return DoResizeReflow(aCX, state, aDesiredRect);
+}
+
+nsIFrame::ReflowStatus
+nsBlockFrame::DoResizeReflow(nsIPresContext* aCX,
+                             nsBlockReflowState& aState,
+                             nsRect& aDesiredRect)
+{
+#ifdef NS_DEBUG
+  PreReflowCheck();
+#endif
+#ifdef NOISY
+  ListTag(stdout);
+  printf(": resize reflow %g,%g\n",
+         NS_TWIPS_TO_POINTS_FLOAT(aState.availSize.width),
+         NS_TWIPS_TO_POINTS_FLOAT(aState.availSize.height));
+  DumpFlow();
+#endif
+
+  // Zap old line data
+  if (nsnull != mLines) {
+    delete mLines;
+    mLines = nsnull;
+  }
+  mNumLines = 0;
+
+  // Check for an overflow list
+  MoveOverflowToChildList();
+
+  // Before we start reflowing, cache a pointer to our state structure
+  // so that inline frames can find it.
+  nsIPresShell* shell = aCX->GetShell();
+  shell->PutCachedData(this, &aState);
+
+  // First reflow any existing frames
+  PRBool reflowMappedOK = PR_TRUE;
+  ReflowStatus status = frComplete;
+  if (nsnull != mFirstChild) {
+    reflowMappedOK = ReflowMappedChildren(aCX, aState);
+    if (!reflowMappedOK) {
+      status = frNotComplete;
+    }
+  }
+
+  if (reflowMappedOK) {
+    // Any space left?
+    nscoord yb = aState.borderPadding.top + aState.availSize.height;
+    if ((nsnull != mFirstChild) && (aState.y >= yb)) {
+      // No space left. Don't try to pull-up children or reflow
+      // unmapped.  We need to return the correct completion status,
+      // so see if there is more to reflow.
+      if (MoreToReflow(aCX)) {
+        status = frNotComplete;
+      }
+    } else if (MoreToReflow(aCX)) {
+      // Try and pull-up some children from a next-in-flow
+      if ((nsnull == mNextInFlow) || PullUpChildren(aCX, aState)) {
+        // If we still have unmapped children then create some new frames
+        if (MoreToReflow(aCX)) {
+          status = ReflowAppendedChildren(aCX, aState);
+        }
+      } else {
+        // We were unable to pull-up all the existing frames from the
+        // next in flow
+        status = frNotComplete;
+      }
+    }
+  }
+
+  // Deal with last line - make sure it gets vertically and
+  // horizontally aligned. This also updates the state's y coordinate
+  // which is good because that's how we size ourselves.
+  if (0 != aState.lineLength) {
+    if (!AdvanceToNextLine(aCX, aState)) {
+      // The last line of output doesn't fit. Push all of the kids to
+      // the next in flow and change our reflow status to not complete
+      // so that we are continued.
+#ifdef NOISY
+      ListTag(stdout);
+      printf(": pushing kids since last line doesn't fit\n");
+#endif
+
+      PushKids(aState);
+      status = frNotComplete;
+    }
+  }
+
+  if (frComplete == status) {
+    // Don't forget to add in the bottom margin from our last child.
+    // Only add it in if there is room for it.
+    nscoord margin = aState.prevMaxPosBottomMargin -
+      aState.prevMaxNegBottomMargin;
+    nscoord y = aState.y + margin;
+    if (y <= aState.borderPadding.top + aState.availSize.height) {
+      aState.y = y;
+    }
+  }
+
+  // Now that reflow has finished, remove the cached pointer
+  shell->RemoveCachedData(this);
+  NS_RELEASE(shell);
+
+  // Translate state.lineLengths into an integer array
+  mNumLines = aState.lineLengths.Count();
+  if (mNumLines > 0) {
+    mLines = new PRInt32[mNumLines];
+    for (PRInt32 i = 0; i < mNumLines; i++) {
+      PRInt32 ll = (PRInt32) aState.lineLengths.ElementAt(i);
+      mLines[i] = ll;
+    }
+  }
+
+  if (!aState.unconstrainedWidth && aState.justifying) {
+    // Perform justification now that we know how many lines we have.
+    JustifyLines(aCX, aState);
+  }
+
+  // Return our desired rect and our status
+  aDesiredRect.x = 0;
+  aDesiredRect.y = 0;
+  aDesiredRect.width = aState.kidXMost + aState.borderPadding.right;
+  if (!aState.unconstrainedWidth) {
+    // Make sure we're at least as wide as the max size we were given
+    nscoord maxWidth = aState.availSize.width + aState.borderPadding.left +
+                       aState.borderPadding.right;
+
+    if (aDesiredRect.width < maxWidth) {
+      aDesiredRect.width = maxWidth;
+    }
+  }
+  aState.y += aState.borderPadding.bottom;
+  aDesiredRect.height = aState.y;
+
+#ifdef NS_DEBUG
+  PostReflowCheck(status);
+#endif
+#ifdef NOISY
+  ListTag(stdout);
+  printf(": resize reflow %g,%g %scomplete [%d,%d,%c]\n",
+         NS_TWIPS_TO_POINTS_FLOAT(aState.availSize.width),
+         NS_TWIPS_TO_POINTS_FLOAT(aState.availSize.height),
+         ((status == frNotComplete) ? "NOT " : ""),
+         mFirstContentOffset, mLastContentOffset,
+         (mLastContentIsComplete ? 'T' : 'F')
+    );
+  DumpFlow();
+#endif
+  mCurrentState = nsnull;
+  return status;
+}
+
+void nsBlockFrame::JustifyLines(nsIPresContext* aCX,
+                                nsBlockReflowState& aState)
+{
+  // XXX we don't justify the last line; what if we are continued,
+  // should we do it then?
+  nsIFrame* kid = mFirstChild;
+  for (PRInt32 i = 0; i < mNumLines; i++) {
+    nsIFrame* lineStart = kid;
+    PRInt32 lineLength = mLines[i];
+    if (i < mNumLines - 1) {
+      if (1 == lineLength) {
+        // For lines with one element on them we can take a shortcut and
+        // let them do the justification. Note that we still call
+        // JustifyReflow even if the available space is zero in case the
+        // child is a hunk of text that ends in whitespace. The whitespace
+        // will be distributed elsewhere causing a proper flush right look
+        // for the last word.
+        nsRect r;
+        kid->GetRect(r);
+        nscoord maxWidth = aState.availSize.width;
+        nscoord availableSpace = maxWidth - r.width;
+        nscoord maxAvailSpace = nscoord(maxWidth * 0.1f);
+        if ((availableSpace >= 0) && (availableSpace < maxAvailSpace)) {
+          kid->JustifyReflow(aCX, availableSpace);
+          kid->SizeTo(r.width + availableSpace, r.height);
+        }
+        kid = kid->GetNextSibling();
+      } else {
+        // XXX Get justification of multiple elements working
+        while (--lineLength >= 0) {
+          kid = kid->GetNextSibling();
+        }
+      }
+    }
+    
+    // Finally, now that the in-flow positions of the line's frames are
+    // known we can apply relative positioning if any of them need it.
+    nsCSSLayout::RelativePositionChildren(aCX, this, aState.mol,
+                                          lineStart, mLines[i]);
+  }
+}
+
+nsIFrame* nsBlockFrame::CreateContinuingFrame(nsIPresContext* aCX,
+                                              nsIFrame* aParent)
+{
+  nsBlockFrame* cf = new nsBlockFrame(mContent, mIndexInParent, aParent);
+  PrepareContinuingFrame(aCX, aParent, cf);
+  return cf;
+}
+
+nsIFrame::ReflowStatus
+nsBlockFrame::IncrementalReflow(nsIPresContext* aCX,
+                                nsISpaceManager* aSpaceManager,
+                                const nsSize& aMaxSize,
+                                nsRect& aDesiredRect,
+                                nsReflowCommand& aReflowCommand)
+{
+  ReflowStatus status = frComplete;
+
+  if (aReflowCommand.GetTarget() == this) {
+    // XXX for now, just do a complete reflow mapped (it'll kinda
+    // work, but it's slow)
+
+    nsBlockReflowState state;
+    SetupState(aCX, state, aMaxSize, nsnull, aSpaceManager);
+    PRBool reflowMappedOK = ReflowMappedChildren(aCX, state);
+    if (!reflowMappedOK) {
+      status = frNotComplete;
+    }
+  } else {
+    // XXX not yet implemented
+    NS_ABORT();
+    // XXX work to compute initial state goes *HERE*
+    aDesiredRect.x = 0;
+    aDesiredRect.y = 0;
+    aDesiredRect.width = 0;
+    aDesiredRect.height = 0;
+  }
+
+  mCurrentState = nsnull;
+  return status;
+}
+
+PRBool nsBlockFrame::IsLeftMostChild(nsIFrame* aFrame)
+{
+  do {
+    nsIFrame* parent = aFrame->GetGeometricParent();
+  
+    // See if there are any non-zero sized child frames that precede aFrame
+    // in the child list
+    nsIFrame* child = parent->FirstChild();
+  
+    while ((nsnull != child) && (aFrame != child)) {
+      // Is the child zero-sized?
+      if ((child->GetWidth() > 0) || (child->GetHeight() > 0)) {
+        // We found a non-zero sized child frame that precedes aFrame
+        return PR_FALSE;
+      }
+  
+      child = child->GetNextSibling();
+    }
+  
+    // aFrame is the left-most non-zero sized frame in its geometric parent.
+    // Walk up one level and check that its parent is left-most as well
+    aFrame = parent;
+  } while (aFrame != this);
+
+  return PR_TRUE;
+}
+
+PRBool nsBlockFrame::AddFloater(nsIPresContext* aCX,
+                                nsIFrame* aFloater,
+                                PlaceholderFrame* aPlaceholder)
+{
+  // Get the frame associated with the space manager, and get its nsIAnchoredItems
+  // interface
+  nsIFrame*          frame = mCurrentState->spaceManager->GetFrame();
+  nsIAnchoredItems*  anchoredItems = nsnull;
+
+  frame->QueryInterface(kIAnchoredItemsIID, (void**)&anchoredItems);
+  NS_ASSERTION(nsnull != anchoredItems, "no anchored items interface");
+
+  if (nsnull != anchoredItems) {
+    anchoredItems->AddAnchoredItem(aFloater, nsIAnchoredItems::anHTMLFloater, this);
+    PlaceFloater(aCX, aFloater, aPlaceholder);
+    return PR_TRUE;
+  }
+
+  return PR_FALSE;
+}
+
+// XXX The size of the floater needs to be taken into consideration if we're
+// computing a maximum element size
+void nsBlockFrame::PlaceFloater(nsIPresContext* aCX,
+                                nsIFrame* aFloater,
+                                PlaceholderFrame* aPlaceholder)
+{
+  // If the floater is the left-most non-zero size child frame then insert
+  // it before the current line; otherwise add it to the below-current-line
+  // todo list and we'll handle it when we flush out the line
+  if (IsLeftMostChild(aPlaceholder)) {
+    // Get the type of floater
+    nsIStyleContext*  styleContext = aFloater->GetStyleContext(aCX);
+    nsStyleMolecule*  mol = (nsStyleMolecule*)styleContext->GetData(kStyleMoleculeSID);
+    NS_RELEASE(styleContext);
+
+    if (!mCurrentState->isInline) {
+      // Get the current band for this line
+      GetAvailableSpaceBand(*mCurrentState, mCurrentState->y + mCurrentState->topMargin);
+    }
+  
+    // Commit some space in the space manager
+    nsRect  region;
+
+    aFloater->GetRect(region);
+    region.y = mCurrentState->currentBand->rects[0].y;
+
+    if (NS_STYLE_FLOAT_LEFT == mol->floats) {
+      region.x = mCurrentState->currentBand->rects[0].x;
+    } else {
+      NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == mol->floats, "bad float type");
+      region.x = mCurrentState->currentBand->rects[0].XMost() - region.width;
+    }
+
+    // XXX Don't forget the floater's margins...
+    mCurrentState->spaceManager->Translate(mCurrentState->borderPadding.left, 0);
+    mCurrentState->spaceManager->AddRectRegion(region);
+
+    // Set the origin of the floater in world coordinates
+    nscoord worldX, worldY;
+
+    mCurrentState->spaceManager->GetTranslation(worldX, worldY);
+    aFloater->MoveTo(region.x + worldX, region.y + worldY);
+    mCurrentState->spaceManager->Translate(-mCurrentState->borderPadding.left, 0);
+
+    // Update the band of available space to reflect space taken up by the floater
+    GetAvailableSpaceBand(*mCurrentState, mCurrentState->y + mCurrentState->topMargin);
+  } else {
+    // Add the floater to our to-do list
+    mCurrentState->floaterToDo.AppendElement(aFloater);
+  }
+}
+
+void nsBlockFrame::ContentAppended(nsIPresShell* aShell,
+                                   nsIPresContext* aPresContext,
+                                   nsIContent* aContainer)
+{
+  // Zip down to the end-of-flow
+  nsBlockFrame* flow = this;
+  for (;;) {
+    nsBlockFrame* next = (nsBlockFrame*) flow->GetNextInFlow();
+    if (nsnull == next) {
+      break;
+    }
+    flow = next;
+  }
+
+  PRInt32 kidIndex = flow->NextChildOffset();
+  PRInt32 startIndex = kidIndex;
+  nsIFrame* prevKidFrame = flow->LastChild();
+  nsIFrame* kidFrame = nsnull;
+  for (;;) {
+    // Get the next content object
+    nsIContent* kid = mContent->ChildAt(kidIndex);
+    if (nsnull == kid) {
+      break;
+    }
+
+    // Resolve style for the kid
+    nsIStyleContext* kidSC = aPresContext->ResolveStyleContextFor(kid, this);
+    nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID);
+
+    // Is it a floater?
+    if (kidMol->floats != NS_STYLE_FLOAT_NONE) {
+      PlaceholderFrame::NewFrame(&kidFrame, kid, kidIndex, this);
+    } else {
+      // Create initial frame for the child
+      nsIContentDelegate* kidDel;
+      nsresult fr;
+      switch (kidMol->display) {
+      case NS_STYLE_DISPLAY_BLOCK:
+      case NS_STYLE_DISPLAY_LIST_ITEM:
+        // Pseudo block frames do not contain other block elements
+        // unless the block element would be the first child.
+        if (IsPseudoFrame()) {
+          // Update last content offset now that we are done drawing
+          // children from our parent.
+          SetLastContentOffset(prevKidFrame);
+  
+          // It better be true that we are not being asked to flow a
+          // block element as our first child. That means the body
+          // decided it needed a pseudo-frame when it shouldn't have.
+          NS_ASSERTION(nsnull != mFirstChild, "bad body");
+  
+          NS_RELEASE(kidSC);
+          NS_RELEASE(kid);
+  
+          return;
+        }
+        // FALL THROUGH (and create frame)
+  
+      case NS_STYLE_DISPLAY_INLINE:
+        kidDel = kid->GetDelegate(aPresContext);
+        kidFrame = kidDel->CreateFrame(aPresContext, kid, kidIndex, this);
+        NS_RELEASE(kidDel);
+        break;
+  
+      default:
+        fr = nsFrame::NewFrame(&kidFrame, kid, kidIndex, this);
+        break;
+      }
+    }
+    kidFrame->SetStyleContext(kidSC);
+    NS_RELEASE(kidSC);
+    NS_RELEASE(kid);
+
+    // Link child frame into the list of children
+    if (nsnull != prevKidFrame) {
+      NS_ASSERTION(nsnull == prevKidFrame->GetNextSibling(), "bad append");
+      prevKidFrame->SetNextSibling(kidFrame);
+    } else {
+      NS_ASSERTION(nsnull == mFirstChild, "bad create");
+      mFirstChild = kidFrame;
+      SetFirstContentOffset(kidFrame);
+    }
+    prevKidFrame = kidFrame;
+    kidIndex++;
+    mChildCount++;
+  }
+  SetLastContentOffset(prevKidFrame);
+
+  // If this is a pseudo-frame then our parent will generate the
+  // reflow command. Otherwise, if the container is us then we should
+  // generate the reflow command because we were directly called.
+  if (!IsPseudoFrame() && (aContainer == mContent)) {
+    nsReflowCommand* rc =
+      new nsReflowCommand(aPresContext, flow, nsReflowCommand::FrameAppended,
+                          startIndex);
+    aShell->AppendReflowCommand(rc);
+  }
+}
+
+PRIntn nsBlockFrame::GetSkipSides() const
+{
+  PRIntn skip = 0;
+  if (nsnull != mPrevInFlow) {
+    skip |= 1 << NS_SIDE_TOP;
+  }
+  if (nsnull != mNextInFlow) {
+    skip |= 1 << NS_SIDE_BOTTOM;
+  }
+  return skip;
+}
+
+nsHTMLFrameType nsBlockFrame::GetFrameType() const
+{
+  return eHTMLFrame_Block;
+}
+
+void nsBlockFrame::ListTag(FILE* out) const
+{
+  if ((nsnull != mGeometricParent) && IsPseudoFrame()) {
+    fprintf(out, "*block(%d)@%p", mIndexInParent, this);
+  } else {
+    nsHTMLContainerFrame::ListTag(out);
+  }
+}
+
+#ifdef NS_DEBUG
+void nsBlockFrame::DumpFlow() const
+{
+#ifdef NOISY_FLOW
+  nsBlockFrame* flow = (nsBlockFrame*) mNextInFlow;
+  while (flow != 0) {
+    printf("  %p: [%d,%d,%c]\n",
+           flow, flow->mFirstContentOffset, flow->mLastContentOffset,
+           (flow->mLastContentIsComplete ? 'T' : 'F'));
+    flow = (nsBlockFrame*) flow->mNextInFlow;
+  }
+#endif
+}
+#endif
diff --git a/mozilla/layout/generic/nsBlockFrame.h b/mozilla/layout/generic/nsBlockFrame.h
new file mode 100644
index 00000000000..ab55c5dbeed
--- /dev/null
+++ b/mozilla/layout/generic/nsBlockFrame.h
@@ -0,0 +1,318 @@
+/* -*- 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.
+ */
+#ifndef nsBlockFrame_h___
+#define nsBlockFrame_h___
+
+#include "nsHTMLContainerFrame.h"
+#include "nsIFloaterContainer.h"
+#include "nsIHTMLFrameType.h"
+#include "nsIRunaround.h"
+#include "nsVoidArray.h"
+struct BlockBandData;
+struct nsMargin;
+struct nsStyleFont;
+
+/**
+ * Block frames have some state which needs to be made
+ * available to child frames for proper reflow. This structure
+ * describes that state.
+ */
+struct nsBlockReflowState {
+  // True if this is the first line of text in a block container
+  PRPackedBool firstLine;
+
+  // True if leading whitespace is allowed to show
+  PRPackedBool allowLeadingWhitespace;
+
+  // This is set when some child frame needs a break after it's placed
+  PRPackedBool breakAfterChild;
+
+  // This is set when a child needs a break before it's placed. Note
+  // that this value is set by a child AFTER we have called it's
+  // ResizeReflow method.
+  PRPackedBool breakBeforeChild;
+
+  // This is set when the first child should be treated specially
+  // because it's an inside list item bullet.
+  // XXX this can go away once we have a way for the bullet's style
+  // molecule to *not* be the same as it's parent's
+  PRPackedBool firstChildIsInsideBullet;
+
+  // For pre-formatted text, this is our current column
+  PRIntn column;
+
+  // The next list ordinal value
+  PRInt32 nextListOrdinal;
+
+  //----------------------------------------------------------------------
+  // State from here on down is not to be used by block child frames!
+
+  // Space manager to use
+  nsISpaceManager* spaceManager;
+
+  // Block's style data
+  nsStyleFont* font;
+  nsStyleMolecule* mol;
+
+  // Block's available size (computed from the block's parent)
+  nsSize availSize;
+
+  // Current band of available space. Used for doing runaround
+  BlockBandData* currentBand;
+
+  // Pointer to a max-element-size (nsnull if none required)
+  nsSize* maxElementSize;
+
+  // The maximum x-most of our lines and block-level elements. This is used to
+  // compute our desired size, and includes our left border/padding. For block-
+  // level elements this also includes the block's right margin.
+  nscoord kidXMost;
+
+  // Current reflow position
+  nscoord y;
+
+  // Current line state
+  nscoord x;                            // inline elements only. not include border/padding
+  PRBool  isInline;                     // whether the current is inline or block
+  nsVoidArray lineLengths;              // line length temporary storage
+  PRIntn currentLineNumber;             // index into mLines
+  nsIFrame* lineStart;                  // frame starting the line
+  PRInt32 lineLength;                   // length of line
+  nscoord* ascents;                     // ascent information for each child
+  nscoord maxAscent;                    // max ascent for this line
+  nscoord maxDescent;                   // max descent for this line
+  nscoord lineWidth;                    // current width of line
+#if 0
+  nscoord maxPosTopMargin;              // maximum positive top margin
+  nscoord maxNegTopMargin;              // maximum negative top margin
+#else
+  nscoord topMargin;                    // current top margin
+#endif
+  nscoord maxPosBottomMargin;           // maximum positive bottom margin
+  nscoord maxNegBottomMargin;           // maximum negative bottom margin
+  nsSize lineMaxElementSize;            // max element size for current line
+  PRBool lastContentIsComplete;         // reflow status of last child on line
+  nsVoidArray floaterToDo;              // list of floaters to place below current line
+
+  PRInt32 maxAscents;                   // size of ascent buffer
+  nscoord ascentBuf[20];
+
+  PRPackedBool needRelativePos;         // some kid in line needs relative pos
+
+  // Previous line state that we carry forward to the next line
+  nsIFrame* prevLineLastFrame;
+  nscoord prevLineHeight;               // height of the previous line
+  nscoord prevMaxPosBottomMargin;       // maximum posative bottom margin
+  nscoord prevMaxNegBottomMargin;       // maximum negative bottom margin
+  PRBool prevLineLastContentIsComplete;
+
+  // Sanitized version of mol->borderPadding; if this block frame is a
+  // pseudo-frame then the margin will be zero'd.
+  nsMargin borderPadding;
+
+  PRPackedBool justifying;              // we are justifying
+
+  // Status from last PlaceAndReflowChild
+  nsIFrame::ReflowStatus reflowStatus;
+
+  // Flags for whether the max size is unconstrained
+  PRBool  unconstrainedWidth;
+  PRBool  unconstrainedHeight;
+
+  nsBlockReflowState();
+
+  ~nsBlockReflowState();
+
+  void Init(const nsSize& aMaxSize, nsSize* aMaxElementSize,
+            nsStyleFont* aFont, nsStyleMolecule* aMol, nsISpaceManager* aSpaceManager);
+
+  void AddAscent(nscoord aAscent);
+  void AdvanceToNextLine(nsIFrame* aPrevLineLastFrame, nscoord aPrevLineHeight);
+
+#ifdef NS_DEBUG
+  void DumpLine();
+  void DumpList();
+#endif
+};
+
+//----------------------------------------------------------------------
+
+/**
+ * 

Block Reflow

+ * + * The block frame reflow machinery performs "2D" layout. Inline + * elements are flowed into logical lines (left to right or right to + * left) and the lines are stacked vertically. Block elements are + * flowed onto their own line after flushing out any preceeding line.

+ * + * After a line is ready to be flushed out, vertical alignment is + * performed. Vertical alignment may require the line to consume more + * vertical space than is available thus causing the entire line to + * be pushed.

+ * + * After vertical alignment is done, horizontal alignment (including + * justification) is performed. Finally, relative positioning is done + * on any elements that require it.

+ * + * During reflow, the block frame will make available to child frames + * it's reflow state using the presentation shell's cached data + * mechanism.

+ * + *

Reflowing Mapped Content

+ *

Pullup

+ *

Reflowing Unmapped Content

+ *

Content Insertion Handling

+ *

Content Deletion Handling

+ *

Style Change Handling

+ * + *

Assertions

+ * mLastContentIsComplete always reflects the state of the last + * child frame on our chlid list. + */ +class nsBlockFrame : public nsHTMLContainerFrame, public nsIHTMLFrameType, + public nsIRunaround, public nsIFloaterContainer +{ +public: + /** + * Create a new block frame that maps the given piece of content. + */ + static nsresult NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); + + virtual ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsSize* aMaxElementSize); + + virtual ReflowStatus IncrementalReflow(nsIPresContext* aPresContext, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsReflowCommand& aReflowCommand); + + virtual void ContentAppended(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer); + + virtual nsIFrame* CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent); + + virtual PRBool AddFloater(nsIPresContext* aCX, + nsIFrame* aFloater, + PlaceholderFrame* aPlaceholder); + virtual void PlaceFloater(nsIPresContext* aCX, + nsIFrame* aFloater, + PlaceholderFrame* aPlaceholder); + + virtual void ListTag(FILE* out = stdout) const; + + virtual nsHTMLFrameType GetFrameType() const; + +protected: + nsBlockFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + virtual ~nsBlockFrame(); + + virtual PRIntn GetSkipSides() const; + + PRBool MoreToReflow(nsIPresContext* aCX); + + nscoord GetTopMarginFor(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsStyleMolecule* aKidMol, + PRBool aIsInline); + + PRBool AdvanceToNextLine(nsIPresContext* aPresContext, + nsBlockReflowState& aState); + + void AddInlineChildToLine(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsIFrame* aKidFrame, + nsReflowMetrics& aKidSize, + nsSize* aKidMaxElementSize, + nsStyleMolecule* aKidMol); + + void AddBlockChild(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsIFrame* aKidFrame, + nsRect& aKidRect, + nsSize* aKidMaxElementSize, + nsStyleMolecule* aKidMol); + + void GetAvailSize(nsSize& aResult, + nsBlockReflowState& aState, + nsStyleMolecule* aKidMol, + PRBool aIsInline); + + PRIntn PlaceAndReflowChild(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsIFrame* kidFrame, + nsStyleMolecule* aKidMol); + + void PushKids(nsBlockReflowState& aState); + + void SetupState(nsIPresContext* aCX, nsBlockReflowState& aState, + const nsSize& aMaxSize, nsSize* aMaxElementSize, + nsISpaceManager* aSpaceManager); + + ReflowStatus DoResizeReflow(nsIPresContext* aPresContext, + nsBlockReflowState& aState, + nsRect& aDesiredRect); + + PRBool ReflowMappedChildren(nsIPresContext* aPresContext, + nsBlockReflowState& aState); + + PRBool PullUpChildren(nsIPresContext* aCX, + nsBlockReflowState& aState); + + ReflowStatus ReflowAppendedChildren(nsIPresContext* aPresContext, + nsBlockReflowState& aState); + + void JustifyLines(nsIPresContext* aPresContext, nsBlockReflowState& aState); + + PRBool IsLeftMostChild(nsIFrame* aFrame); + + void GetAvailableSpaceBand(nsBlockReflowState& aState, nscoord aY); + + void PlaceBelowCurrentLineFloaters(nsIPresContext* aCX, + nsBlockReflowState& aState, + nscoord aY); + + void ClearFloaters(nsBlockReflowState& aState, PRUint32 aClear); + +#ifdef NS_DEBUG + void DumpFlow() const; +#endif + + /** + * Array of lines lengths. For each logical line of children, this array + * contains a count of the number of children on the line. + */ + PRInt32* mLines; + PRInt32 mNumLines; + nsBlockReflowState* mCurrentState; +}; + +#endif /* nsBlockFrame_h___ */ diff --git a/mozilla/layout/generic/nsBlockReflowState.cpp b/mozilla/layout/generic/nsBlockReflowState.cpp new file mode 100644 index 00000000000..de26654f45d --- /dev/null +++ b/mozilla/layout/generic/nsBlockReflowState.cpp @@ -0,0 +1,2030 @@ +/* -*- 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 "nsBlockFrame.h" +#include "nsSize.h" +#include "nsIAnchoredItems.h" +#include "nsIContent.h" +#include "nsIContentDelegate.h" +#include "nsISpaceManager.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsIPresContext.h" +#include "nsMargin.h" +#include "nsHTMLIIDs.h" +#include "nsCSSLayout.h" +#include "nsCRT.h" +#include "nsIPresShell.h" +#include "nsReflowCommand.h" +#include "nsPlaceholderFrame.h" +#include "nsHTMLAtoms.h" +#include "nsHTMLValue.h" +#include "nsIHTMLContent.h" + +#ifdef NS_DEBUG +#undef NOISY +#undef NOISY_FLOW +#else +#undef NOISY +#undef NOISY_FLOW +#endif + +static NS_DEFINE_IID(kIRunaroundIID, NS_IRUNAROUND_IID); +static NS_DEFINE_IID(kIFloaterContainerIID, NS_IFLOATERCONTAINER_IID); +static NS_DEFINE_IID(kIAnchoredItemsIID, NS_IANCHOREDITEMS_IID); +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); +static NS_DEFINE_IID(kStyleFontSID, NS_STYLEFONT_SID); + +struct BlockBandData : public nsBandData { + nsRect data[5]; + + BlockBandData() {size = 5; rects = data;} +}; + +// XXX Bugs +// 1. right to left reflow can generate negative x coordinates. + +// XXX Speedup idea (all containers) + +// If I reflow a child and it gives back not-complete status then +// there is no sense in trying to pullup children. For blocks, it's a +// little more complicated unless the child is a block - if the child +// is a block, then we must be out of room hence we should stop. If +// the child is not a block then our line should be flushed (see #2 +// below) if our line is already empty then we must be out of room. + +// For inline frames and column frames, if we reflow a child and get +// back not-complete status then we should bail immediately because we +// are out of room. + +// XXX Speedup ideas: +// 1. change pullup code to use line information from next in flow +// 2. we can advance to next line immediately after reflowing something +// and noticing that it's not complete. +// 3. pass down last child information in aState so that pullup, etc., +// don't need to recompute it + +// XXX TODO: +// 0. Move justification into line flushing code + +// 1. To get ebina margins I need "auto" information from the style +// system margin's. A bottom/top margin of auto will then be computed like +// ebina computes it [however the heck that is]. + +// 2. kicking out floaters and talking with floater container to adjust +// left and right margins + +nsBlockReflowState::nsBlockReflowState() +{ +} + +void nsBlockReflowState::Init(const nsSize& aMaxSize, + nsSize* aMaxElementSize, + nsStyleFont* aFont, + nsStyleMolecule* aMol, + nsISpaceManager* aSpaceManager) +{ + firstLine = PR_TRUE; + allowLeadingWhitespace = PR_FALSE; + breakAfterChild = PR_FALSE; + breakBeforeChild = PR_FALSE; + firstChildIsInsideBullet = PR_FALSE; + nextListOrdinal = -1; + column = 0; + + spaceManager = aSpaceManager; + currentBand = new BlockBandData; + font = aFont; + mol = aMol; + availSize.width = aMaxSize.width; + availSize.height = aMaxSize.height; + maxElementSize = aMaxElementSize; + if (nsnull != aMaxElementSize) { + aMaxElementSize->width = 0; + aMaxElementSize->height = 0; + } + + kidXMost = 0; + x = 0; + y = 0; + + isInline = PR_FALSE; + currentLineNumber = 0; + lineStart = nsnull; + lineLength = 0; + ascents = ascentBuf; + maxAscent = 0; + maxDescent = 0; + lineWidth = 0; + maxPosBottomMargin = 0; + maxNegBottomMargin = 0; + lineMaxElementSize.width = 0; + lineMaxElementSize.height = 0; + lastContentIsComplete = PR_TRUE; + + maxAscents = sizeof(ascentBuf) / sizeof(ascentBuf[0]); + needRelativePos = PR_FALSE; + + prevLineLastFrame = nsnull; + prevLineHeight = 0; + topMargin = 0; + prevMaxPosBottomMargin = 0; + prevMaxNegBottomMargin = 0; + prevLineLastContentIsComplete = PR_TRUE; + + unconstrainedWidth = PRBool(aMaxSize.width == NS_UNCONSTRAINEDSIZE); + unconstrainedHeight = PRBool(aMaxSize.height == NS_UNCONSTRAINEDSIZE); + + justifying = (NS_STYLE_TEXT_ALIGN_JUSTIFY == mol->textAlign) && + (NS_STYLE_WHITESPACE_PRE != mol->whiteSpace); + reflowStatus = nsIFrame::frNotComplete; +} + +nsBlockReflowState::~nsBlockReflowState() +{ + if (ascents != ascentBuf) { + delete ascents; + } + delete currentBand; +} + +void nsBlockReflowState::AddAscent(nscoord aAscent) +{ + NS_PRECONDITION(lineLength <= maxAscents, "bad line length"); + if (lineLength == maxAscents) { + maxAscents *= 2; + nscoord* newAscents = new nscoord[maxAscents]; + if (nsnull != newAscents) { + nsCRT::memcpy(newAscents, ascents, sizeof(nscoord) * lineLength); + if (ascents != ascentBuf) { + delete ascents; + } + ascents = newAscents; + } else { + // Yikes! Out of memory! + return; + } + } + ascents[lineLength] = aAscent; +} + +void nsBlockReflowState::AdvanceToNextLine(nsIFrame* aPrevLineLastFrame, + nscoord aPrevLineHeight) +{ + firstLine = PR_FALSE; + allowLeadingWhitespace = PR_FALSE; + column = 0; + breakAfterChild = PR_FALSE; + breakBeforeChild = PR_FALSE; + lineStart = nsnull; + lineLength = 0; + currentLineNumber++; + maxAscent = 0; + maxDescent = 0; + lineWidth = 0; + needRelativePos = PR_FALSE; + + prevLineLastFrame = aPrevLineLastFrame; + prevLineHeight = aPrevLineHeight; + prevMaxPosBottomMargin = maxPosBottomMargin; + prevMaxNegBottomMargin = maxNegBottomMargin; + + // Remember previous line's lastContentIsComplete + prevLineLastContentIsComplete = lastContentIsComplete; + lastContentIsComplete = PR_TRUE; + + topMargin = 0; + maxPosBottomMargin = 0; + maxNegBottomMargin = 0; +} + +#ifdef NS_DEBUG +void nsBlockReflowState::DumpLine() +{ + nsIFrame* f = lineStart; + PRInt32 ll = lineLength; + while (--ll >= 0) { + printf(" "); + ((nsFrame*)f)->ListTag(stdout);/* XXX */ + printf("\n"); + f = f->GetNextSibling(); + } +} + +void nsBlockReflowState::DumpList() +{ + nsIFrame* f = lineStart; + while (nsnull != f) { + printf(" "); + ((nsFrame*)f)->ListTag(stdout);/* XXX */ + printf("\n"); + f = f->GetNextSibling(); + } +} +#endif + +//---------------------------------------------------------------------- + +nsresult nsBlockFrame::NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIFrame* it = new nsBlockFrame(aContent, aIndexInParent, aParent); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aInstancePtrResult = it; + return NS_OK; +} + +nsBlockFrame::nsBlockFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) + : nsHTMLContainerFrame(aContent, aIndexInParent, aParent) +{ +} + +nsBlockFrame::~nsBlockFrame() +{ + if (nsnull != mLines) { + delete mLines; + } +} + +nsresult +nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) +{ + NS_PRECONDITION(0 != aInstancePtr, "null ptr"); + if (NULL == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kIHTMLFrameTypeIID)) { + *aInstancePtr = (void*) ((nsIHTMLFrameType*) this); + return NS_OK; + } else if (aIID.Equals(kIRunaroundIID)) { + *aInstancePtr = (void*) ((nsIRunaround*) this); + return NS_OK; + } else if (aIID.Equals(kIFloaterContainerIID)) { + *aInstancePtr = (void*) ((nsIFloaterContainer*) this); + return NS_OK; + } + return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr); +} + +// Computes the top margin to use for this child frames based on its display +// type and the display type of the previous child frame. +// +// Adjacent vertical margins between block-level elements are collapsed. +nscoord nsBlockFrame::GetTopMarginFor(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsStyleMolecule* aKidMol, + PRBool aIsInline) +{ + if (aIsInline) { + // Just use whatever the previous bottom margin was + return aState.prevMaxPosBottomMargin - aState.prevMaxNegBottomMargin; + } else { + nscoord maxNegTopMargin = 0; + nscoord maxPosTopMargin = 0; + if (aKidMol->margin.top < 0) { + maxNegTopMargin = -aKidMol->margin.top; + } else { + maxPosTopMargin = aKidMol->margin.top; + } + + nscoord maxPos = PR_MAX(aState.prevMaxPosBottomMargin, maxPosTopMargin); + nscoord maxNeg = PR_MAX(aState.prevMaxNegBottomMargin, maxNegTopMargin); + return maxPos - maxNeg; + } +} + +void nsBlockFrame::PlaceBelowCurrentLineFloaters(nsIPresContext* aCX, + nsBlockReflowState& aState, + nscoord aY) +{ + NS_PRECONDITION(aState.floaterToDo.Count() > 0, "no floaters"); + + // XXX Factor this code with PlaceFloater()... + PRInt32 numFloaters = aState.floaterToDo.Count(); + + for (PRInt32 i = 0; i < numFloaters; i++) { + nsIFrame* floater = (nsIFrame*)aState.floaterToDo[i]; + nsRect region; + + // Get the band of available space + // XXX This is inefficient to do this inside the loop... + GetAvailableSpaceBand(aState, aY); + + // Get the type of floater + nsIStyleContext* styleContext = floater->GetStyleContext(aCX); + nsStyleMolecule* mol = (nsStyleMolecule*)styleContext->GetData(kStyleMoleculeSID); + NS_RELEASE(styleContext); + + floater->GetRect(region); + region.y = mCurrentState->currentBand->rects[0].y; + + if (NS_STYLE_FLOAT_LEFT == mol->floats) { + region.x = mCurrentState->currentBand->rects[0].x; + } else { + NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == mol->floats, "bad float type"); + region.x = mCurrentState->currentBand->rects[0].XMost() - region.width; + } + + // XXX Don't forget the floater's margins... + mCurrentState->spaceManager->Translate(mCurrentState->borderPadding.left, 0); + mCurrentState->spaceManager->AddRectRegion(region); + + // Set the origin of the floater in world coordinates + nscoord worldX, worldY; + + mCurrentState->spaceManager->GetTranslation(worldX, worldY); + floater->MoveTo(region.x + worldX, region.y + worldY); + mCurrentState->spaceManager->Translate(-mCurrentState->borderPadding.left, 0); + } + aState.floaterToDo.Clear(); +} + +/** + * Flush a line out. Return true if the line fits in our available + * height. If the line does not fit then return false. When the line + * fits we advance the y coordinate, reset the x coordinate and + * prepare the nsBlockReflowState for the next line. + */ +PRBool nsBlockFrame::AdvanceToNextLine(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ + NS_PRECONDITION(aState.lineLength > 0, "bad line"); + NS_PRECONDITION(nsnull != aState.lineStart, "bad line"); + + nscoord y = aState.y + aState.topMargin; + nscoord lineHeight; + + if (aState.isInline) { + // Vertically align the children on this line, returning the height of + // the line upon completion. + lineHeight = nsCSSLayout::VerticallyAlignChildren(aCX, this, aState.font, y, + aState.lineStart, aState.lineLength, + aState.ascents, aState.maxAscent); + + // Any below current line floaters to place? + if (aState.floaterToDo.Count() > 0) { + PlaceBelowCurrentLineFloaters(aCX, aState, y + lineHeight); + // XXX Factor in the height of the floaters as well when considering + // whether the line fits. + // The default policy is that if there isn't room for the floaters then + // both the line and the floaters are pushed to the next-in-flow... + } + } else { + lineHeight = aState.lineStart->GetHeight(); + } + + // The first line always fits + if (aState.currentLineNumber > 0) { + nscoord yb = aState.borderPadding.top + aState.availSize.height; + if (y + lineHeight > yb) { + // After vertical alignment of the children and factoring in the + // proper margin, the line doesn't fit. + return PR_FALSE; + } + } + + if (aState.isInline) { + // Check if the right-edge of the line exceeds our running x-most + nscoord xMost = aState.borderPadding.left + aState.lineWidth; + if (xMost > aState.kidXMost) { + aState.kidXMost = xMost; + } + } + + // Advance the y coordinate to the new position where the next + // line or block element will go. + aState.y = y + lineHeight; + aState.x = 0; + + // Now that the vertical alignment is done we can perform horizontal + // alignment and relative positioning. Skip all of these if we are + // doing an unconstrained (in x) reflow. There's no point in doing + // the work if we *know* we are going to reflowed again. + if (!aState.unconstrainedWidth) { + nsCSSLayout::HorizontallyPlaceChildren(aCX, this, aState.mol, + aState.lineStart, aState.lineLength, + aState.lineWidth, + aState.availSize.width); + + // Finally, now that the in-flow positions of the line's frames are + // known we can apply relative positioning if any of them need it. + if (!aState.justifying) { + nsCSSLayout::RelativePositionChildren(aCX, this, aState.mol, + aState.lineStart, + aState.lineLength); + } + } + + // Record line length + aState.lineLengths.AppendElement((void*)aState.lineLength); + + // Find the last frame in the line + // XXX keep this as running state in the nsBlockReflowState + nsIFrame* lastFrame = aState.lineStart; + PRInt32 lineLen = aState.lineLength - 1; + while (--lineLen >= 0) { + lastFrame = lastFrame->GetNextSibling(); + } + + // Update maxElementSize + if (nsnull != aState.maxElementSize) { + nsSize& lineMax = aState.lineMaxElementSize; + nsSize* maxMax = aState.maxElementSize; + if (lineMax.width > maxMax->width) { + maxMax->width = lineMax.width; + } + if (lineMax.height > maxMax->height) { + maxMax->height = lineMax.height; + } + aState.lineMaxElementSize.width = 0; + aState.lineMaxElementSize.height = 0; + } + + // Advance to the next line + aState.AdvanceToNextLine(lastFrame, lineHeight); + + return PR_TRUE; +} + +/** + * Add an inline child to the current line. Advance various running + * values after placement. + */ +void nsBlockFrame::AddInlineChildToLine(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsIFrame* aKidFrame, + nsReflowMetrics& aKidSize, + nsSize* aKidMaxElementSize, + nsStyleMolecule* aKidMol) +{ + NS_PRECONDITION(nsnull != aState.lineStart, "bad line"); + + PRIntn direction = aState.mol->direction; + if (NS_STYLE_POSITION_RELATIVE == aKidMol->positionFlags) { + aState.needRelativePos = PR_TRUE; + } + + // Place and size the child + // XXX add in left margin from kid + nsRect r; + r.y = aState.y; + r.width = aKidSize.width; + r.height = aKidSize.height; + if (NS_STYLE_DIRECTION_LTR == aState.mol->direction) { + // Left to right positioning. + r.x = aState.borderPadding.left + aState.x + aKidMol->margin.left; + aState.x += aKidSize.width + aKidMol->margin.left + aKidMol->margin.right; + } else { + // Right to left positioning + // XXX what should we do when aState.x goes negative??? + r.x = aState.x - aState.borderPadding.right - aKidMol->margin.right - aKidSize.width; + aState.x -= aKidSize.width + aKidMol->margin.right + aKidMol->margin.left; + } + aKidFrame->SetRect(r); + aState.AddAscent(aKidSize.ascent); + aState.lineWidth += aKidSize.width; + aState.lineLength++; + + // Update maximums for the line + if (aKidSize.ascent > aState.maxAscent) { + aState.maxAscent = aKidSize.ascent; + } + if (aKidSize.descent > aState.maxDescent) { + aState.maxDescent = aKidSize.descent; + } + // Update running margin maximums + if (aState.firstChildIsInsideBullet && (aKidFrame == mFirstChild)) { + // XXX temporary code. Since the molecule for the bullet frame + // is the same as the LI frame, we get bad style information. + // ignore it. + } else { + nscoord margin; +#if 0 + // XXX CSS2 spec says that top/bottom margin don't affect line height + // calculation. We're waiting for clarification on this issue... + if ((margin = aKidMol->margin.top) < 0) { + margin = -margin; + if (margin > aState.maxNegTopMargin) { + aState.maxNegTopMargin = margin; + } + } else { + if (margin > aState.maxPosTopMargin) { + aState.maxPosTopMargin = margin; + } + } +#endif + if ((margin = aKidMol->margin.bottom) < 0) { + margin = -margin; + if (margin > aState.maxNegBottomMargin) { + aState.maxNegBottomMargin = margin; + } + } else { + if (margin > aState.maxPosBottomMargin) { + aState.maxPosBottomMargin = margin; + } + } + } + + // Update line max element size + nsSize& mes = aState.lineMaxElementSize; + if (nsnull != aKidMaxElementSize) { + if (aKidMaxElementSize->width > mes.width) { + mes.width = aKidMaxElementSize->width; + } + if (aKidMaxElementSize->height > mes.height) { + mes.height = aKidMaxElementSize->height; + } + } +} + +// Places and sizes the block-level element, and advances the line. +// The rect is in the local coordinate space of the kid frame. +void nsBlockFrame::AddBlockChild(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsIFrame* aKidFrame, + nsRect& aKidRect, + nsSize* aKidMaxElementSize, + nsStyleMolecule* aKidMol) +{ + NS_PRECONDITION(nsnull != aState.lineStart, "bad line"); + + if (NS_STYLE_POSITION_RELATIVE == aKidMol->positionFlags) { + aState.needRelativePos = PR_TRUE; + } + + // Translate from the kid's coordinate space to our coordinate space + aKidRect.x += aState.borderPadding.left + aKidMol->margin.left; + aKidRect.y += aState.y + aState.topMargin; + + // Place and size the child + aKidFrame->SetRect(aKidRect); + + aState.AddAscent(aKidRect.height); + aState.lineLength++; + + // Is this the widest child frame? + nscoord xMost = aKidRect.XMost() + aKidMol->margin.right; + if (xMost > aState.kidXMost) { + aState.kidXMost = xMost; + } + + // Update the max element size + if (nsnull != aKidMaxElementSize) { + if (aKidMaxElementSize->width > aState.maxElementSize->width) { + aState.maxElementSize->width = aKidMaxElementSize->width; + } + if (aKidMaxElementSize->height > aState.maxElementSize->height) { + aState.maxElementSize->height = aKidMaxElementSize->height; + } + } + + // and the bottom line margin information which we'll use when placing + // the next child + if (aKidMol->margin.bottom < 0) { + aState.maxNegBottomMargin = -aKidMol->margin.bottom; + } else { + aState.maxPosBottomMargin = aKidMol->margin.bottom; + } + + // Update the running y-offset + aState.y += aKidRect.height + aState.topMargin; + + // Apply relative positioning if necessary + nsCSSLayout::RelativePositionChildren(aCX, this, aState.mol, aKidFrame, 1); + + // Advance to the next line + aState.AdvanceToNextLine(aKidFrame, aKidRect.height); +} + +/** + * Compute the available size for reflowing the given child at the + * current x,y position in the state. Note that this may return + * negative or zero width/height's if we are out of room. + */ +void nsBlockFrame::GetAvailSize(nsSize& aResult, + nsBlockReflowState& aState, + nsStyleMolecule* aKidMol, + PRBool aIsInline) +{ + // Determine the maximum available reflow height for the child + nscoord yb = aState.borderPadding.top + aState.availSize.height; + aResult.height = aState.unconstrainedHeight ? NS_UNCONSTRAINEDSIZE : + yb - aState.y - aState.topMargin; + + // Determine the maximum available reflow width for the child + if (aState.unconstrainedWidth) { + aResult.width = NS_UNCONSTRAINEDSIZE; + } else if (aIsInline) { + if (NS_STYLE_DIRECTION_LTR == aState.mol->direction) { + aResult.width = aState.currentBand->rects[0].XMost() - aState.x; + } else { + aResult.width = aState.x - aState.currentBand->rects[0].x; + } + } else { + // It's a block + aResult.width = aState.availSize.width - aKidMol->margin.left - + aKidMol->margin.right; + } +} + +/** + * Push all of the kids that we have not reflowed, starting at + * aState.lineStart. aPrevKid is the kid previous to aState.lineStart + * and is also our last child. Note that line length is NOT a + * reflection of the number of children we are actually pushing + * (because we don't break the sibling list as we add children to the + * line). + */ +void nsBlockFrame::PushKids(nsBlockReflowState& aState) +{ + nsIFrame* prevFrame = aState.prevLineLastFrame; + NS_PRECONDITION(nsnull != prevFrame, "pushing all kids"); + NS_PRECONDITION(prevFrame->GetNextSibling() == aState.lineStart, + "bad prev line"); + +#ifdef NS_DEBUG + PRInt32 numKids = LengthOf(mFirstChild); + NS_ASSERTION(numKids == mChildCount, "bad child count"); +#endif + +#ifdef NOISY + ListTag(stdout); + printf(": push kids (childCount=%d)\n", mChildCount); + DumpFlow(); +#endif + + PushChildren(aState.lineStart, prevFrame, mLastContentIsComplete); + SetLastContentOffset(prevFrame); + + // Set mLastContentIsComplete to the previous lines last content is + // complete now that the previous line's last child is our last + // child. + mLastContentIsComplete = aState.prevLineLastContentIsComplete; + + // Fix up child count + // XXX is there a better way? aState.lineLength doesn't work because + // we might be pushing more than just the pending line. + nsIFrame* kid = mFirstChild; + PRInt32 kids = 0; + while (nsnull != kid) { + kids++; + kid = kid->GetNextSibling(); + } + mChildCount = kids; + + // Make sure we have no lingering line data + aState.lineLength = 0; + aState.lineStart = nsnull; + +#ifdef NOISY + ListTag(stdout); + printf(": push kids done (childCount=%d) [%c]\n", mChildCount, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif +} + +/** + * Gets a band of available space starting at the specified y-offset. Assumes + * the local coordinate space is currently set to the upper-left origin of the + * bounding rect + * + * Updates "currentBand" and "x" member data of the block reflow state + */ +void nsBlockFrame::GetAvailableSpaceBand(nsBlockReflowState& aState, nscoord aY) +{ + // Gets a band of available space. + aState.spaceManager->Translate(aState.borderPadding.left, 0); + aState.spaceManager->GetBandData(aY, aState.availSize, *aState.currentBand); + + // XXX This is hack code that needs to change when the space manager interface + // changes to return both the available and unavailable space + // + // We'll get back anywhere between 1 and 3 rects depending on how many floaters + // there are. Actually the way it currently works we could get back zero rects + // if there are overlapping left and right floaters occupying all the space + if (aState.currentBand->count > 1) { + // If there are three rects then let's assume that there are floaters on the + // left and right and that only the middle rect is available + if (aState.currentBand->count == 3) { + aState.currentBand->rects[0] = aState.currentBand->rects[1]; + } else { + // There are two rects. That means either a left or right floater. Just use + // whichever space is larger. + if (aState.currentBand->rects[1].width > aState.currentBand->rects[0].width) { + aState.currentBand->rects[0] = aState.currentBand->rects[1]; + } + } + } + aState.spaceManager->Translate(-aState.borderPadding.left, 0); + aState.x = aState.currentBand->rects[0].x; +} + +void nsBlockFrame::ClearFloaters(nsBlockReflowState& aState, PRUint32 aClear) +{ + // Translate the coordinate space + aState.spaceManager->Translate(aState.borderPadding.left, 0); + +getBand: + nscoord y = aState.y + aState.topMargin; + PRBool isLeftFloater = PR_FALSE; + PRBool isRightFloater = PR_FALSE; + + // Get a band of available space + aState.spaceManager->GetBandData(y, aState.availSize, *aState.currentBand); + + if (aState.currentBand->count == 1) { + if (aState.currentBand->rects[0].width != aState.availSize.width) { + // Some of the space is taken up by floaters + if (aState.currentBand->rects[0].x > 0) { + isLeftFloater = PR_TRUE; + } + + if (aState.currentBand->rects[0].XMost() < aState.availSize.width) { + isRightFloater = PR_TRUE; + } + } + } else if (aState.currentBand->count == 2) { + if (aState.currentBand->rects[0].width > aState.currentBand->rects[1].width) { + isRightFloater = PR_TRUE; + } else { + isLeftFloater = PR_TRUE; + + // There may also be a right floater + if (aState.currentBand->rects[1].XMost() < aState.availSize.width) { + isRightFloater = PR_TRUE; + } + } + } else { + // Must be both left and right floaters + isLeftFloater = PR_TRUE; + isRightFloater = PR_TRUE; + } + + if (isLeftFloater) { + if ((aClear == NS_STYLE_CLEAR_LEFT) || (aClear == NS_STYLE_CLEAR_BOTH)) { + aState.y += aState.currentBand->rects[0].height; + goto getBand; + } + } + if (isRightFloater) { + if ((aClear == NS_STYLE_CLEAR_RIGHT) || (aClear == NS_STYLE_CLEAR_BOTH)) { + aState.y += aState.currentBand->rects[0].height; + goto getBand; + } + } + + aState.spaceManager->Translate(-aState.borderPadding.left, 0); +} + +// Bit's for PlaceAndReflowChild return value +#define PLACE_FIT 0x1 +#define PLACE_FLOWED 0x2 + +PRIntn +nsBlockFrame::PlaceAndReflowChild(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsIFrame* kidFrame, + nsStyleMolecule* aKidMol) +{ + nsSize kidMaxElementSize; + nsSize* pKidMaxElementSize = + (nsnull != aState.maxElementSize) ? &kidMaxElementSize : nsnull; + + // Get line start setup if we are at the start of a new line + if (nsnull == aState.lineStart) { + NS_ASSERTION(0 == aState.lineLength, "bad line length"); + aState.lineStart = kidFrame; + } + + // Get kid and its style + // XXX How is this any different than what was passed in to us as aKidMol? + nsIContent* kid = kidFrame->GetContent(); + nsIStyleContext* kidSC = kidFrame->GetStyleContext(aCX); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + NS_RELEASE(kid); + + // Figure out if kid is a block element or not + PRBool isInline = PR_TRUE; + PRIntn display = kidMol->display; + if (aState.firstChildIsInsideBullet && (mFirstChild == kidFrame)) { + // XXX Special hack for properly reflowing bullets that have the + // inside value for list-style-position. + display = NS_STYLE_DISPLAY_INLINE; + } + if ((NS_STYLE_DISPLAY_BLOCK == display) || + (NS_STYLE_DISPLAY_LIST_ITEM == display)) { + // Block elements always end up on the next line (unless they are + // already at the start of the line). + isInline = PR_FALSE; + if (aState.lineLength > 0) { + aState.breakAfterChild = PR_TRUE; + } + } + + // Handle forced break first + if (aState.breakAfterChild) { + NS_ASSERTION(aState.lineStart != kidFrame, "bad line"); + + // Get the last child in the current line + nsIFrame* lastFrame = aState.lineStart; + PRInt32 lineLen = aState.lineLength - 1; + while (--lineLen >= 0) { + lastFrame = lastFrame->GetNextSibling(); + } + + if (!AdvanceToNextLine(aCX, aState)) { + // The previous line didn't fit. + return 0; + } + aState.lineStart = kidFrame; + + // Get the style for the last child, and see if it wanted to clear floaters. + // This handles the BR tag, which is the only inline element for which clear + // applies + nsIStyleContext* lastChildSC = lastFrame->GetStyleContext(aCX); + nsStyleMolecule* lastChildMol = (nsStyleMolecule*)lastChildSC->GetData(kStyleMoleculeSID); + if (lastChildMol->clear != NS_STYLE_CLEAR_NONE) { + ClearFloaters(aState, lastChildMol->clear); + } + NS_RELEASE(lastChildSC); + } + + // Now that we've handled force breaks (and maybe called AdvanceToNextLine() + // which checks), remember whether it's an inline frame + aState.isInline = isInline; + + // If we're at the beginning of a line then compute the top margin that we + // should use + if (aState.lineStart == kidFrame) { + // Compute the top margin to use for this line + aState.topMargin = GetTopMarginFor(aCX, aState, kidMol, aState.isInline); + + // If it's an inline element then get a band of available space + // + // XXX If we have a current band and there's unused space in that band + // then avoid this call to get a band... + if (aState.isInline) { + GetAvailableSpaceBand(aState, aState.y + aState.topMargin); + } + } + + // Compute the available space to reflow the child into and then + // reflow it into that space. + nsSize kidAvailSize; + GetAvailSize(kidAvailSize, aState, kidMol, aState.isInline); + if ((aState.currentLineNumber > 0) && (kidAvailSize.height <= 0)) { + // No more room + return 0; + } + + ReflowStatus status; + + if (aState.isInline) { + nsReflowMetrics kidSize; + + // Inline elements are never passed the space manager + status = ReflowChild(kidFrame, aCX, kidSize, kidAvailSize, + pKidMaxElementSize); + + // For first children, we skip all the fit checks because we must + // fit at least one child for a parent to figure what to do with us. + if ((aState.currentLineNumber > 0) || (aState.lineLength > 0)) { + NS_ASSERTION(nsnull != aState.lineStart, "bad line start"); + + if (kidFrame == aState.lineStart) { + // Width always fits when we are at the logical left margin. + // Just check the height. + // + // XXX This height check isn't correct now that we have bands of + // available space... + if (kidSize.height > kidAvailSize.height) { + // It's too tall + return PLACE_FLOWED; + } + } else { + // Examine state and if the breakBeforeChild is set and we + // aren't already on the new line, do the forcing now. + // XXX Why aren't we doing this check BEFORE we resize reflow the child? + if (aState.breakBeforeChild) { + aState.breakBeforeChild = PR_FALSE; + if (kidFrame != aState.lineStart) { + if (!AdvanceToNextLine(aCX, aState)) { + // Flushing out the line failed. + return PLACE_FLOWED; + } + aState.lineStart = kidFrame; + + // Get a band of available space + GetAvailableSpaceBand(aState, aState.y + aState.topMargin); + + // Reflow child now that it has the line to itself + GetAvailSize(kidAvailSize, aState, kidMol, PR_TRUE); + status = ReflowChild(kidFrame, aCX, kidSize, kidAvailSize, + pKidMaxElementSize); + } + } + + // When we are not at the logical left margin then we need + // to check the width first. If we are too wide then advance + // to the next line and try reflowing again. + if (kidSize.width > kidAvailSize.width) { + // Too wide. Try next line + if (!AdvanceToNextLine(aCX, aState)) { + // Flushing out the line failed. + return PLACE_FLOWED; + } + aState.lineStart = kidFrame; + + // Get a band of available space + GetAvailableSpaceBand(aState, aState.y + aState.topMargin); + + // Reflow splittable children + if (kidFrame->IsSplittable()) { + // Update size info now that we are on the next line. Then + // reflow the child into the new available space. + GetAvailSize(kidAvailSize, aState, kidMol, PR_TRUE); + status = ReflowChild(kidFrame, aCX, kidSize, kidAvailSize, + pKidMaxElementSize); + + // If we just reflowed our last child then update the + // mLastContentIsComplete state. + if (nsnull == kidFrame->GetNextSibling()) { + // Use state from the reflow we just did + mLastContentIsComplete = PRBool(status == frComplete); + } + } + + // XXX This height check isn't correct now that we have bands of + // available space... + if (kidSize.height > kidAvailSize.height) { + // It's too tall on the next line + return PLACE_FLOWED; + } + // It's ok if it's too wide on the next line. + } + } + } + + // Add child to the line + AddInlineChildToLine(aCX, aState, kidFrame, kidSize, pKidMaxElementSize, kidMol); + + } else { + nsRect kidRect; + + // Does the block-level element want to clear any floaters that impact + // it? Note that the clear property only applies to block-level elements + // and the BR tag + if (aKidMol->clear != NS_STYLE_CLEAR_NONE) { + ClearFloaters(aState, aKidMol->clear); + GetAvailSize(kidAvailSize, aState, kidMol, PR_FALSE); + if ((aState.currentLineNumber > 0) && (kidAvailSize.height <= 0)) { + // No more room + return 0; + } + } + + // Give the block its own local coordinate space. + // + // XXX This is wrong to have the parent try and account for the kid's + // left margin here, because we have to wait until we know what the + // left edge is and that means resolving any floaters that impact the + // block. If the kid wants to interact with the space manager then it + // will have to deal with left/right margins itself + nscoord tx = aState.borderPadding.left + aKidMol->margin.left; + nscoord ty = aState.y + aState.topMargin; + + // Give the block-level element the opportunity to use the space manager + aState.spaceManager->Translate(tx, ty); + status = ReflowChild(kidFrame, aCX, aState.spaceManager, kidAvailSize, + kidRect, pKidMaxElementSize); + aState.spaceManager->Translate(-tx, -ty); + + // For first children, we skip all the fit checks because we must + // fit at least one child for a parent to figure what to do with us. + if ((aState.currentLineNumber > 0) || (aState.lineLength > 0)) { + // Block elements always fit horizontally (because they are + // always placed at the logical left margin). Check to see if + // the block fits vertically + if (kidRect.YMost() > kidAvailSize.height) { + // Nope + return PLACE_FLOWED; + } + } + + // Add block child + AddBlockChild(aCX, aState, kidFrame, kidRect, pKidMaxElementSize, kidMol); + } + + // If we just reflowed our last child then update the + // mLastContentIsComplete state. + if (nsnull == kidFrame->GetNextSibling()) { + // Use state from the reflow we just did + mLastContentIsComplete = PRBool(status == frComplete); + } + + aState.lastContentIsComplete = PRBool(status == frComplete); + if (aState.isInline && (frNotComplete == status)) { + // Since the inline child didn't complete its reflow we *know* + // that a continuation of it can't possibly fit on the current + // line. Therefore, set a flag in the state that will cause the + // a line break before the next frame is placed. + aState.breakAfterChild = PR_TRUE; + } + NS_RELEASE(kidSC); + + aState.reflowStatus = status; + return PLACE_FLOWED | PLACE_FIT; +} + +/** + * Reflow the existing frames. + * + * @param aCX presentation context to use + * @param aState in out parameter which tracks the state of + * reflow for the block frame. + * @return true if we successfully reflowed all the mapped children and false + * otherwise, e.g. we pushed children to the next in flow + */ +PRBool +nsBlockFrame::ReflowMappedChildren(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": reflow mapped (childCount=%d) [%d,%d,%c]\n", + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif + + PRBool result = PR_TRUE; + nsIFrame* kidFrame; + nsIFrame* prevKidFrame = nsnull; + + for (kidFrame = mFirstChild; nsnull != kidFrame; ) { + nsIContent* kid = kidFrame->GetContent(); + nsIStyleContext* kidSC = aCX->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + NS_RELEASE(kid); + + // Attempt to place and reflow the child + + // XXX if child is not splittable and it fits just place it where + // it is, otherwise advance to the next line and place it there if + // possible + + PRIntn placeStatus = PlaceAndReflowChild(aCX, aState, kidFrame, kidMol); + ReflowStatus status = aState.reflowStatus; + NS_RELEASE(kidSC); + if (0 == (placeStatus & PLACE_FIT)) { + // The child doesn't fit. Push it and any remaining children. + PushKids(aState); + result = PR_FALSE; + goto push_done; + } + + // Is the child complete? + if (frComplete == status) { + // Yes, the child is complete + NS_ASSERTION(nsnull == kidFrame->GetNextInFlow(), "bad child flow list"); + } else { + // No the child isn't complete + nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); + if (nsnull == kidNextInFlow) { + // The child doesn't have a next-in-flow so create a continuing + // frame. This hooks the child into the flow + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aCX, this); + NS_ASSERTION(nsnull != continuingFrame, "frame creation failed"); + + // Add the continuing frame to the sibling list + nsIFrame* nextSib = kidFrame->GetNextSibling(); + continuingFrame->SetNextSibling(nextSib); + kidFrame->SetNextSibling(continuingFrame); + mChildCount++; + } + + // Unlike the inline frame code we can't assume that we used + // up all of our space because the child's reflow status is + // frNotComplete. Instead, the child is probably split and + // we need to reflow the continuations as well. + } + + // Get the next child frame + prevKidFrame = kidFrame; + kidFrame = kidFrame->GetNextSibling(); + } + + push_done:; + // Update the child count member data + NS_POSTCONDITION(LastChild()->GetIndexInParent() == mLastContentOffset, "bad last content offset"); + +#ifdef NS_DEBUG + PRInt32 len = LengthOf(mFirstChild); + NS_POSTCONDITION(len == mChildCount, "bad child count"); + VerifyLastIsComplete(); +#endif + +#ifdef NOISY + ListTag(stdout); + printf(": reflow mapped %sok (childCount=%d) [%d,%d,%c]\n", + (result ? "" : "NOT "), + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif + return result; +} + +PRBool nsBlockFrame::MoreToReflow(nsIPresContext* aCX) +{ + PRBool rv = PR_FALSE; + if (IsPseudoFrame()) { + // Get the next content object that we would like to reflow + PRInt32 kidIndex = NextChildOffset(); + nsIContent* kid = mContent->ChildAt(kidIndex); + if (nsnull != kid) { + // Resolve style for the kid + nsIStyleContext* kidSC = aCX->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + switch (kidMol->display) { + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + // Block pseudo-frames do not contain other block elements + break; + + default: + rv = PR_TRUE; + break; + } + NS_RELEASE(kidSC); + NS_RELEASE(kid); + } + } else { + if (NextChildOffset() < mContent->ChildCount()) { + rv = PR_TRUE; + } + } + return rv; +} + +/** + * Create new frames for content we haven't yet mapped + * + * @param aCX presentation context to use + * @return frComplete if all content has been mapped and frNotComplete + * if we should be continued + */ +nsIFrame::ReflowStatus +nsBlockFrame::ReflowAppendedChildren(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif + nsIFrame* kidPrevInFlow = nsnull; + ReflowStatus result = frNotComplete; + + // If we have no children and we have a prev-in-flow then we need to pick + // up where it left off. If we have children, e.g. we're being resized, then + // our content offset should already be set correctly... + if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) { + nsBlockFrame* prev = (nsBlockFrame*) mPrevInFlow; + NS_ASSERTION(prev->mLastContentOffset >= prev->mFirstContentOffset, "bad prevInFlow"); + mFirstContentOffset = prev->NextChildOffset(); + if (PR_FALSE == prev->mLastContentIsComplete) { + // Our prev-in-flow's last child is not complete + kidPrevInFlow = prev->LastChild(); + } + } + + // Place our children, one at a time until we are out of children + PRInt32 kidIndex = NextChildOffset(); + nsIFrame* prevKidFrame = LastChild(); + nsIFrame* kidFrame = nsnull; + for (;;) { + // Get the next content object + nsIContent* kid = mContent->ChildAt(kidIndex); + if (nsnull == kid) { + result = frComplete; + break; + } + + // Resolve style for the kid + nsIStyleContext* kidSC = aCX->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + + // Is it a floater? + if (kidMol->floats != NS_STYLE_FLOAT_NONE) { + PlaceholderFrame::NewFrame(&kidFrame, kid, kidIndex, this); + kidFrame->SetStyleContext(kidSC); + } else if (nsnull == kidPrevInFlow) { + // Create initial frame for the child + nsIContentDelegate* kidDel; + nsresult fr; + switch (kidMol->display) { + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + // Pseudo block frames do not contain other block elements + // unless the block element would be the first child. + if (IsPseudoFrame()) { + // If we're being used as a pseudo frame, i.e. we map the same + // content as our parent then we want to indicate we're complete; + // otherwise we'll be continued and go on mapping children... + + // It better be true that we are not being asked to flow a + // block element as our first child. That means the body + // decided it needed a pseudo-frame when it shouldn't have. + NS_ASSERTION(nsnull != mFirstChild, "bad body"); + + NS_RELEASE(kidSC); + NS_RELEASE(kid); + result = frComplete; + goto done; + } + // FALL THROUGH (and create frame) + + case NS_STYLE_DISPLAY_INLINE: + kidDel = kid->GetDelegate(aCX); + kidFrame = kidDel->CreateFrame(aCX, kid, kidIndex, this); + NS_RELEASE(kidDel); + break; + + default: + NS_ASSERTION(nsnull == kidPrevInFlow, "bad prev in flow"); + fr = nsFrame::NewFrame(&kidFrame, kid, kidIndex, this); + break; + } + kidFrame->SetStyleContext(kidSC); + } else { + // Since kid has a prev-in-flow, use that to create the next + // frame. + kidFrame = kidPrevInFlow->CreateContinuingFrame(aCX, this); + } + + // Link child frame into the list of children. If the frame ends + // up not fitting and getting pushed, the PushKids code will fixup + // the child count for us. + if (nsnull != prevKidFrame) { + NS_ASSERTION(nsnull == prevKidFrame->GetNextSibling(), "bad append"); + prevKidFrame->SetNextSibling(kidFrame); + } else { + NS_ASSERTION(nsnull == mFirstChild, "bad create"); + mFirstChild = kidFrame; + SetFirstContentOffset(kidFrame); + } + prevKidFrame = kidFrame; + mChildCount++; + + // Reflow child frame as many times as necessary until it is + // complete. + ReflowStatus status; + do { + PRIntn placeStatus = PlaceAndReflowChild(aCX, aState, kidFrame, kidMol); + status = aState.reflowStatus; + if (0 == (placeStatus & PLACE_FIT)) { + // We ran out of room. + mLastContentIsComplete = PRBool(nsnull == kidFrame->GetNextInFlow()); + PushKids(aState); + + NS_RELEASE(kid); + NS_RELEASE(kidSC); + goto push_done; + } + + // Did the child complete? + prevKidFrame = kidFrame; + if (frNotComplete == status) { + // Child didn't complete so create a continuing frame + kidPrevInFlow = kidFrame; + nsIFrame* continuingFrame = kidFrame->CreateContinuingFrame(aCX, this); + + // Add the continuing frame to the sibling list + continuingFrame->SetNextSibling(kidFrame->GetNextSibling()); + kidFrame->SetNextSibling(continuingFrame); + kidFrame = continuingFrame; + mChildCount++; + + // Switch to new kid style + NS_RELEASE(kidSC); + kidSC = kidFrame->GetStyleContext(aCX); + kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + } + NS_ASSERTION(nsnull == kidFrame->GetNextInFlow(), "huh?"); + } while (frNotComplete == status); + NS_RELEASE(kid); + NS_RELEASE(kidSC); + + // The child that we just reflowed is complete + NS_ASSERTION(nsnull == kidFrame->GetNextInFlow(), "bad child flow list"); + kidIndex++; + kidPrevInFlow = nsnull; + } + + done: + // To get here we either completely reflowed all our appended + // children OR we are a pseudo-frame and we ran into a block + // element. In either case our last content MUST be complete. + NS_ASSERTION(PR_TRUE == aState.lastContentIsComplete, "bad state"); + + NS_ASSERTION(LastChild() == prevKidFrame, "bad last child"); + SetLastContentOffset(prevKidFrame); + + push_done: +#ifdef NS_DEBUG + PRInt32 len = LengthOf(mFirstChild); + NS_ASSERTION(len == mChildCount, "bad child count"); + VerifyLastIsComplete(); +#endif + return result; +} + +/** + * Pullup frames from our next in flow and try to place them. Before + * this is called our previously mapped children, if any have been + * reflowed which means that the block reflow state's x and y + * coordinates and other data are ready to go. + * + * Return true if we pulled everything up. + */ +PRBool +nsBlockFrame::PullUpChildren(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": pullup (childCount=%d) [%d,%d,%c]\n", + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif + + PRBool result = PR_TRUE; + nsBlockFrame* nextInFlow = (nsBlockFrame*) mNextInFlow; + nsIFrame* prevKidFrame = LastChild(); + while (nsnull != nextInFlow) { + // Get first available frame from the next-in-flow + nsIFrame* kidFrame = PullUpOneChild(nextInFlow, prevKidFrame); + if (nsnull == kidFrame) { + // We've pulled up all the children from that next-in-flow, so + // move to the next next-in-flow. + nextInFlow = (nsBlockFrame*) nextInFlow->mNextInFlow; + continue; + } + + // Get style information for the pulled up kid + nsIContent* kid = kidFrame->GetContent(); + nsIStyleContext* kidSC = aCX->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + + ReflowStatus status; + do { + PRIntn placeStatus = PlaceAndReflowChild(aCX, aState, kidFrame, kidMol); + status = aState.reflowStatus; + if (0 == (placeStatus & PLACE_FIT)) { + // Push the kids that didn't fit back down to the next-in-flow + mLastContentIsComplete = PRBool(nsnull == kidFrame->GetNextInFlow()); + PushKids(aState); + + result = PR_FALSE; + NS_RELEASE(kid); + NS_RELEASE(kidSC); + goto push_done; + } + + if (frNotComplete == status) { + // Child is not complete + nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); + if (nsnull == kidNextInFlow) { + // Create a continuing frame for the incomplete child + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aCX, this); + + // Add the continuing frame to our sibling list. + continuingFrame->SetNextSibling(kidFrame->GetNextSibling()); + kidFrame->SetNextSibling(continuingFrame); + prevKidFrame = kidFrame; + kidFrame = continuingFrame; + mChildCount++; + + // Switch to new kid style + NS_RELEASE(kidSC); + kidSC = kidFrame->GetStyleContext(aCX); + kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + } else { + // The child has a next-in-flow, but it's not one of ours. + // It *must* be in one of our next-in-flows. Collect it + // then. + NS_ASSERTION(kidNextInFlow->GetGeometricParent() != this, + "busted kid next-in-flow"); + break; + } + } + } while (frNotComplete == status); + NS_RELEASE(kid); + NS_RELEASE(kidSC); + + prevKidFrame = kidFrame; + } + + if (nsnull != prevKidFrame) { + // The only way we can get here is by pulling up every last child + // in our next-in-flows (and reflowing any continunations they + // have). Therefore we KNOW that our last child is complete. + NS_ASSERTION(PR_TRUE == aState.lastContentIsComplete, "bad state"); + NS_ASSERTION(LastChild() == prevKidFrame, "bad last child"); + SetLastContentOffset(prevKidFrame); + } + + push_done:; + + if (result == PR_FALSE) { + // If our next-in-flow is empty OR our next next-in-flow is empty + // then adjust the offsets of all of the empty next-in-flows. + nextInFlow = (nsBlockFrame*) mNextInFlow; + if ((0 == nextInFlow->mChildCount) || + ((nsnull != nextInFlow->mNextInFlow) && + (0 == ((nsBlockFrame*)(nextInFlow->mNextInFlow))->mChildCount))) { + // We didn't pullup everything and we need to fixup one of our + // next-in-flows content offsets. + AdjustOffsetOfEmptyNextInFlows(); + } + } + + +#ifdef NS_DEBUG + PRInt32 len = LengthOf(mFirstChild); + NS_ASSERTION(len == mChildCount, "bad child count"); + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": pullup %sok (childCount=%d) [%d,%d,%c]\n", + (result ? "" : "NOT "), + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif + return result; +} + +void nsBlockFrame::SetupState(nsIPresContext* aCX, + nsBlockReflowState& aState, + const nsSize& aMaxSize, + nsSize* aMaxElementSize, + nsISpaceManager* aSpaceManager) +{ + // Setup reflow state + nsStyleMolecule* mol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + nsStyleFont* font = + (nsStyleFont*)mStyleContext->GetData(kStyleFontSID); + aState.Init(aMaxSize, aMaxElementSize, font, mol, aSpaceManager); + + // Apply border and padding adjustments for regular frames only + if (PR_FALSE == IsPseudoFrame()) { + aState.borderPadding = mol->borderPadding; + aState.y = mol->borderPadding.top; + aState.availSize.width -= + (mol->borderPadding.left + mol->borderPadding.right); + aState.availSize.height -= + (mol->borderPadding.top + mol->borderPadding.bottom); + } else { + aState.borderPadding.SizeTo(0, 0, 0, 0); + } + + // Setup initial list ordinal value + nsIAtom* tag = mContent->GetTag(); + if ((tag == nsHTMLAtoms::ul) || (tag == nsHTMLAtoms::ol) || + (tag == nsHTMLAtoms::menu) || (tag == nsHTMLAtoms::dir)) { + nsHTMLValue value; + if (eContentAttr_HasValue == + ((nsIHTMLContent*)mContent)->GetAttribute(nsHTMLAtoms::start, value)) { + if (eHTMLUnit_Absolute == value.GetUnit()) { + aState.nextListOrdinal = value.GetIntValue(); + } + } + } + NS_RELEASE(tag); + + mCurrentState = &aState; +} + +#include "nsUnitConversion.h"/* XXX */ +nsIFrame::ReflowStatus +nsBlockFrame::ResizeReflow(nsIPresContext* aCX, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsSize* aMaxElementSize) +{ + nsBlockReflowState state; + SetupState(aCX, state, aMaxSize, aMaxElementSize, aSpaceManager); + return DoResizeReflow(aCX, state, aDesiredRect); +} + +nsIFrame::ReflowStatus +nsBlockFrame::DoResizeReflow(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsRect& aDesiredRect) +{ +#ifdef NS_DEBUG + PreReflowCheck(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": resize reflow %g,%g\n", + NS_TWIPS_TO_POINTS_FLOAT(aState.availSize.width), + NS_TWIPS_TO_POINTS_FLOAT(aState.availSize.height)); + DumpFlow(); +#endif + + // Zap old line data + if (nsnull != mLines) { + delete mLines; + mLines = nsnull; + } + mNumLines = 0; + + // Check for an overflow list + MoveOverflowToChildList(); + + // Before we start reflowing, cache a pointer to our state structure + // so that inline frames can find it. + nsIPresShell* shell = aCX->GetShell(); + shell->PutCachedData(this, &aState); + + // First reflow any existing frames + PRBool reflowMappedOK = PR_TRUE; + ReflowStatus status = frComplete; + if (nsnull != mFirstChild) { + reflowMappedOK = ReflowMappedChildren(aCX, aState); + if (!reflowMappedOK) { + status = frNotComplete; + } + } + + if (reflowMappedOK) { + // Any space left? + nscoord yb = aState.borderPadding.top + aState.availSize.height; + if ((nsnull != mFirstChild) && (aState.y >= yb)) { + // No space left. Don't try to pull-up children or reflow + // unmapped. We need to return the correct completion status, + // so see if there is more to reflow. + if (MoreToReflow(aCX)) { + status = frNotComplete; + } + } else if (MoreToReflow(aCX)) { + // Try and pull-up some children from a next-in-flow + if ((nsnull == mNextInFlow) || PullUpChildren(aCX, aState)) { + // If we still have unmapped children then create some new frames + if (MoreToReflow(aCX)) { + status = ReflowAppendedChildren(aCX, aState); + } + } else { + // We were unable to pull-up all the existing frames from the + // next in flow + status = frNotComplete; + } + } + } + + // Deal with last line - make sure it gets vertically and + // horizontally aligned. This also updates the state's y coordinate + // which is good because that's how we size ourselves. + if (0 != aState.lineLength) { + if (!AdvanceToNextLine(aCX, aState)) { + // The last line of output doesn't fit. Push all of the kids to + // the next in flow and change our reflow status to not complete + // so that we are continued. +#ifdef NOISY + ListTag(stdout); + printf(": pushing kids since last line doesn't fit\n"); +#endif + + PushKids(aState); + status = frNotComplete; + } + } + + if (frComplete == status) { + // Don't forget to add in the bottom margin from our last child. + // Only add it in if there is room for it. + nscoord margin = aState.prevMaxPosBottomMargin - + aState.prevMaxNegBottomMargin; + nscoord y = aState.y + margin; + if (y <= aState.borderPadding.top + aState.availSize.height) { + aState.y = y; + } + } + + // Now that reflow has finished, remove the cached pointer + shell->RemoveCachedData(this); + NS_RELEASE(shell); + + // Translate state.lineLengths into an integer array + mNumLines = aState.lineLengths.Count(); + if (mNumLines > 0) { + mLines = new PRInt32[mNumLines]; + for (PRInt32 i = 0; i < mNumLines; i++) { + PRInt32 ll = (PRInt32) aState.lineLengths.ElementAt(i); + mLines[i] = ll; + } + } + + if (!aState.unconstrainedWidth && aState.justifying) { + // Perform justification now that we know how many lines we have. + JustifyLines(aCX, aState); + } + + // Return our desired rect and our status + aDesiredRect.x = 0; + aDesiredRect.y = 0; + aDesiredRect.width = aState.kidXMost + aState.borderPadding.right; + if (!aState.unconstrainedWidth) { + // Make sure we're at least as wide as the max size we were given + nscoord maxWidth = aState.availSize.width + aState.borderPadding.left + + aState.borderPadding.right; + + if (aDesiredRect.width < maxWidth) { + aDesiredRect.width = maxWidth; + } + } + aState.y += aState.borderPadding.bottom; + aDesiredRect.height = aState.y; + +#ifdef NS_DEBUG + PostReflowCheck(status); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": resize reflow %g,%g %scomplete [%d,%d,%c]\n", + NS_TWIPS_TO_POINTS_FLOAT(aState.availSize.width), + NS_TWIPS_TO_POINTS_FLOAT(aState.availSize.height), + ((status == frNotComplete) ? "NOT " : ""), + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F') + ); + DumpFlow(); +#endif + mCurrentState = nsnull; + return status; +} + +void nsBlockFrame::JustifyLines(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ + // XXX we don't justify the last line; what if we are continued, + // should we do it then? + nsIFrame* kid = mFirstChild; + for (PRInt32 i = 0; i < mNumLines; i++) { + nsIFrame* lineStart = kid; + PRInt32 lineLength = mLines[i]; + if (i < mNumLines - 1) { + if (1 == lineLength) { + // For lines with one element on them we can take a shortcut and + // let them do the justification. Note that we still call + // JustifyReflow even if the available space is zero in case the + // child is a hunk of text that ends in whitespace. The whitespace + // will be distributed elsewhere causing a proper flush right look + // for the last word. + nsRect r; + kid->GetRect(r); + nscoord maxWidth = aState.availSize.width; + nscoord availableSpace = maxWidth - r.width; + nscoord maxAvailSpace = nscoord(maxWidth * 0.1f); + if ((availableSpace >= 0) && (availableSpace < maxAvailSpace)) { + kid->JustifyReflow(aCX, availableSpace); + kid->SizeTo(r.width + availableSpace, r.height); + } + kid = kid->GetNextSibling(); + } else { + // XXX Get justification of multiple elements working + while (--lineLength >= 0) { + kid = kid->GetNextSibling(); + } + } + } + + // Finally, now that the in-flow positions of the line's frames are + // known we can apply relative positioning if any of them need it. + nsCSSLayout::RelativePositionChildren(aCX, this, aState.mol, + lineStart, mLines[i]); + } +} + +nsIFrame* nsBlockFrame::CreateContinuingFrame(nsIPresContext* aCX, + nsIFrame* aParent) +{ + nsBlockFrame* cf = new nsBlockFrame(mContent, mIndexInParent, aParent); + PrepareContinuingFrame(aCX, aParent, cf); + return cf; +} + +nsIFrame::ReflowStatus +nsBlockFrame::IncrementalReflow(nsIPresContext* aCX, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsReflowCommand& aReflowCommand) +{ + ReflowStatus status = frComplete; + + if (aReflowCommand.GetTarget() == this) { + // XXX for now, just do a complete reflow mapped (it'll kinda + // work, but it's slow) + + nsBlockReflowState state; + SetupState(aCX, state, aMaxSize, nsnull, aSpaceManager); + PRBool reflowMappedOK = ReflowMappedChildren(aCX, state); + if (!reflowMappedOK) { + status = frNotComplete; + } + } else { + // XXX not yet implemented + NS_ABORT(); + // XXX work to compute initial state goes *HERE* + aDesiredRect.x = 0; + aDesiredRect.y = 0; + aDesiredRect.width = 0; + aDesiredRect.height = 0; + } + + mCurrentState = nsnull; + return status; +} + +PRBool nsBlockFrame::IsLeftMostChild(nsIFrame* aFrame) +{ + do { + nsIFrame* parent = aFrame->GetGeometricParent(); + + // See if there are any non-zero sized child frames that precede aFrame + // in the child list + nsIFrame* child = parent->FirstChild(); + + while ((nsnull != child) && (aFrame != child)) { + // Is the child zero-sized? + if ((child->GetWidth() > 0) || (child->GetHeight() > 0)) { + // We found a non-zero sized child frame that precedes aFrame + return PR_FALSE; + } + + child = child->GetNextSibling(); + } + + // aFrame is the left-most non-zero sized frame in its geometric parent. + // Walk up one level and check that its parent is left-most as well + aFrame = parent; + } while (aFrame != this); + + return PR_TRUE; +} + +PRBool nsBlockFrame::AddFloater(nsIPresContext* aCX, + nsIFrame* aFloater, + PlaceholderFrame* aPlaceholder) +{ + // Get the frame associated with the space manager, and get its nsIAnchoredItems + // interface + nsIFrame* frame = mCurrentState->spaceManager->GetFrame(); + nsIAnchoredItems* anchoredItems = nsnull; + + frame->QueryInterface(kIAnchoredItemsIID, (void**)&anchoredItems); + NS_ASSERTION(nsnull != anchoredItems, "no anchored items interface"); + + if (nsnull != anchoredItems) { + anchoredItems->AddAnchoredItem(aFloater, nsIAnchoredItems::anHTMLFloater, this); + PlaceFloater(aCX, aFloater, aPlaceholder); + return PR_TRUE; + } + + return PR_FALSE; +} + +// XXX The size of the floater needs to be taken into consideration if we're +// computing a maximum element size +void nsBlockFrame::PlaceFloater(nsIPresContext* aCX, + nsIFrame* aFloater, + PlaceholderFrame* aPlaceholder) +{ + // If the floater is the left-most non-zero size child frame then insert + // it before the current line; otherwise add it to the below-current-line + // todo list and we'll handle it when we flush out the line + if (IsLeftMostChild(aPlaceholder)) { + // Get the type of floater + nsIStyleContext* styleContext = aFloater->GetStyleContext(aCX); + nsStyleMolecule* mol = (nsStyleMolecule*)styleContext->GetData(kStyleMoleculeSID); + NS_RELEASE(styleContext); + + if (!mCurrentState->isInline) { + // Get the current band for this line + GetAvailableSpaceBand(*mCurrentState, mCurrentState->y + mCurrentState->topMargin); + } + + // Commit some space in the space manager + nsRect region; + + aFloater->GetRect(region); + region.y = mCurrentState->currentBand->rects[0].y; + + if (NS_STYLE_FLOAT_LEFT == mol->floats) { + region.x = mCurrentState->currentBand->rects[0].x; + } else { + NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == mol->floats, "bad float type"); + region.x = mCurrentState->currentBand->rects[0].XMost() - region.width; + } + + // XXX Don't forget the floater's margins... + mCurrentState->spaceManager->Translate(mCurrentState->borderPadding.left, 0); + mCurrentState->spaceManager->AddRectRegion(region); + + // Set the origin of the floater in world coordinates + nscoord worldX, worldY; + + mCurrentState->spaceManager->GetTranslation(worldX, worldY); + aFloater->MoveTo(region.x + worldX, region.y + worldY); + mCurrentState->spaceManager->Translate(-mCurrentState->borderPadding.left, 0); + + // Update the band of available space to reflect space taken up by the floater + GetAvailableSpaceBand(*mCurrentState, mCurrentState->y + mCurrentState->topMargin); + } else { + // Add the floater to our to-do list + mCurrentState->floaterToDo.AppendElement(aFloater); + } +} + +void nsBlockFrame::ContentAppended(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer) +{ + // Zip down to the end-of-flow + nsBlockFrame* flow = this; + for (;;) { + nsBlockFrame* next = (nsBlockFrame*) flow->GetNextInFlow(); + if (nsnull == next) { + break; + } + flow = next; + } + + PRInt32 kidIndex = flow->NextChildOffset(); + PRInt32 startIndex = kidIndex; + nsIFrame* prevKidFrame = flow->LastChild(); + nsIFrame* kidFrame = nsnull; + for (;;) { + // Get the next content object + nsIContent* kid = mContent->ChildAt(kidIndex); + if (nsnull == kid) { + break; + } + + // Resolve style for the kid + nsIStyleContext* kidSC = aPresContext->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + + // Is it a floater? + if (kidMol->floats != NS_STYLE_FLOAT_NONE) { + PlaceholderFrame::NewFrame(&kidFrame, kid, kidIndex, this); + } else { + // Create initial frame for the child + nsIContentDelegate* kidDel; + nsresult fr; + switch (kidMol->display) { + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + // Pseudo block frames do not contain other block elements + // unless the block element would be the first child. + if (IsPseudoFrame()) { + // Update last content offset now that we are done drawing + // children from our parent. + SetLastContentOffset(prevKidFrame); + + // It better be true that we are not being asked to flow a + // block element as our first child. That means the body + // decided it needed a pseudo-frame when it shouldn't have. + NS_ASSERTION(nsnull != mFirstChild, "bad body"); + + NS_RELEASE(kidSC); + NS_RELEASE(kid); + + return; + } + // FALL THROUGH (and create frame) + + case NS_STYLE_DISPLAY_INLINE: + kidDel = kid->GetDelegate(aPresContext); + kidFrame = kidDel->CreateFrame(aPresContext, kid, kidIndex, this); + NS_RELEASE(kidDel); + break; + + default: + fr = nsFrame::NewFrame(&kidFrame, kid, kidIndex, this); + break; + } + } + kidFrame->SetStyleContext(kidSC); + NS_RELEASE(kidSC); + NS_RELEASE(kid); + + // Link child frame into the list of children + if (nsnull != prevKidFrame) { + NS_ASSERTION(nsnull == prevKidFrame->GetNextSibling(), "bad append"); + prevKidFrame->SetNextSibling(kidFrame); + } else { + NS_ASSERTION(nsnull == mFirstChild, "bad create"); + mFirstChild = kidFrame; + SetFirstContentOffset(kidFrame); + } + prevKidFrame = kidFrame; + kidIndex++; + mChildCount++; + } + SetLastContentOffset(prevKidFrame); + + // If this is a pseudo-frame then our parent will generate the + // reflow command. Otherwise, if the container is us then we should + // generate the reflow command because we were directly called. + if (!IsPseudoFrame() && (aContainer == mContent)) { + nsReflowCommand* rc = + new nsReflowCommand(aPresContext, flow, nsReflowCommand::FrameAppended, + startIndex); + aShell->AppendReflowCommand(rc); + } +} + +PRIntn nsBlockFrame::GetSkipSides() const +{ + PRIntn skip = 0; + if (nsnull != mPrevInFlow) { + skip |= 1 << NS_SIDE_TOP; + } + if (nsnull != mNextInFlow) { + skip |= 1 << NS_SIDE_BOTTOM; + } + return skip; +} + +nsHTMLFrameType nsBlockFrame::GetFrameType() const +{ + return eHTMLFrame_Block; +} + +void nsBlockFrame::ListTag(FILE* out) const +{ + if ((nsnull != mGeometricParent) && IsPseudoFrame()) { + fprintf(out, "*block(%d)@%p", mIndexInParent, this); + } else { + nsHTMLContainerFrame::ListTag(out); + } +} + +#ifdef NS_DEBUG +void nsBlockFrame::DumpFlow() const +{ +#ifdef NOISY_FLOW + nsBlockFrame* flow = (nsBlockFrame*) mNextInFlow; + while (flow != 0) { + printf(" %p: [%d,%d,%c]\n", + flow, flow->mFirstContentOffset, flow->mLastContentOffset, + (flow->mLastContentIsComplete ? 'T' : 'F')); + flow = (nsBlockFrame*) flow->mNextInFlow; + } +#endif +} +#endif diff --git a/mozilla/layout/generic/nsBlockReflowState.h b/mozilla/layout/generic/nsBlockReflowState.h new file mode 100644 index 00000000000..de26654f45d --- /dev/null +++ b/mozilla/layout/generic/nsBlockReflowState.h @@ -0,0 +1,2030 @@ +/* -*- 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 "nsBlockFrame.h" +#include "nsSize.h" +#include "nsIAnchoredItems.h" +#include "nsIContent.h" +#include "nsIContentDelegate.h" +#include "nsISpaceManager.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsIPresContext.h" +#include "nsMargin.h" +#include "nsHTMLIIDs.h" +#include "nsCSSLayout.h" +#include "nsCRT.h" +#include "nsIPresShell.h" +#include "nsReflowCommand.h" +#include "nsPlaceholderFrame.h" +#include "nsHTMLAtoms.h" +#include "nsHTMLValue.h" +#include "nsIHTMLContent.h" + +#ifdef NS_DEBUG +#undef NOISY +#undef NOISY_FLOW +#else +#undef NOISY +#undef NOISY_FLOW +#endif + +static NS_DEFINE_IID(kIRunaroundIID, NS_IRUNAROUND_IID); +static NS_DEFINE_IID(kIFloaterContainerIID, NS_IFLOATERCONTAINER_IID); +static NS_DEFINE_IID(kIAnchoredItemsIID, NS_IANCHOREDITEMS_IID); +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); +static NS_DEFINE_IID(kStyleFontSID, NS_STYLEFONT_SID); + +struct BlockBandData : public nsBandData { + nsRect data[5]; + + BlockBandData() {size = 5; rects = data;} +}; + +// XXX Bugs +// 1. right to left reflow can generate negative x coordinates. + +// XXX Speedup idea (all containers) + +// If I reflow a child and it gives back not-complete status then +// there is no sense in trying to pullup children. For blocks, it's a +// little more complicated unless the child is a block - if the child +// is a block, then we must be out of room hence we should stop. If +// the child is not a block then our line should be flushed (see #2 +// below) if our line is already empty then we must be out of room. + +// For inline frames and column frames, if we reflow a child and get +// back not-complete status then we should bail immediately because we +// are out of room. + +// XXX Speedup ideas: +// 1. change pullup code to use line information from next in flow +// 2. we can advance to next line immediately after reflowing something +// and noticing that it's not complete. +// 3. pass down last child information in aState so that pullup, etc., +// don't need to recompute it + +// XXX TODO: +// 0. Move justification into line flushing code + +// 1. To get ebina margins I need "auto" information from the style +// system margin's. A bottom/top margin of auto will then be computed like +// ebina computes it [however the heck that is]. + +// 2. kicking out floaters and talking with floater container to adjust +// left and right margins + +nsBlockReflowState::nsBlockReflowState() +{ +} + +void nsBlockReflowState::Init(const nsSize& aMaxSize, + nsSize* aMaxElementSize, + nsStyleFont* aFont, + nsStyleMolecule* aMol, + nsISpaceManager* aSpaceManager) +{ + firstLine = PR_TRUE; + allowLeadingWhitespace = PR_FALSE; + breakAfterChild = PR_FALSE; + breakBeforeChild = PR_FALSE; + firstChildIsInsideBullet = PR_FALSE; + nextListOrdinal = -1; + column = 0; + + spaceManager = aSpaceManager; + currentBand = new BlockBandData; + font = aFont; + mol = aMol; + availSize.width = aMaxSize.width; + availSize.height = aMaxSize.height; + maxElementSize = aMaxElementSize; + if (nsnull != aMaxElementSize) { + aMaxElementSize->width = 0; + aMaxElementSize->height = 0; + } + + kidXMost = 0; + x = 0; + y = 0; + + isInline = PR_FALSE; + currentLineNumber = 0; + lineStart = nsnull; + lineLength = 0; + ascents = ascentBuf; + maxAscent = 0; + maxDescent = 0; + lineWidth = 0; + maxPosBottomMargin = 0; + maxNegBottomMargin = 0; + lineMaxElementSize.width = 0; + lineMaxElementSize.height = 0; + lastContentIsComplete = PR_TRUE; + + maxAscents = sizeof(ascentBuf) / sizeof(ascentBuf[0]); + needRelativePos = PR_FALSE; + + prevLineLastFrame = nsnull; + prevLineHeight = 0; + topMargin = 0; + prevMaxPosBottomMargin = 0; + prevMaxNegBottomMargin = 0; + prevLineLastContentIsComplete = PR_TRUE; + + unconstrainedWidth = PRBool(aMaxSize.width == NS_UNCONSTRAINEDSIZE); + unconstrainedHeight = PRBool(aMaxSize.height == NS_UNCONSTRAINEDSIZE); + + justifying = (NS_STYLE_TEXT_ALIGN_JUSTIFY == mol->textAlign) && + (NS_STYLE_WHITESPACE_PRE != mol->whiteSpace); + reflowStatus = nsIFrame::frNotComplete; +} + +nsBlockReflowState::~nsBlockReflowState() +{ + if (ascents != ascentBuf) { + delete ascents; + } + delete currentBand; +} + +void nsBlockReflowState::AddAscent(nscoord aAscent) +{ + NS_PRECONDITION(lineLength <= maxAscents, "bad line length"); + if (lineLength == maxAscents) { + maxAscents *= 2; + nscoord* newAscents = new nscoord[maxAscents]; + if (nsnull != newAscents) { + nsCRT::memcpy(newAscents, ascents, sizeof(nscoord) * lineLength); + if (ascents != ascentBuf) { + delete ascents; + } + ascents = newAscents; + } else { + // Yikes! Out of memory! + return; + } + } + ascents[lineLength] = aAscent; +} + +void nsBlockReflowState::AdvanceToNextLine(nsIFrame* aPrevLineLastFrame, + nscoord aPrevLineHeight) +{ + firstLine = PR_FALSE; + allowLeadingWhitespace = PR_FALSE; + column = 0; + breakAfterChild = PR_FALSE; + breakBeforeChild = PR_FALSE; + lineStart = nsnull; + lineLength = 0; + currentLineNumber++; + maxAscent = 0; + maxDescent = 0; + lineWidth = 0; + needRelativePos = PR_FALSE; + + prevLineLastFrame = aPrevLineLastFrame; + prevLineHeight = aPrevLineHeight; + prevMaxPosBottomMargin = maxPosBottomMargin; + prevMaxNegBottomMargin = maxNegBottomMargin; + + // Remember previous line's lastContentIsComplete + prevLineLastContentIsComplete = lastContentIsComplete; + lastContentIsComplete = PR_TRUE; + + topMargin = 0; + maxPosBottomMargin = 0; + maxNegBottomMargin = 0; +} + +#ifdef NS_DEBUG +void nsBlockReflowState::DumpLine() +{ + nsIFrame* f = lineStart; + PRInt32 ll = lineLength; + while (--ll >= 0) { + printf(" "); + ((nsFrame*)f)->ListTag(stdout);/* XXX */ + printf("\n"); + f = f->GetNextSibling(); + } +} + +void nsBlockReflowState::DumpList() +{ + nsIFrame* f = lineStart; + while (nsnull != f) { + printf(" "); + ((nsFrame*)f)->ListTag(stdout);/* XXX */ + printf("\n"); + f = f->GetNextSibling(); + } +} +#endif + +//---------------------------------------------------------------------- + +nsresult nsBlockFrame::NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIFrame* it = new nsBlockFrame(aContent, aIndexInParent, aParent); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aInstancePtrResult = it; + return NS_OK; +} + +nsBlockFrame::nsBlockFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) + : nsHTMLContainerFrame(aContent, aIndexInParent, aParent) +{ +} + +nsBlockFrame::~nsBlockFrame() +{ + if (nsnull != mLines) { + delete mLines; + } +} + +nsresult +nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) +{ + NS_PRECONDITION(0 != aInstancePtr, "null ptr"); + if (NULL == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kIHTMLFrameTypeIID)) { + *aInstancePtr = (void*) ((nsIHTMLFrameType*) this); + return NS_OK; + } else if (aIID.Equals(kIRunaroundIID)) { + *aInstancePtr = (void*) ((nsIRunaround*) this); + return NS_OK; + } else if (aIID.Equals(kIFloaterContainerIID)) { + *aInstancePtr = (void*) ((nsIFloaterContainer*) this); + return NS_OK; + } + return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr); +} + +// Computes the top margin to use for this child frames based on its display +// type and the display type of the previous child frame. +// +// Adjacent vertical margins between block-level elements are collapsed. +nscoord nsBlockFrame::GetTopMarginFor(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsStyleMolecule* aKidMol, + PRBool aIsInline) +{ + if (aIsInline) { + // Just use whatever the previous bottom margin was + return aState.prevMaxPosBottomMargin - aState.prevMaxNegBottomMargin; + } else { + nscoord maxNegTopMargin = 0; + nscoord maxPosTopMargin = 0; + if (aKidMol->margin.top < 0) { + maxNegTopMargin = -aKidMol->margin.top; + } else { + maxPosTopMargin = aKidMol->margin.top; + } + + nscoord maxPos = PR_MAX(aState.prevMaxPosBottomMargin, maxPosTopMargin); + nscoord maxNeg = PR_MAX(aState.prevMaxNegBottomMargin, maxNegTopMargin); + return maxPos - maxNeg; + } +} + +void nsBlockFrame::PlaceBelowCurrentLineFloaters(nsIPresContext* aCX, + nsBlockReflowState& aState, + nscoord aY) +{ + NS_PRECONDITION(aState.floaterToDo.Count() > 0, "no floaters"); + + // XXX Factor this code with PlaceFloater()... + PRInt32 numFloaters = aState.floaterToDo.Count(); + + for (PRInt32 i = 0; i < numFloaters; i++) { + nsIFrame* floater = (nsIFrame*)aState.floaterToDo[i]; + nsRect region; + + // Get the band of available space + // XXX This is inefficient to do this inside the loop... + GetAvailableSpaceBand(aState, aY); + + // Get the type of floater + nsIStyleContext* styleContext = floater->GetStyleContext(aCX); + nsStyleMolecule* mol = (nsStyleMolecule*)styleContext->GetData(kStyleMoleculeSID); + NS_RELEASE(styleContext); + + floater->GetRect(region); + region.y = mCurrentState->currentBand->rects[0].y; + + if (NS_STYLE_FLOAT_LEFT == mol->floats) { + region.x = mCurrentState->currentBand->rects[0].x; + } else { + NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == mol->floats, "bad float type"); + region.x = mCurrentState->currentBand->rects[0].XMost() - region.width; + } + + // XXX Don't forget the floater's margins... + mCurrentState->spaceManager->Translate(mCurrentState->borderPadding.left, 0); + mCurrentState->spaceManager->AddRectRegion(region); + + // Set the origin of the floater in world coordinates + nscoord worldX, worldY; + + mCurrentState->spaceManager->GetTranslation(worldX, worldY); + floater->MoveTo(region.x + worldX, region.y + worldY); + mCurrentState->spaceManager->Translate(-mCurrentState->borderPadding.left, 0); + } + aState.floaterToDo.Clear(); +} + +/** + * Flush a line out. Return true if the line fits in our available + * height. If the line does not fit then return false. When the line + * fits we advance the y coordinate, reset the x coordinate and + * prepare the nsBlockReflowState for the next line. + */ +PRBool nsBlockFrame::AdvanceToNextLine(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ + NS_PRECONDITION(aState.lineLength > 0, "bad line"); + NS_PRECONDITION(nsnull != aState.lineStart, "bad line"); + + nscoord y = aState.y + aState.topMargin; + nscoord lineHeight; + + if (aState.isInline) { + // Vertically align the children on this line, returning the height of + // the line upon completion. + lineHeight = nsCSSLayout::VerticallyAlignChildren(aCX, this, aState.font, y, + aState.lineStart, aState.lineLength, + aState.ascents, aState.maxAscent); + + // Any below current line floaters to place? + if (aState.floaterToDo.Count() > 0) { + PlaceBelowCurrentLineFloaters(aCX, aState, y + lineHeight); + // XXX Factor in the height of the floaters as well when considering + // whether the line fits. + // The default policy is that if there isn't room for the floaters then + // both the line and the floaters are pushed to the next-in-flow... + } + } else { + lineHeight = aState.lineStart->GetHeight(); + } + + // The first line always fits + if (aState.currentLineNumber > 0) { + nscoord yb = aState.borderPadding.top + aState.availSize.height; + if (y + lineHeight > yb) { + // After vertical alignment of the children and factoring in the + // proper margin, the line doesn't fit. + return PR_FALSE; + } + } + + if (aState.isInline) { + // Check if the right-edge of the line exceeds our running x-most + nscoord xMost = aState.borderPadding.left + aState.lineWidth; + if (xMost > aState.kidXMost) { + aState.kidXMost = xMost; + } + } + + // Advance the y coordinate to the new position where the next + // line or block element will go. + aState.y = y + lineHeight; + aState.x = 0; + + // Now that the vertical alignment is done we can perform horizontal + // alignment and relative positioning. Skip all of these if we are + // doing an unconstrained (in x) reflow. There's no point in doing + // the work if we *know* we are going to reflowed again. + if (!aState.unconstrainedWidth) { + nsCSSLayout::HorizontallyPlaceChildren(aCX, this, aState.mol, + aState.lineStart, aState.lineLength, + aState.lineWidth, + aState.availSize.width); + + // Finally, now that the in-flow positions of the line's frames are + // known we can apply relative positioning if any of them need it. + if (!aState.justifying) { + nsCSSLayout::RelativePositionChildren(aCX, this, aState.mol, + aState.lineStart, + aState.lineLength); + } + } + + // Record line length + aState.lineLengths.AppendElement((void*)aState.lineLength); + + // Find the last frame in the line + // XXX keep this as running state in the nsBlockReflowState + nsIFrame* lastFrame = aState.lineStart; + PRInt32 lineLen = aState.lineLength - 1; + while (--lineLen >= 0) { + lastFrame = lastFrame->GetNextSibling(); + } + + // Update maxElementSize + if (nsnull != aState.maxElementSize) { + nsSize& lineMax = aState.lineMaxElementSize; + nsSize* maxMax = aState.maxElementSize; + if (lineMax.width > maxMax->width) { + maxMax->width = lineMax.width; + } + if (lineMax.height > maxMax->height) { + maxMax->height = lineMax.height; + } + aState.lineMaxElementSize.width = 0; + aState.lineMaxElementSize.height = 0; + } + + // Advance to the next line + aState.AdvanceToNextLine(lastFrame, lineHeight); + + return PR_TRUE; +} + +/** + * Add an inline child to the current line. Advance various running + * values after placement. + */ +void nsBlockFrame::AddInlineChildToLine(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsIFrame* aKidFrame, + nsReflowMetrics& aKidSize, + nsSize* aKidMaxElementSize, + nsStyleMolecule* aKidMol) +{ + NS_PRECONDITION(nsnull != aState.lineStart, "bad line"); + + PRIntn direction = aState.mol->direction; + if (NS_STYLE_POSITION_RELATIVE == aKidMol->positionFlags) { + aState.needRelativePos = PR_TRUE; + } + + // Place and size the child + // XXX add in left margin from kid + nsRect r; + r.y = aState.y; + r.width = aKidSize.width; + r.height = aKidSize.height; + if (NS_STYLE_DIRECTION_LTR == aState.mol->direction) { + // Left to right positioning. + r.x = aState.borderPadding.left + aState.x + aKidMol->margin.left; + aState.x += aKidSize.width + aKidMol->margin.left + aKidMol->margin.right; + } else { + // Right to left positioning + // XXX what should we do when aState.x goes negative??? + r.x = aState.x - aState.borderPadding.right - aKidMol->margin.right - aKidSize.width; + aState.x -= aKidSize.width + aKidMol->margin.right + aKidMol->margin.left; + } + aKidFrame->SetRect(r); + aState.AddAscent(aKidSize.ascent); + aState.lineWidth += aKidSize.width; + aState.lineLength++; + + // Update maximums for the line + if (aKidSize.ascent > aState.maxAscent) { + aState.maxAscent = aKidSize.ascent; + } + if (aKidSize.descent > aState.maxDescent) { + aState.maxDescent = aKidSize.descent; + } + // Update running margin maximums + if (aState.firstChildIsInsideBullet && (aKidFrame == mFirstChild)) { + // XXX temporary code. Since the molecule for the bullet frame + // is the same as the LI frame, we get bad style information. + // ignore it. + } else { + nscoord margin; +#if 0 + // XXX CSS2 spec says that top/bottom margin don't affect line height + // calculation. We're waiting for clarification on this issue... + if ((margin = aKidMol->margin.top) < 0) { + margin = -margin; + if (margin > aState.maxNegTopMargin) { + aState.maxNegTopMargin = margin; + } + } else { + if (margin > aState.maxPosTopMargin) { + aState.maxPosTopMargin = margin; + } + } +#endif + if ((margin = aKidMol->margin.bottom) < 0) { + margin = -margin; + if (margin > aState.maxNegBottomMargin) { + aState.maxNegBottomMargin = margin; + } + } else { + if (margin > aState.maxPosBottomMargin) { + aState.maxPosBottomMargin = margin; + } + } + } + + // Update line max element size + nsSize& mes = aState.lineMaxElementSize; + if (nsnull != aKidMaxElementSize) { + if (aKidMaxElementSize->width > mes.width) { + mes.width = aKidMaxElementSize->width; + } + if (aKidMaxElementSize->height > mes.height) { + mes.height = aKidMaxElementSize->height; + } + } +} + +// Places and sizes the block-level element, and advances the line. +// The rect is in the local coordinate space of the kid frame. +void nsBlockFrame::AddBlockChild(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsIFrame* aKidFrame, + nsRect& aKidRect, + nsSize* aKidMaxElementSize, + nsStyleMolecule* aKidMol) +{ + NS_PRECONDITION(nsnull != aState.lineStart, "bad line"); + + if (NS_STYLE_POSITION_RELATIVE == aKidMol->positionFlags) { + aState.needRelativePos = PR_TRUE; + } + + // Translate from the kid's coordinate space to our coordinate space + aKidRect.x += aState.borderPadding.left + aKidMol->margin.left; + aKidRect.y += aState.y + aState.topMargin; + + // Place and size the child + aKidFrame->SetRect(aKidRect); + + aState.AddAscent(aKidRect.height); + aState.lineLength++; + + // Is this the widest child frame? + nscoord xMost = aKidRect.XMost() + aKidMol->margin.right; + if (xMost > aState.kidXMost) { + aState.kidXMost = xMost; + } + + // Update the max element size + if (nsnull != aKidMaxElementSize) { + if (aKidMaxElementSize->width > aState.maxElementSize->width) { + aState.maxElementSize->width = aKidMaxElementSize->width; + } + if (aKidMaxElementSize->height > aState.maxElementSize->height) { + aState.maxElementSize->height = aKidMaxElementSize->height; + } + } + + // and the bottom line margin information which we'll use when placing + // the next child + if (aKidMol->margin.bottom < 0) { + aState.maxNegBottomMargin = -aKidMol->margin.bottom; + } else { + aState.maxPosBottomMargin = aKidMol->margin.bottom; + } + + // Update the running y-offset + aState.y += aKidRect.height + aState.topMargin; + + // Apply relative positioning if necessary + nsCSSLayout::RelativePositionChildren(aCX, this, aState.mol, aKidFrame, 1); + + // Advance to the next line + aState.AdvanceToNextLine(aKidFrame, aKidRect.height); +} + +/** + * Compute the available size for reflowing the given child at the + * current x,y position in the state. Note that this may return + * negative or zero width/height's if we are out of room. + */ +void nsBlockFrame::GetAvailSize(nsSize& aResult, + nsBlockReflowState& aState, + nsStyleMolecule* aKidMol, + PRBool aIsInline) +{ + // Determine the maximum available reflow height for the child + nscoord yb = aState.borderPadding.top + aState.availSize.height; + aResult.height = aState.unconstrainedHeight ? NS_UNCONSTRAINEDSIZE : + yb - aState.y - aState.topMargin; + + // Determine the maximum available reflow width for the child + if (aState.unconstrainedWidth) { + aResult.width = NS_UNCONSTRAINEDSIZE; + } else if (aIsInline) { + if (NS_STYLE_DIRECTION_LTR == aState.mol->direction) { + aResult.width = aState.currentBand->rects[0].XMost() - aState.x; + } else { + aResult.width = aState.x - aState.currentBand->rects[0].x; + } + } else { + // It's a block + aResult.width = aState.availSize.width - aKidMol->margin.left - + aKidMol->margin.right; + } +} + +/** + * Push all of the kids that we have not reflowed, starting at + * aState.lineStart. aPrevKid is the kid previous to aState.lineStart + * and is also our last child. Note that line length is NOT a + * reflection of the number of children we are actually pushing + * (because we don't break the sibling list as we add children to the + * line). + */ +void nsBlockFrame::PushKids(nsBlockReflowState& aState) +{ + nsIFrame* prevFrame = aState.prevLineLastFrame; + NS_PRECONDITION(nsnull != prevFrame, "pushing all kids"); + NS_PRECONDITION(prevFrame->GetNextSibling() == aState.lineStart, + "bad prev line"); + +#ifdef NS_DEBUG + PRInt32 numKids = LengthOf(mFirstChild); + NS_ASSERTION(numKids == mChildCount, "bad child count"); +#endif + +#ifdef NOISY + ListTag(stdout); + printf(": push kids (childCount=%d)\n", mChildCount); + DumpFlow(); +#endif + + PushChildren(aState.lineStart, prevFrame, mLastContentIsComplete); + SetLastContentOffset(prevFrame); + + // Set mLastContentIsComplete to the previous lines last content is + // complete now that the previous line's last child is our last + // child. + mLastContentIsComplete = aState.prevLineLastContentIsComplete; + + // Fix up child count + // XXX is there a better way? aState.lineLength doesn't work because + // we might be pushing more than just the pending line. + nsIFrame* kid = mFirstChild; + PRInt32 kids = 0; + while (nsnull != kid) { + kids++; + kid = kid->GetNextSibling(); + } + mChildCount = kids; + + // Make sure we have no lingering line data + aState.lineLength = 0; + aState.lineStart = nsnull; + +#ifdef NOISY + ListTag(stdout); + printf(": push kids done (childCount=%d) [%c]\n", mChildCount, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif +} + +/** + * Gets a band of available space starting at the specified y-offset. Assumes + * the local coordinate space is currently set to the upper-left origin of the + * bounding rect + * + * Updates "currentBand" and "x" member data of the block reflow state + */ +void nsBlockFrame::GetAvailableSpaceBand(nsBlockReflowState& aState, nscoord aY) +{ + // Gets a band of available space. + aState.spaceManager->Translate(aState.borderPadding.left, 0); + aState.spaceManager->GetBandData(aY, aState.availSize, *aState.currentBand); + + // XXX This is hack code that needs to change when the space manager interface + // changes to return both the available and unavailable space + // + // We'll get back anywhere between 1 and 3 rects depending on how many floaters + // there are. Actually the way it currently works we could get back zero rects + // if there are overlapping left and right floaters occupying all the space + if (aState.currentBand->count > 1) { + // If there are three rects then let's assume that there are floaters on the + // left and right and that only the middle rect is available + if (aState.currentBand->count == 3) { + aState.currentBand->rects[0] = aState.currentBand->rects[1]; + } else { + // There are two rects. That means either a left or right floater. Just use + // whichever space is larger. + if (aState.currentBand->rects[1].width > aState.currentBand->rects[0].width) { + aState.currentBand->rects[0] = aState.currentBand->rects[1]; + } + } + } + aState.spaceManager->Translate(-aState.borderPadding.left, 0); + aState.x = aState.currentBand->rects[0].x; +} + +void nsBlockFrame::ClearFloaters(nsBlockReflowState& aState, PRUint32 aClear) +{ + // Translate the coordinate space + aState.spaceManager->Translate(aState.borderPadding.left, 0); + +getBand: + nscoord y = aState.y + aState.topMargin; + PRBool isLeftFloater = PR_FALSE; + PRBool isRightFloater = PR_FALSE; + + // Get a band of available space + aState.spaceManager->GetBandData(y, aState.availSize, *aState.currentBand); + + if (aState.currentBand->count == 1) { + if (aState.currentBand->rects[0].width != aState.availSize.width) { + // Some of the space is taken up by floaters + if (aState.currentBand->rects[0].x > 0) { + isLeftFloater = PR_TRUE; + } + + if (aState.currentBand->rects[0].XMost() < aState.availSize.width) { + isRightFloater = PR_TRUE; + } + } + } else if (aState.currentBand->count == 2) { + if (aState.currentBand->rects[0].width > aState.currentBand->rects[1].width) { + isRightFloater = PR_TRUE; + } else { + isLeftFloater = PR_TRUE; + + // There may also be a right floater + if (aState.currentBand->rects[1].XMost() < aState.availSize.width) { + isRightFloater = PR_TRUE; + } + } + } else { + // Must be both left and right floaters + isLeftFloater = PR_TRUE; + isRightFloater = PR_TRUE; + } + + if (isLeftFloater) { + if ((aClear == NS_STYLE_CLEAR_LEFT) || (aClear == NS_STYLE_CLEAR_BOTH)) { + aState.y += aState.currentBand->rects[0].height; + goto getBand; + } + } + if (isRightFloater) { + if ((aClear == NS_STYLE_CLEAR_RIGHT) || (aClear == NS_STYLE_CLEAR_BOTH)) { + aState.y += aState.currentBand->rects[0].height; + goto getBand; + } + } + + aState.spaceManager->Translate(-aState.borderPadding.left, 0); +} + +// Bit's for PlaceAndReflowChild return value +#define PLACE_FIT 0x1 +#define PLACE_FLOWED 0x2 + +PRIntn +nsBlockFrame::PlaceAndReflowChild(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsIFrame* kidFrame, + nsStyleMolecule* aKidMol) +{ + nsSize kidMaxElementSize; + nsSize* pKidMaxElementSize = + (nsnull != aState.maxElementSize) ? &kidMaxElementSize : nsnull; + + // Get line start setup if we are at the start of a new line + if (nsnull == aState.lineStart) { + NS_ASSERTION(0 == aState.lineLength, "bad line length"); + aState.lineStart = kidFrame; + } + + // Get kid and its style + // XXX How is this any different than what was passed in to us as aKidMol? + nsIContent* kid = kidFrame->GetContent(); + nsIStyleContext* kidSC = kidFrame->GetStyleContext(aCX); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + NS_RELEASE(kid); + + // Figure out if kid is a block element or not + PRBool isInline = PR_TRUE; + PRIntn display = kidMol->display; + if (aState.firstChildIsInsideBullet && (mFirstChild == kidFrame)) { + // XXX Special hack for properly reflowing bullets that have the + // inside value for list-style-position. + display = NS_STYLE_DISPLAY_INLINE; + } + if ((NS_STYLE_DISPLAY_BLOCK == display) || + (NS_STYLE_DISPLAY_LIST_ITEM == display)) { + // Block elements always end up on the next line (unless they are + // already at the start of the line). + isInline = PR_FALSE; + if (aState.lineLength > 0) { + aState.breakAfterChild = PR_TRUE; + } + } + + // Handle forced break first + if (aState.breakAfterChild) { + NS_ASSERTION(aState.lineStart != kidFrame, "bad line"); + + // Get the last child in the current line + nsIFrame* lastFrame = aState.lineStart; + PRInt32 lineLen = aState.lineLength - 1; + while (--lineLen >= 0) { + lastFrame = lastFrame->GetNextSibling(); + } + + if (!AdvanceToNextLine(aCX, aState)) { + // The previous line didn't fit. + return 0; + } + aState.lineStart = kidFrame; + + // Get the style for the last child, and see if it wanted to clear floaters. + // This handles the BR tag, which is the only inline element for which clear + // applies + nsIStyleContext* lastChildSC = lastFrame->GetStyleContext(aCX); + nsStyleMolecule* lastChildMol = (nsStyleMolecule*)lastChildSC->GetData(kStyleMoleculeSID); + if (lastChildMol->clear != NS_STYLE_CLEAR_NONE) { + ClearFloaters(aState, lastChildMol->clear); + } + NS_RELEASE(lastChildSC); + } + + // Now that we've handled force breaks (and maybe called AdvanceToNextLine() + // which checks), remember whether it's an inline frame + aState.isInline = isInline; + + // If we're at the beginning of a line then compute the top margin that we + // should use + if (aState.lineStart == kidFrame) { + // Compute the top margin to use for this line + aState.topMargin = GetTopMarginFor(aCX, aState, kidMol, aState.isInline); + + // If it's an inline element then get a band of available space + // + // XXX If we have a current band and there's unused space in that band + // then avoid this call to get a band... + if (aState.isInline) { + GetAvailableSpaceBand(aState, aState.y + aState.topMargin); + } + } + + // Compute the available space to reflow the child into and then + // reflow it into that space. + nsSize kidAvailSize; + GetAvailSize(kidAvailSize, aState, kidMol, aState.isInline); + if ((aState.currentLineNumber > 0) && (kidAvailSize.height <= 0)) { + // No more room + return 0; + } + + ReflowStatus status; + + if (aState.isInline) { + nsReflowMetrics kidSize; + + // Inline elements are never passed the space manager + status = ReflowChild(kidFrame, aCX, kidSize, kidAvailSize, + pKidMaxElementSize); + + // For first children, we skip all the fit checks because we must + // fit at least one child for a parent to figure what to do with us. + if ((aState.currentLineNumber > 0) || (aState.lineLength > 0)) { + NS_ASSERTION(nsnull != aState.lineStart, "bad line start"); + + if (kidFrame == aState.lineStart) { + // Width always fits when we are at the logical left margin. + // Just check the height. + // + // XXX This height check isn't correct now that we have bands of + // available space... + if (kidSize.height > kidAvailSize.height) { + // It's too tall + return PLACE_FLOWED; + } + } else { + // Examine state and if the breakBeforeChild is set and we + // aren't already on the new line, do the forcing now. + // XXX Why aren't we doing this check BEFORE we resize reflow the child? + if (aState.breakBeforeChild) { + aState.breakBeforeChild = PR_FALSE; + if (kidFrame != aState.lineStart) { + if (!AdvanceToNextLine(aCX, aState)) { + // Flushing out the line failed. + return PLACE_FLOWED; + } + aState.lineStart = kidFrame; + + // Get a band of available space + GetAvailableSpaceBand(aState, aState.y + aState.topMargin); + + // Reflow child now that it has the line to itself + GetAvailSize(kidAvailSize, aState, kidMol, PR_TRUE); + status = ReflowChild(kidFrame, aCX, kidSize, kidAvailSize, + pKidMaxElementSize); + } + } + + // When we are not at the logical left margin then we need + // to check the width first. If we are too wide then advance + // to the next line and try reflowing again. + if (kidSize.width > kidAvailSize.width) { + // Too wide. Try next line + if (!AdvanceToNextLine(aCX, aState)) { + // Flushing out the line failed. + return PLACE_FLOWED; + } + aState.lineStart = kidFrame; + + // Get a band of available space + GetAvailableSpaceBand(aState, aState.y + aState.topMargin); + + // Reflow splittable children + if (kidFrame->IsSplittable()) { + // Update size info now that we are on the next line. Then + // reflow the child into the new available space. + GetAvailSize(kidAvailSize, aState, kidMol, PR_TRUE); + status = ReflowChild(kidFrame, aCX, kidSize, kidAvailSize, + pKidMaxElementSize); + + // If we just reflowed our last child then update the + // mLastContentIsComplete state. + if (nsnull == kidFrame->GetNextSibling()) { + // Use state from the reflow we just did + mLastContentIsComplete = PRBool(status == frComplete); + } + } + + // XXX This height check isn't correct now that we have bands of + // available space... + if (kidSize.height > kidAvailSize.height) { + // It's too tall on the next line + return PLACE_FLOWED; + } + // It's ok if it's too wide on the next line. + } + } + } + + // Add child to the line + AddInlineChildToLine(aCX, aState, kidFrame, kidSize, pKidMaxElementSize, kidMol); + + } else { + nsRect kidRect; + + // Does the block-level element want to clear any floaters that impact + // it? Note that the clear property only applies to block-level elements + // and the BR tag + if (aKidMol->clear != NS_STYLE_CLEAR_NONE) { + ClearFloaters(aState, aKidMol->clear); + GetAvailSize(kidAvailSize, aState, kidMol, PR_FALSE); + if ((aState.currentLineNumber > 0) && (kidAvailSize.height <= 0)) { + // No more room + return 0; + } + } + + // Give the block its own local coordinate space. + // + // XXX This is wrong to have the parent try and account for the kid's + // left margin here, because we have to wait until we know what the + // left edge is and that means resolving any floaters that impact the + // block. If the kid wants to interact with the space manager then it + // will have to deal with left/right margins itself + nscoord tx = aState.borderPadding.left + aKidMol->margin.left; + nscoord ty = aState.y + aState.topMargin; + + // Give the block-level element the opportunity to use the space manager + aState.spaceManager->Translate(tx, ty); + status = ReflowChild(kidFrame, aCX, aState.spaceManager, kidAvailSize, + kidRect, pKidMaxElementSize); + aState.spaceManager->Translate(-tx, -ty); + + // For first children, we skip all the fit checks because we must + // fit at least one child for a parent to figure what to do with us. + if ((aState.currentLineNumber > 0) || (aState.lineLength > 0)) { + // Block elements always fit horizontally (because they are + // always placed at the logical left margin). Check to see if + // the block fits vertically + if (kidRect.YMost() > kidAvailSize.height) { + // Nope + return PLACE_FLOWED; + } + } + + // Add block child + AddBlockChild(aCX, aState, kidFrame, kidRect, pKidMaxElementSize, kidMol); + } + + // If we just reflowed our last child then update the + // mLastContentIsComplete state. + if (nsnull == kidFrame->GetNextSibling()) { + // Use state from the reflow we just did + mLastContentIsComplete = PRBool(status == frComplete); + } + + aState.lastContentIsComplete = PRBool(status == frComplete); + if (aState.isInline && (frNotComplete == status)) { + // Since the inline child didn't complete its reflow we *know* + // that a continuation of it can't possibly fit on the current + // line. Therefore, set a flag in the state that will cause the + // a line break before the next frame is placed. + aState.breakAfterChild = PR_TRUE; + } + NS_RELEASE(kidSC); + + aState.reflowStatus = status; + return PLACE_FLOWED | PLACE_FIT; +} + +/** + * Reflow the existing frames. + * + * @param aCX presentation context to use + * @param aState in out parameter which tracks the state of + * reflow for the block frame. + * @return true if we successfully reflowed all the mapped children and false + * otherwise, e.g. we pushed children to the next in flow + */ +PRBool +nsBlockFrame::ReflowMappedChildren(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": reflow mapped (childCount=%d) [%d,%d,%c]\n", + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif + + PRBool result = PR_TRUE; + nsIFrame* kidFrame; + nsIFrame* prevKidFrame = nsnull; + + for (kidFrame = mFirstChild; nsnull != kidFrame; ) { + nsIContent* kid = kidFrame->GetContent(); + nsIStyleContext* kidSC = aCX->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + NS_RELEASE(kid); + + // Attempt to place and reflow the child + + // XXX if child is not splittable and it fits just place it where + // it is, otherwise advance to the next line and place it there if + // possible + + PRIntn placeStatus = PlaceAndReflowChild(aCX, aState, kidFrame, kidMol); + ReflowStatus status = aState.reflowStatus; + NS_RELEASE(kidSC); + if (0 == (placeStatus & PLACE_FIT)) { + // The child doesn't fit. Push it and any remaining children. + PushKids(aState); + result = PR_FALSE; + goto push_done; + } + + // Is the child complete? + if (frComplete == status) { + // Yes, the child is complete + NS_ASSERTION(nsnull == kidFrame->GetNextInFlow(), "bad child flow list"); + } else { + // No the child isn't complete + nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); + if (nsnull == kidNextInFlow) { + // The child doesn't have a next-in-flow so create a continuing + // frame. This hooks the child into the flow + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aCX, this); + NS_ASSERTION(nsnull != continuingFrame, "frame creation failed"); + + // Add the continuing frame to the sibling list + nsIFrame* nextSib = kidFrame->GetNextSibling(); + continuingFrame->SetNextSibling(nextSib); + kidFrame->SetNextSibling(continuingFrame); + mChildCount++; + } + + // Unlike the inline frame code we can't assume that we used + // up all of our space because the child's reflow status is + // frNotComplete. Instead, the child is probably split and + // we need to reflow the continuations as well. + } + + // Get the next child frame + prevKidFrame = kidFrame; + kidFrame = kidFrame->GetNextSibling(); + } + + push_done:; + // Update the child count member data + NS_POSTCONDITION(LastChild()->GetIndexInParent() == mLastContentOffset, "bad last content offset"); + +#ifdef NS_DEBUG + PRInt32 len = LengthOf(mFirstChild); + NS_POSTCONDITION(len == mChildCount, "bad child count"); + VerifyLastIsComplete(); +#endif + +#ifdef NOISY + ListTag(stdout); + printf(": reflow mapped %sok (childCount=%d) [%d,%d,%c]\n", + (result ? "" : "NOT "), + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif + return result; +} + +PRBool nsBlockFrame::MoreToReflow(nsIPresContext* aCX) +{ + PRBool rv = PR_FALSE; + if (IsPseudoFrame()) { + // Get the next content object that we would like to reflow + PRInt32 kidIndex = NextChildOffset(); + nsIContent* kid = mContent->ChildAt(kidIndex); + if (nsnull != kid) { + // Resolve style for the kid + nsIStyleContext* kidSC = aCX->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + switch (kidMol->display) { + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + // Block pseudo-frames do not contain other block elements + break; + + default: + rv = PR_TRUE; + break; + } + NS_RELEASE(kidSC); + NS_RELEASE(kid); + } + } else { + if (NextChildOffset() < mContent->ChildCount()) { + rv = PR_TRUE; + } + } + return rv; +} + +/** + * Create new frames for content we haven't yet mapped + * + * @param aCX presentation context to use + * @return frComplete if all content has been mapped and frNotComplete + * if we should be continued + */ +nsIFrame::ReflowStatus +nsBlockFrame::ReflowAppendedChildren(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif + nsIFrame* kidPrevInFlow = nsnull; + ReflowStatus result = frNotComplete; + + // If we have no children and we have a prev-in-flow then we need to pick + // up where it left off. If we have children, e.g. we're being resized, then + // our content offset should already be set correctly... + if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) { + nsBlockFrame* prev = (nsBlockFrame*) mPrevInFlow; + NS_ASSERTION(prev->mLastContentOffset >= prev->mFirstContentOffset, "bad prevInFlow"); + mFirstContentOffset = prev->NextChildOffset(); + if (PR_FALSE == prev->mLastContentIsComplete) { + // Our prev-in-flow's last child is not complete + kidPrevInFlow = prev->LastChild(); + } + } + + // Place our children, one at a time until we are out of children + PRInt32 kidIndex = NextChildOffset(); + nsIFrame* prevKidFrame = LastChild(); + nsIFrame* kidFrame = nsnull; + for (;;) { + // Get the next content object + nsIContent* kid = mContent->ChildAt(kidIndex); + if (nsnull == kid) { + result = frComplete; + break; + } + + // Resolve style for the kid + nsIStyleContext* kidSC = aCX->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + + // Is it a floater? + if (kidMol->floats != NS_STYLE_FLOAT_NONE) { + PlaceholderFrame::NewFrame(&kidFrame, kid, kidIndex, this); + kidFrame->SetStyleContext(kidSC); + } else if (nsnull == kidPrevInFlow) { + // Create initial frame for the child + nsIContentDelegate* kidDel; + nsresult fr; + switch (kidMol->display) { + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + // Pseudo block frames do not contain other block elements + // unless the block element would be the first child. + if (IsPseudoFrame()) { + // If we're being used as a pseudo frame, i.e. we map the same + // content as our parent then we want to indicate we're complete; + // otherwise we'll be continued and go on mapping children... + + // It better be true that we are not being asked to flow a + // block element as our first child. That means the body + // decided it needed a pseudo-frame when it shouldn't have. + NS_ASSERTION(nsnull != mFirstChild, "bad body"); + + NS_RELEASE(kidSC); + NS_RELEASE(kid); + result = frComplete; + goto done; + } + // FALL THROUGH (and create frame) + + case NS_STYLE_DISPLAY_INLINE: + kidDel = kid->GetDelegate(aCX); + kidFrame = kidDel->CreateFrame(aCX, kid, kidIndex, this); + NS_RELEASE(kidDel); + break; + + default: + NS_ASSERTION(nsnull == kidPrevInFlow, "bad prev in flow"); + fr = nsFrame::NewFrame(&kidFrame, kid, kidIndex, this); + break; + } + kidFrame->SetStyleContext(kidSC); + } else { + // Since kid has a prev-in-flow, use that to create the next + // frame. + kidFrame = kidPrevInFlow->CreateContinuingFrame(aCX, this); + } + + // Link child frame into the list of children. If the frame ends + // up not fitting and getting pushed, the PushKids code will fixup + // the child count for us. + if (nsnull != prevKidFrame) { + NS_ASSERTION(nsnull == prevKidFrame->GetNextSibling(), "bad append"); + prevKidFrame->SetNextSibling(kidFrame); + } else { + NS_ASSERTION(nsnull == mFirstChild, "bad create"); + mFirstChild = kidFrame; + SetFirstContentOffset(kidFrame); + } + prevKidFrame = kidFrame; + mChildCount++; + + // Reflow child frame as many times as necessary until it is + // complete. + ReflowStatus status; + do { + PRIntn placeStatus = PlaceAndReflowChild(aCX, aState, kidFrame, kidMol); + status = aState.reflowStatus; + if (0 == (placeStatus & PLACE_FIT)) { + // We ran out of room. + mLastContentIsComplete = PRBool(nsnull == kidFrame->GetNextInFlow()); + PushKids(aState); + + NS_RELEASE(kid); + NS_RELEASE(kidSC); + goto push_done; + } + + // Did the child complete? + prevKidFrame = kidFrame; + if (frNotComplete == status) { + // Child didn't complete so create a continuing frame + kidPrevInFlow = kidFrame; + nsIFrame* continuingFrame = kidFrame->CreateContinuingFrame(aCX, this); + + // Add the continuing frame to the sibling list + continuingFrame->SetNextSibling(kidFrame->GetNextSibling()); + kidFrame->SetNextSibling(continuingFrame); + kidFrame = continuingFrame; + mChildCount++; + + // Switch to new kid style + NS_RELEASE(kidSC); + kidSC = kidFrame->GetStyleContext(aCX); + kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + } + NS_ASSERTION(nsnull == kidFrame->GetNextInFlow(), "huh?"); + } while (frNotComplete == status); + NS_RELEASE(kid); + NS_RELEASE(kidSC); + + // The child that we just reflowed is complete + NS_ASSERTION(nsnull == kidFrame->GetNextInFlow(), "bad child flow list"); + kidIndex++; + kidPrevInFlow = nsnull; + } + + done: + // To get here we either completely reflowed all our appended + // children OR we are a pseudo-frame and we ran into a block + // element. In either case our last content MUST be complete. + NS_ASSERTION(PR_TRUE == aState.lastContentIsComplete, "bad state"); + + NS_ASSERTION(LastChild() == prevKidFrame, "bad last child"); + SetLastContentOffset(prevKidFrame); + + push_done: +#ifdef NS_DEBUG + PRInt32 len = LengthOf(mFirstChild); + NS_ASSERTION(len == mChildCount, "bad child count"); + VerifyLastIsComplete(); +#endif + return result; +} + +/** + * Pullup frames from our next in flow and try to place them. Before + * this is called our previously mapped children, if any have been + * reflowed which means that the block reflow state's x and y + * coordinates and other data are ready to go. + * + * Return true if we pulled everything up. + */ +PRBool +nsBlockFrame::PullUpChildren(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": pullup (childCount=%d) [%d,%d,%c]\n", + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif + + PRBool result = PR_TRUE; + nsBlockFrame* nextInFlow = (nsBlockFrame*) mNextInFlow; + nsIFrame* prevKidFrame = LastChild(); + while (nsnull != nextInFlow) { + // Get first available frame from the next-in-flow + nsIFrame* kidFrame = PullUpOneChild(nextInFlow, prevKidFrame); + if (nsnull == kidFrame) { + // We've pulled up all the children from that next-in-flow, so + // move to the next next-in-flow. + nextInFlow = (nsBlockFrame*) nextInFlow->mNextInFlow; + continue; + } + + // Get style information for the pulled up kid + nsIContent* kid = kidFrame->GetContent(); + nsIStyleContext* kidSC = aCX->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + + ReflowStatus status; + do { + PRIntn placeStatus = PlaceAndReflowChild(aCX, aState, kidFrame, kidMol); + status = aState.reflowStatus; + if (0 == (placeStatus & PLACE_FIT)) { + // Push the kids that didn't fit back down to the next-in-flow + mLastContentIsComplete = PRBool(nsnull == kidFrame->GetNextInFlow()); + PushKids(aState); + + result = PR_FALSE; + NS_RELEASE(kid); + NS_RELEASE(kidSC); + goto push_done; + } + + if (frNotComplete == status) { + // Child is not complete + nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); + if (nsnull == kidNextInFlow) { + // Create a continuing frame for the incomplete child + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aCX, this); + + // Add the continuing frame to our sibling list. + continuingFrame->SetNextSibling(kidFrame->GetNextSibling()); + kidFrame->SetNextSibling(continuingFrame); + prevKidFrame = kidFrame; + kidFrame = continuingFrame; + mChildCount++; + + // Switch to new kid style + NS_RELEASE(kidSC); + kidSC = kidFrame->GetStyleContext(aCX); + kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + } else { + // The child has a next-in-flow, but it's not one of ours. + // It *must* be in one of our next-in-flows. Collect it + // then. + NS_ASSERTION(kidNextInFlow->GetGeometricParent() != this, + "busted kid next-in-flow"); + break; + } + } + } while (frNotComplete == status); + NS_RELEASE(kid); + NS_RELEASE(kidSC); + + prevKidFrame = kidFrame; + } + + if (nsnull != prevKidFrame) { + // The only way we can get here is by pulling up every last child + // in our next-in-flows (and reflowing any continunations they + // have). Therefore we KNOW that our last child is complete. + NS_ASSERTION(PR_TRUE == aState.lastContentIsComplete, "bad state"); + NS_ASSERTION(LastChild() == prevKidFrame, "bad last child"); + SetLastContentOffset(prevKidFrame); + } + + push_done:; + + if (result == PR_FALSE) { + // If our next-in-flow is empty OR our next next-in-flow is empty + // then adjust the offsets of all of the empty next-in-flows. + nextInFlow = (nsBlockFrame*) mNextInFlow; + if ((0 == nextInFlow->mChildCount) || + ((nsnull != nextInFlow->mNextInFlow) && + (0 == ((nsBlockFrame*)(nextInFlow->mNextInFlow))->mChildCount))) { + // We didn't pullup everything and we need to fixup one of our + // next-in-flows content offsets. + AdjustOffsetOfEmptyNextInFlows(); + } + } + + +#ifdef NS_DEBUG + PRInt32 len = LengthOf(mFirstChild); + NS_ASSERTION(len == mChildCount, "bad child count"); + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": pullup %sok (childCount=%d) [%d,%d,%c]\n", + (result ? "" : "NOT "), + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif + return result; +} + +void nsBlockFrame::SetupState(nsIPresContext* aCX, + nsBlockReflowState& aState, + const nsSize& aMaxSize, + nsSize* aMaxElementSize, + nsISpaceManager* aSpaceManager) +{ + // Setup reflow state + nsStyleMolecule* mol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + nsStyleFont* font = + (nsStyleFont*)mStyleContext->GetData(kStyleFontSID); + aState.Init(aMaxSize, aMaxElementSize, font, mol, aSpaceManager); + + // Apply border and padding adjustments for regular frames only + if (PR_FALSE == IsPseudoFrame()) { + aState.borderPadding = mol->borderPadding; + aState.y = mol->borderPadding.top; + aState.availSize.width -= + (mol->borderPadding.left + mol->borderPadding.right); + aState.availSize.height -= + (mol->borderPadding.top + mol->borderPadding.bottom); + } else { + aState.borderPadding.SizeTo(0, 0, 0, 0); + } + + // Setup initial list ordinal value + nsIAtom* tag = mContent->GetTag(); + if ((tag == nsHTMLAtoms::ul) || (tag == nsHTMLAtoms::ol) || + (tag == nsHTMLAtoms::menu) || (tag == nsHTMLAtoms::dir)) { + nsHTMLValue value; + if (eContentAttr_HasValue == + ((nsIHTMLContent*)mContent)->GetAttribute(nsHTMLAtoms::start, value)) { + if (eHTMLUnit_Absolute == value.GetUnit()) { + aState.nextListOrdinal = value.GetIntValue(); + } + } + } + NS_RELEASE(tag); + + mCurrentState = &aState; +} + +#include "nsUnitConversion.h"/* XXX */ +nsIFrame::ReflowStatus +nsBlockFrame::ResizeReflow(nsIPresContext* aCX, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsSize* aMaxElementSize) +{ + nsBlockReflowState state; + SetupState(aCX, state, aMaxSize, aMaxElementSize, aSpaceManager); + return DoResizeReflow(aCX, state, aDesiredRect); +} + +nsIFrame::ReflowStatus +nsBlockFrame::DoResizeReflow(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsRect& aDesiredRect) +{ +#ifdef NS_DEBUG + PreReflowCheck(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": resize reflow %g,%g\n", + NS_TWIPS_TO_POINTS_FLOAT(aState.availSize.width), + NS_TWIPS_TO_POINTS_FLOAT(aState.availSize.height)); + DumpFlow(); +#endif + + // Zap old line data + if (nsnull != mLines) { + delete mLines; + mLines = nsnull; + } + mNumLines = 0; + + // Check for an overflow list + MoveOverflowToChildList(); + + // Before we start reflowing, cache a pointer to our state structure + // so that inline frames can find it. + nsIPresShell* shell = aCX->GetShell(); + shell->PutCachedData(this, &aState); + + // First reflow any existing frames + PRBool reflowMappedOK = PR_TRUE; + ReflowStatus status = frComplete; + if (nsnull != mFirstChild) { + reflowMappedOK = ReflowMappedChildren(aCX, aState); + if (!reflowMappedOK) { + status = frNotComplete; + } + } + + if (reflowMappedOK) { + // Any space left? + nscoord yb = aState.borderPadding.top + aState.availSize.height; + if ((nsnull != mFirstChild) && (aState.y >= yb)) { + // No space left. Don't try to pull-up children or reflow + // unmapped. We need to return the correct completion status, + // so see if there is more to reflow. + if (MoreToReflow(aCX)) { + status = frNotComplete; + } + } else if (MoreToReflow(aCX)) { + // Try and pull-up some children from a next-in-flow + if ((nsnull == mNextInFlow) || PullUpChildren(aCX, aState)) { + // If we still have unmapped children then create some new frames + if (MoreToReflow(aCX)) { + status = ReflowAppendedChildren(aCX, aState); + } + } else { + // We were unable to pull-up all the existing frames from the + // next in flow + status = frNotComplete; + } + } + } + + // Deal with last line - make sure it gets vertically and + // horizontally aligned. This also updates the state's y coordinate + // which is good because that's how we size ourselves. + if (0 != aState.lineLength) { + if (!AdvanceToNextLine(aCX, aState)) { + // The last line of output doesn't fit. Push all of the kids to + // the next in flow and change our reflow status to not complete + // so that we are continued. +#ifdef NOISY + ListTag(stdout); + printf(": pushing kids since last line doesn't fit\n"); +#endif + + PushKids(aState); + status = frNotComplete; + } + } + + if (frComplete == status) { + // Don't forget to add in the bottom margin from our last child. + // Only add it in if there is room for it. + nscoord margin = aState.prevMaxPosBottomMargin - + aState.prevMaxNegBottomMargin; + nscoord y = aState.y + margin; + if (y <= aState.borderPadding.top + aState.availSize.height) { + aState.y = y; + } + } + + // Now that reflow has finished, remove the cached pointer + shell->RemoveCachedData(this); + NS_RELEASE(shell); + + // Translate state.lineLengths into an integer array + mNumLines = aState.lineLengths.Count(); + if (mNumLines > 0) { + mLines = new PRInt32[mNumLines]; + for (PRInt32 i = 0; i < mNumLines; i++) { + PRInt32 ll = (PRInt32) aState.lineLengths.ElementAt(i); + mLines[i] = ll; + } + } + + if (!aState.unconstrainedWidth && aState.justifying) { + // Perform justification now that we know how many lines we have. + JustifyLines(aCX, aState); + } + + // Return our desired rect and our status + aDesiredRect.x = 0; + aDesiredRect.y = 0; + aDesiredRect.width = aState.kidXMost + aState.borderPadding.right; + if (!aState.unconstrainedWidth) { + // Make sure we're at least as wide as the max size we were given + nscoord maxWidth = aState.availSize.width + aState.borderPadding.left + + aState.borderPadding.right; + + if (aDesiredRect.width < maxWidth) { + aDesiredRect.width = maxWidth; + } + } + aState.y += aState.borderPadding.bottom; + aDesiredRect.height = aState.y; + +#ifdef NS_DEBUG + PostReflowCheck(status); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": resize reflow %g,%g %scomplete [%d,%d,%c]\n", + NS_TWIPS_TO_POINTS_FLOAT(aState.availSize.width), + NS_TWIPS_TO_POINTS_FLOAT(aState.availSize.height), + ((status == frNotComplete) ? "NOT " : ""), + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F') + ); + DumpFlow(); +#endif + mCurrentState = nsnull; + return status; +} + +void nsBlockFrame::JustifyLines(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ + // XXX we don't justify the last line; what if we are continued, + // should we do it then? + nsIFrame* kid = mFirstChild; + for (PRInt32 i = 0; i < mNumLines; i++) { + nsIFrame* lineStart = kid; + PRInt32 lineLength = mLines[i]; + if (i < mNumLines - 1) { + if (1 == lineLength) { + // For lines with one element on them we can take a shortcut and + // let them do the justification. Note that we still call + // JustifyReflow even if the available space is zero in case the + // child is a hunk of text that ends in whitespace. The whitespace + // will be distributed elsewhere causing a proper flush right look + // for the last word. + nsRect r; + kid->GetRect(r); + nscoord maxWidth = aState.availSize.width; + nscoord availableSpace = maxWidth - r.width; + nscoord maxAvailSpace = nscoord(maxWidth * 0.1f); + if ((availableSpace >= 0) && (availableSpace < maxAvailSpace)) { + kid->JustifyReflow(aCX, availableSpace); + kid->SizeTo(r.width + availableSpace, r.height); + } + kid = kid->GetNextSibling(); + } else { + // XXX Get justification of multiple elements working + while (--lineLength >= 0) { + kid = kid->GetNextSibling(); + } + } + } + + // Finally, now that the in-flow positions of the line's frames are + // known we can apply relative positioning if any of them need it. + nsCSSLayout::RelativePositionChildren(aCX, this, aState.mol, + lineStart, mLines[i]); + } +} + +nsIFrame* nsBlockFrame::CreateContinuingFrame(nsIPresContext* aCX, + nsIFrame* aParent) +{ + nsBlockFrame* cf = new nsBlockFrame(mContent, mIndexInParent, aParent); + PrepareContinuingFrame(aCX, aParent, cf); + return cf; +} + +nsIFrame::ReflowStatus +nsBlockFrame::IncrementalReflow(nsIPresContext* aCX, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsReflowCommand& aReflowCommand) +{ + ReflowStatus status = frComplete; + + if (aReflowCommand.GetTarget() == this) { + // XXX for now, just do a complete reflow mapped (it'll kinda + // work, but it's slow) + + nsBlockReflowState state; + SetupState(aCX, state, aMaxSize, nsnull, aSpaceManager); + PRBool reflowMappedOK = ReflowMappedChildren(aCX, state); + if (!reflowMappedOK) { + status = frNotComplete; + } + } else { + // XXX not yet implemented + NS_ABORT(); + // XXX work to compute initial state goes *HERE* + aDesiredRect.x = 0; + aDesiredRect.y = 0; + aDesiredRect.width = 0; + aDesiredRect.height = 0; + } + + mCurrentState = nsnull; + return status; +} + +PRBool nsBlockFrame::IsLeftMostChild(nsIFrame* aFrame) +{ + do { + nsIFrame* parent = aFrame->GetGeometricParent(); + + // See if there are any non-zero sized child frames that precede aFrame + // in the child list + nsIFrame* child = parent->FirstChild(); + + while ((nsnull != child) && (aFrame != child)) { + // Is the child zero-sized? + if ((child->GetWidth() > 0) || (child->GetHeight() > 0)) { + // We found a non-zero sized child frame that precedes aFrame + return PR_FALSE; + } + + child = child->GetNextSibling(); + } + + // aFrame is the left-most non-zero sized frame in its geometric parent. + // Walk up one level and check that its parent is left-most as well + aFrame = parent; + } while (aFrame != this); + + return PR_TRUE; +} + +PRBool nsBlockFrame::AddFloater(nsIPresContext* aCX, + nsIFrame* aFloater, + PlaceholderFrame* aPlaceholder) +{ + // Get the frame associated with the space manager, and get its nsIAnchoredItems + // interface + nsIFrame* frame = mCurrentState->spaceManager->GetFrame(); + nsIAnchoredItems* anchoredItems = nsnull; + + frame->QueryInterface(kIAnchoredItemsIID, (void**)&anchoredItems); + NS_ASSERTION(nsnull != anchoredItems, "no anchored items interface"); + + if (nsnull != anchoredItems) { + anchoredItems->AddAnchoredItem(aFloater, nsIAnchoredItems::anHTMLFloater, this); + PlaceFloater(aCX, aFloater, aPlaceholder); + return PR_TRUE; + } + + return PR_FALSE; +} + +// XXX The size of the floater needs to be taken into consideration if we're +// computing a maximum element size +void nsBlockFrame::PlaceFloater(nsIPresContext* aCX, + nsIFrame* aFloater, + PlaceholderFrame* aPlaceholder) +{ + // If the floater is the left-most non-zero size child frame then insert + // it before the current line; otherwise add it to the below-current-line + // todo list and we'll handle it when we flush out the line + if (IsLeftMostChild(aPlaceholder)) { + // Get the type of floater + nsIStyleContext* styleContext = aFloater->GetStyleContext(aCX); + nsStyleMolecule* mol = (nsStyleMolecule*)styleContext->GetData(kStyleMoleculeSID); + NS_RELEASE(styleContext); + + if (!mCurrentState->isInline) { + // Get the current band for this line + GetAvailableSpaceBand(*mCurrentState, mCurrentState->y + mCurrentState->topMargin); + } + + // Commit some space in the space manager + nsRect region; + + aFloater->GetRect(region); + region.y = mCurrentState->currentBand->rects[0].y; + + if (NS_STYLE_FLOAT_LEFT == mol->floats) { + region.x = mCurrentState->currentBand->rects[0].x; + } else { + NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == mol->floats, "bad float type"); + region.x = mCurrentState->currentBand->rects[0].XMost() - region.width; + } + + // XXX Don't forget the floater's margins... + mCurrentState->spaceManager->Translate(mCurrentState->borderPadding.left, 0); + mCurrentState->spaceManager->AddRectRegion(region); + + // Set the origin of the floater in world coordinates + nscoord worldX, worldY; + + mCurrentState->spaceManager->GetTranslation(worldX, worldY); + aFloater->MoveTo(region.x + worldX, region.y + worldY); + mCurrentState->spaceManager->Translate(-mCurrentState->borderPadding.left, 0); + + // Update the band of available space to reflect space taken up by the floater + GetAvailableSpaceBand(*mCurrentState, mCurrentState->y + mCurrentState->topMargin); + } else { + // Add the floater to our to-do list + mCurrentState->floaterToDo.AppendElement(aFloater); + } +} + +void nsBlockFrame::ContentAppended(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer) +{ + // Zip down to the end-of-flow + nsBlockFrame* flow = this; + for (;;) { + nsBlockFrame* next = (nsBlockFrame*) flow->GetNextInFlow(); + if (nsnull == next) { + break; + } + flow = next; + } + + PRInt32 kidIndex = flow->NextChildOffset(); + PRInt32 startIndex = kidIndex; + nsIFrame* prevKidFrame = flow->LastChild(); + nsIFrame* kidFrame = nsnull; + for (;;) { + // Get the next content object + nsIContent* kid = mContent->ChildAt(kidIndex); + if (nsnull == kid) { + break; + } + + // Resolve style for the kid + nsIStyleContext* kidSC = aPresContext->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + + // Is it a floater? + if (kidMol->floats != NS_STYLE_FLOAT_NONE) { + PlaceholderFrame::NewFrame(&kidFrame, kid, kidIndex, this); + } else { + // Create initial frame for the child + nsIContentDelegate* kidDel; + nsresult fr; + switch (kidMol->display) { + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + // Pseudo block frames do not contain other block elements + // unless the block element would be the first child. + if (IsPseudoFrame()) { + // Update last content offset now that we are done drawing + // children from our parent. + SetLastContentOffset(prevKidFrame); + + // It better be true that we are not being asked to flow a + // block element as our first child. That means the body + // decided it needed a pseudo-frame when it shouldn't have. + NS_ASSERTION(nsnull != mFirstChild, "bad body"); + + NS_RELEASE(kidSC); + NS_RELEASE(kid); + + return; + } + // FALL THROUGH (and create frame) + + case NS_STYLE_DISPLAY_INLINE: + kidDel = kid->GetDelegate(aPresContext); + kidFrame = kidDel->CreateFrame(aPresContext, kid, kidIndex, this); + NS_RELEASE(kidDel); + break; + + default: + fr = nsFrame::NewFrame(&kidFrame, kid, kidIndex, this); + break; + } + } + kidFrame->SetStyleContext(kidSC); + NS_RELEASE(kidSC); + NS_RELEASE(kid); + + // Link child frame into the list of children + if (nsnull != prevKidFrame) { + NS_ASSERTION(nsnull == prevKidFrame->GetNextSibling(), "bad append"); + prevKidFrame->SetNextSibling(kidFrame); + } else { + NS_ASSERTION(nsnull == mFirstChild, "bad create"); + mFirstChild = kidFrame; + SetFirstContentOffset(kidFrame); + } + prevKidFrame = kidFrame; + kidIndex++; + mChildCount++; + } + SetLastContentOffset(prevKidFrame); + + // If this is a pseudo-frame then our parent will generate the + // reflow command. Otherwise, if the container is us then we should + // generate the reflow command because we were directly called. + if (!IsPseudoFrame() && (aContainer == mContent)) { + nsReflowCommand* rc = + new nsReflowCommand(aPresContext, flow, nsReflowCommand::FrameAppended, + startIndex); + aShell->AppendReflowCommand(rc); + } +} + +PRIntn nsBlockFrame::GetSkipSides() const +{ + PRIntn skip = 0; + if (nsnull != mPrevInFlow) { + skip |= 1 << NS_SIDE_TOP; + } + if (nsnull != mNextInFlow) { + skip |= 1 << NS_SIDE_BOTTOM; + } + return skip; +} + +nsHTMLFrameType nsBlockFrame::GetFrameType() const +{ + return eHTMLFrame_Block; +} + +void nsBlockFrame::ListTag(FILE* out) const +{ + if ((nsnull != mGeometricParent) && IsPseudoFrame()) { + fprintf(out, "*block(%d)@%p", mIndexInParent, this); + } else { + nsHTMLContainerFrame::ListTag(out); + } +} + +#ifdef NS_DEBUG +void nsBlockFrame::DumpFlow() const +{ +#ifdef NOISY_FLOW + nsBlockFrame* flow = (nsBlockFrame*) mNextInFlow; + while (flow != 0) { + printf(" %p: [%d,%d,%c]\n", + flow, flow->mFirstContentOffset, flow->mLastContentOffset, + (flow->mLastContentIsComplete ? 'T' : 'F')); + flow = (nsBlockFrame*) flow->mNextInFlow; + } +#endif +} +#endif diff --git a/mozilla/layout/generic/nsHTMLContainerFrame.cpp b/mozilla/layout/generic/nsHTMLContainerFrame.cpp new file mode 100644 index 00000000000..960b6c0396d --- /dev/null +++ b/mozilla/layout/generic/nsHTMLContainerFrame.cpp @@ -0,0 +1,321 @@ +/* -*- 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 "nsHTMLContainerFrame.h" +#include "nsIRenderingContext.h" +#include "nsIPresContext.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsCSSRendering.h" +#include "nsIContent.h" +#include "nsHTMLAtoms.h" +#include "nsIWidget.h" +#include "nsILinkHandler.h" +#include "nsHTMLValue.h" +#include "nsGUIEvent.h" +#include "nsIDocument.h" +#include "nsIURL.h" + +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); +static NS_DEFINE_IID(kStyleColorSID, NS_STYLECOLOR_SID); + +nsHTMLContainerFrame::nsHTMLContainerFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) + : nsContainerFrame(aContent, aIndexInParent, aParent) +{ +} + +nsHTMLContainerFrame::~nsHTMLContainerFrame() +{ +} + +void +nsHTMLContainerFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + // Do not paint ourselves if we are a pseudo-frame + if (PR_FALSE == IsPseudoFrame()) { + PRIntn skipSides = GetSkipSides(); + nsStyleColor* color = + (nsStyleColor*)mStyleContext->GetData(kStyleColorSID); + nsStyleMolecule* mol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this, + aDirtyRect, mRect, *color); + nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, + aDirtyRect, mRect, *mol, skipSides); + } + + PaintChildren(aPresContext, aRenderingContext, aDirtyRect); + + if (nsIFrame::GetShowFrameBorders()) { + aRenderingContext.SetColor(NS_RGB(255,0,0)); + aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height); + } +} + +void nsHTMLContainerFrame::TriggerLink(nsIPresContext& aPresContext, + const nsString& aBase, + const nsString& aURLSpec, + const nsString& aTargetSpec) +{ + nsILinkHandler* handler; + if (NS_OK == aPresContext.GetLinkHandler(&handler)) { + // Resolve url to an absolute url + nsIURL* docURL = nsnull; + nsIDocument* doc = mContent->GetDocument(); + if (nsnull != doc) { + docURL = doc->GetDocumentURL(); + NS_RELEASE(doc); + } + + nsAutoString absURLSpec; + nsresult rv = NS_MakeAbsoluteURL(docURL, aBase, aURLSpec, absURLSpec); + if (nsnull != docURL) { + NS_RELEASE(docURL); + } + + // Now pass on absolute url to the click handler + handler->OnLinkClick(this, absURLSpec, aTargetSpec); + } +} + +nsEventStatus nsHTMLContainerFrame::HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent) +{ + nsEventStatus rv = nsEventStatus_eIgnore; + switch (aEvent->message) { + case NS_MOUSE_LEFT_BUTTON_UP: + if (nsEventStatus_eIgnore == + nsContainerFrame::HandleEvent(aPresContext, aEvent)) { + // If our child didn't take the click then since we are an + // anchor, we take the click. + nsIAtom* tag = mContent->GetTag(); + if (tag == nsHTMLAtoms::a) { + nsAutoString base, href, target; + mContent->GetAttribute("href", href); + mContent->GetAttribute("target", target); + TriggerLink(aPresContext, base, href, target); + rv = nsEventStatus_eConsumeNoDefault; + } + NS_IF_RELEASE(tag); + } + break; + + case NS_MOUSE_RIGHT_BUTTON_DOWN: + // XXX Bring up a contextual menu provided by the application + break; + + default: + rv = nsContainerFrame::HandleEvent(aPresContext, aEvent); + break; + } + return rv; +} + +PRInt32 nsHTMLContainerFrame::GetCursorAt(nsIPresContext& aPresContext, + const nsPoint& aPoint, + nsIFrame** aFrame) +{ + nsStyleMolecule* mol = (nsStyleMolecule*) + mStyleContext->GetData(kStyleMoleculeSID); + if (mol->cursor != NS_STYLE_CURSOR_INHERIT) { + // If this container has a particular cursor, use it, otherwise + // let the child decide. + *aFrame = this; + return (PRInt32) mol->cursor; + } + return nsContainerFrame::GetCursorAt(aPresContext, aPoint, aFrame); +} + +#if 0 +nsIFrame::ReflowStatus +nsHTMLContainerFrame::IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsISpaceManager* aSpaceManager, + nsReflowCommand& aReflowCommand) +{ + // 0. Get to the correct flow block for this frame that applies to + // the effected frame. If the reflow command is not for us or it's + // deleted or changed then "child" is the child being + // effected. Otherwise child is the child before the effected + // content child (or null if the effected child is our first child) + * flow = FindFlowBlock(aReflowCommand, &child); + + // 1. Recover reflow state + State state; + RecoverState(aPresContext, ..., state); + + // 2. Put state into presentation shell cache so child frames can find + // it. + + if (aReflowCommand.GetTarget() == this) { + // Apply reflow command to the flow frame; one of it's immediate + // children has changed state. + ReflowStatus status; + switch (aReflowCommand.GetType()) { + case nsReflowCommand::rcContentAppended: + status = ReflowAppended(aPresContext, aDesiredSize, aMaxSize, + aSpaceManager, state, flow); + break; + case nsReflowCommand::rcContentInserted: + status = ReflowInserted(aPresContext, aDesiredSize, aMaxSize, + aSpaceManager, state, flow); + break; + case nsReflowCommand::rcContentDeleted: + status = ReflowDeleted(aPresContext, aDesiredSize, aMaxSize, + aSpaceManager, state, flow); + break; + case nsReflowCommand::rcContentChanged: + status = ReflowChanged(aPresContext, aDesiredSize, aMaxSize, + aSpaceManager, state, flow); + break; + case nsReflowCommand::rcUserDefined: + switch ( + break; + default: + // Ignore all other reflow commands + status = frComplete; + break; + } + } else { + // Reflow command applies to one of our children. We need to + // figure out which child because it's going to change size most + // likely and we need to be prepared to deal with it. + nsIFrame* kid = nsnull; + status = aReflowCommand.Next(aDesiredSize, aMaxSize, aSpaceManager, kid); + + // Execute the ReflowChanged post-processing code that deals with + // the child frame's size change; next-in-flows, overflow-lists, + // etc. + } + + // 4. Remove state from presentation shell cache + + return status; +} + +nsIFrame::ReflowStatus +nsHTMLContainerFrame::ReflowAppended(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsISpaceManager* aSpaceManager, + nsReflowCommand& aReflowCommand) +{ + // 1. compute state up to but not including new content w/o reflowing + // everything that's already been flowed + + // 2. if this container uses pseudo-frames then 2b, else 2a + + // 2a. start a reflow-unmapped of the new children + + // 2b. reflow-mapped the last-child if it's a pseudo as it might + // pickup the new children; smarter containers can avoid this if + // they can determine that the last-child won't pickup the new + // children up. Once reflowing the last-child is complete then if + // the status is frComplete then and only then try reflowing any + // remaining unmapped children + + // 2c. For inline and column code the result of a reflow mapped + // cannot impact any previously reflowed children. For block this + // is not true so block needs to reconstruct the line and then + // proceed as if the line were being reflowed for the first time + // (skipping over the existing children, of course). The line still + // needs to be flushed out, vertically aligned, etc, which may cause + // it to not fit. + + // 3. we may end up pushing kids to next-in-flow or stopping before + // all children have been mapped because we are out of room. parent + // needs to look at our return status and create a next-in-flow for + // us; the currently implemented reflow-unmapped code will do the + // right thing in that a child that is being appended and reflowed + // will get it's continuations created by us; if we run out of room + // we return an incomplete status to our parent and it does the same + // to us. +} + +// use a custom reflow command when we push or create an overflow list; + +nsIFrame::ReflowStatus +nsHTMLContainerFrame::ReflowInserted(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsISpaceManager* aSpaceManager, + nsReflowCommand& aReflowCommand) +{ + // 1. compute state up to but not including new content w/o reflowing + // everything that's already been flowed + + // 2. Content insertion implies a new child of this container; the + // content inserted may need special attention (see + // ContentAppended). The same rules apply. However, if the + // pseudo-frame doesn't pullup the child then we need to + // ResizeReflow the addition (We cannot go through the + // reflow-unmapped path because the child frame(s) will need to be + // inserted into the list). + + // 2a if reflow results in a push then go through push reflow + // command path else go through deal-with-size-change +} + +nsIFrame::ReflowStatus +nsHTMLContainerFrame::ReflowDeleted(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsISpaceManager* aSpaceManager, + nsReflowCommand& aReflowCommand) +{ + // 1. compute state up to but not including deleted content w/o reflowing + // everything that's already been flowed + + // 2. remove all of the child frames that belong to the deleted + // child; this includes next-in-flows. mark all of our next-in-flows + // that are impacted by this as dirty (or generate another reflow + // command) + + // 3. Run reflow-mapped code starting at the deleted child point; + // return the usual status to the parent. + + + // Generate reflow commands for my next-in-flows if they are + // impacted by deleting my child's next-in-flows +} + +// Meta point about ReflowChanged; we will factor out the change so +// that only stylistic changes that actually require a reflow end up +// at this frame. The style system will differentiate between +// rendering-only changes and reflow changes. + +nsIFrame::ReflowStatus +nsHTMLContainerFrame::ReflowChanged(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsISpaceManager* aSpaceManager, + nsReflowCommand& aReflowCommand) +{ + // 1. compute state up to but not including deleted content w/o reflowing + // everything that's already been flowed + + // 2. delete the frame that corresponds to the changed child (and + // it's next-in-flows, etc.) + + // 3. run the ReflowInserted code on the content +} +#endif diff --git a/mozilla/layout/generic/nsHTMLContainerFrame.h b/mozilla/layout/generic/nsHTMLContainerFrame.h new file mode 100644 index 00000000000..974db84442d --- /dev/null +++ b/mozilla/layout/generic/nsHTMLContainerFrame.h @@ -0,0 +1,89 @@ +/* -*- 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. + */ +#ifndef nsHTMLContainerFrame_h___ +#define nsHTMLContainerFrame_h___ + +#include "nsContainerFrame.h" +class nsString; +struct nsStyleMolecule; + +// Base class for html container frames that provides common +// functionality. +class nsHTMLContainerFrame : public nsContainerFrame { +public: + nsHTMLContainerFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + virtual void Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + virtual nsEventStatus HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent); + + virtual PRInt32 GetCursorAt(nsIPresContext& aPresContext, + const nsPoint& aPoint, + nsIFrame** aFrame); + +#if 0 + virtual ReflowStatus IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsISpaceManager* aSpaceManager, + nsReflowCommand& aReflowCommand); +#endif + +protected: + virtual ~nsHTMLContainerFrame(); + + virtual PRIntn GetSkipSides() const = 0; + + void TriggerLink(nsIPresContext& aPresContext, + const nsString& aBase, + const nsString& aURLSpec, + const nsString& aTargetSpec); + +#if 0 + virtual ReflowStatus ReflowAppended(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsISpaceManager* aSpaceManager, + nsReflowCommand& aReflowCommand); + + virtual ReflowStatus ReflowInserted(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsISpaceManager* aSpaceManager, + nsReflowCommand& aReflowCommand); + + virtual ReflowStatus ReflowDeleted(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsISpaceManager* aSpaceManager, + nsReflowCommand& aReflowCommand); + + virtual ReflowStatus ReflowChanged(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsISpaceManager* aSpaceManager, + nsReflowCommand& aReflowCommand); +#endif +}; + +#endif /* nsHTMLContainerFrame_h___ */ diff --git a/mozilla/layout/generic/nsHTMLParts.h b/mozilla/layout/generic/nsHTMLParts.h new file mode 100644 index 00000000000..4004a300b13 --- /dev/null +++ b/mozilla/layout/generic/nsHTMLParts.h @@ -0,0 +1,134 @@ +/* -*- 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. + */ +#ifndef nsHTMLParts_h___ +#define nsHTMLParts_h___ + +#include "nscore.h" +#include "nsISupports.h" +class nsIArena; +class nsIAtom; +class nsIContent; +class nsIDocument; +class nsIHTMLContent; +class nsIHTMLContentSink; +class nsITextContent; +class nsIURL; +class nsString; + +// XXX naming consistency puhleeze! + +extern nsresult NS_NewHTMLContentSink(nsIHTMLContentSink** aInstancePtrResult, + nsIDocument* aDoc, + nsIURL* aURL); + +// Create an html root part +extern nsresult + NS_NewRootPart(nsIHTMLContent** aInstancePtrResult, + nsIDocument* aDocument); + +// Create an html body part +extern nsresult + NS_NewBodyPart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag); + +// Create a new generic html container (e.g. P, DIV, SPAN, B, I, etc). +// Not used for tables or framesets (see below). +extern nsresult + NS_NewHTMLContainer(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag); +extern nsresult + NS_NewHTMLContainer(nsIHTMLContent** aInstancePtrResult, + nsIArena* aArena, nsIAtom* aTag); + +extern nsresult + NS_NewHTMLBreak(nsIHTMLContent** aInstancePtrResult, nsIAtom* aTag); + +extern nsresult + NS_NewHTMLWordBreak(nsIHTMLContent** aInstancePtrResult, nsIAtom* aTag); + +extern nsresult + NS_NewHTMLSpacer(nsIHTMLContent** aInstancePtrResult, nsIAtom* aTag); + +// Create a new text content object. The memory for the unicode string +// will be allocated from the heap. The object returned will support +// the nsIHTMLContent interface as well as the nsITextContent +// interface +extern nsresult + NS_NewHTMLText(nsIHTMLContent** aInstancePtrResult, + const PRUnichar* us, PRInt32 uslen = 0); +extern nsresult + NS_NewHTMLText(nsIHTMLContent** aInstancePtrResult, + nsIArena* aArena, const PRUnichar* us, PRInt32 uslen = 0); + +// Create a new text content object. The memory for the unicode string +// is allocated by the caller. The caller is responsible for +// deallocating the memory (e.g. use an nsIArena). The object returned +// will support the nsIHTMLContent interface as well as the +// nsITextContent interface +extern nsresult + NS_NewSharedHTMLText(nsIHTMLContent** aInstancePtrResult, + PRUnichar* us, PRInt32 uslen = 0); +extern nsresult + NS_NewSharedHTMLText(nsIHTMLContent** aInstancePtrResult, + nsIArena* aArena, PRUnichar* us, PRInt32 uslen = 0); + +/** Create a new horizontal rule content object (e.g
.) */ +extern nsresult +NS_NewHRulePart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag); + +/** Create a new table content object
*/ +extern nsresult +NS_NewTablePart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag); + +/** Create a new table row group object */ +extern nsresult +NS_NewTableRowGroupPart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag); + +/** Create a new table row content object */ +extern nsresult +NS_NewTableRowPart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag); + +/** Create a new table column group content object */ +extern nsresult +NS_NewTableColGroupPart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag); + +/** Create a new table column content object */ +extern nsresult +NS_NewTableColPart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag); + +/** Create a new table cell content object +
*/ +extern nsresult +NS_NewTableCellPart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag); + +/** Create a new table caption content object
*/ +extern nsresult +NS_NewTableCaptionPart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag); + +extern nsresult +NS_NewHTMLImage(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag); + +#endif /* nsHTMLParts_h___ */ diff --git a/mozilla/layout/generic/nsIFrame.h b/mozilla/layout/generic/nsIFrame.h new file mode 100644 index 00000000000..25db0e7323b --- /dev/null +++ b/mozilla/layout/generic/nsIFrame.h @@ -0,0 +1,385 @@ +/* -*- 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. + */ +#ifndef nsIFrame_h___ +#define nsIFrame_h___ + +#include +#include "nslayout.h" +#include "nsISupports.h" +#include "nsSize.h" +#include "nsGUIEvent.h" + +class nsIContent; +class nsIPresContext; +class nsIPresShell; +class nsIRenderingContext; +class nsISpaceManager; +class nsIStyleContext; +class nsIView; +class nsIWidget; +class nsReflowCommand; + +struct nsStyleStruct; +struct nsGUIEvent; + +struct nsPoint; +struct nsRect; +struct nsReflowMetrics; + +// IID for the nsIFrame interface {12B193D0-9F70-11d1-8500-00A02468FAB6} +#define NS_IFRAME_IID \ +{ 0x12b193d0, 0x9f70, 0x11d1, \ + {0x85, 0x0, 0x0, 0xa0, 0x24, 0x68, 0xfa, 0xb6}} + +/** + * Reflow metrics used to return the frame's desired size and alignment + * information. + * + * @see #ResizeReflow() + * @see #IncrementalReflow() + * @see #GetReflowMetrics() + */ +struct nsReflowMetrics { + nscoord width, height; + nscoord ascent, descent; +}; + +/** + * Constant used to indicate an unconstrained size. + * + * @see #ResizeReflow() + * @see #IncrementalReflow() + */ +#define NS_UNCONSTRAINEDSIZE NS_MAXSIZE + +/** + * A frame in the layout model. This interface is supported by all frame + * objects. + * + * Frames are NOT reference counted. Use the DeleteFrame() member function + * instead + */ +class nsIFrame : private nsISupports +{ +public: + /** + * QueryInterface() defined in nsISupports. This is the only member + * function of nsISupports that is public. + */ + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr) = 0; + + /** + * Deletes this frame and each of its child frames (recursively calls + * DeleteFrame() for each child) + */ + virtual void DeleteFrame() = 0; + + /** + * Get the content object associated with this frame. Adds a reference to + * the content object so the caller must do a release. + * + * @see nsISupports#Release() + */ + virtual nsIContent* GetContent() const = 0; + + /** + * Get/Set the frame's index in parent. + */ + virtual PRInt32 GetIndexInParent() const = 0; + virtual void SetIndexInParent(PRInt32 aIndexInParent) = 0; + + /** + * Get the style context associated with this frame. Note that GetStyleContext() + * adds a reference to the style context so the caller must do a release. + * + * @see #nsISupports#Release() + */ + virtual nsIStyleContext* GetStyleContext(nsIPresContext* aContext) = 0; + virtual void SetStyleContext(nsIStyleContext* aContext) = 0; + + + /** + * + * Get the style data associated with this frame + * + * + */ + virtual nsStyleStruct* GetStyleData(const nsIID& aSID) = 0; + + /** + * Accessor functions for geometric and content parent. + */ + virtual nsIFrame* GetContentParent() const = 0; + virtual void SetContentParent(const nsIFrame* aParent) = 0; + virtual nsIFrame* GetGeometricParent() const = 0; + virtual void SetGeometricParent(const nsIFrame* aParent) = 0; + + /** + * Bounding rect of the frame. The values are in twips, and the origin is + * relative to the upper-left of the geometric parent. The size includes the + * content area, borders, and padding. + */ + virtual nsRect GetRect() const = 0; + virtual void GetRect(nsRect& aRect) const = 0; + virtual void GetOrigin(nsPoint& aPoint) const = 0; + virtual nscoord GetWidth() const = 0; + virtual nscoord GetHeight() const = 0; + virtual void SetRect(const nsRect& aRect) = 0; + virtual void MoveTo(nscoord aX, nscoord aY) = 0; + virtual void SizeTo(nscoord aWidth, nscoord aHeight) = 0; + + /** + * Painting + */ + virtual void Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) = 0; + + /** + * Handle an event. + */ + virtual nsEventStatus HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent) = 0; + + /** + * Get the cursor for a given point in the frame tree. The + * call returns the desired cursor (or NS_STYLE_CURSOR_INHERIT if + * no cursor is wanted). In addition, if a cursor is desired + * then *aFrame is set to the frame that wants the cursor. + */ + virtual PRInt32 GetCursorAt(nsIPresContext& aPresContext, + const nsPoint& aPoint, + nsIFrame** aFrame) = 0; + + /** + * Child frame enumeration + */ + virtual PRInt32 ChildCount() const = 0; + virtual nsIFrame* ChildAt(PRInt32 aIndex) const = 0; + virtual PRInt32 IndexOf(const nsIFrame* aChild) const = 0; + virtual nsIFrame* FirstChild() const = 0; + virtual nsIFrame* NextChild(const nsIFrame* aChild) const = 0; + virtual nsIFrame* PrevChild(const nsIFrame* aChild) const = 0; + virtual nsIFrame* LastChild() const = 0; + + /** + * Reflow status returned by the reflow methods + * + * @see #ResizeReflow() + * @see #IncrementalReflow() + */ + enum ReflowStatus {frComplete, frNotComplete}; + + /** + * Resize reflow. The frame is given a maximum size and asked for its desired + * size. This is the frame's opportunity to reflow its children. + * + * @param aDesiredSize out parameter where you should return the + * desired size and ascent/descent info. You should include any + * space you want for border/padding in the desired size you return. + * @param aMaxSize the available space in which to lay out. Each dimension + * can either be constrained or unconstrained (a value of + * NS_UNCONSTRAINEDSIZE). If constrained you should choose a value that's + * less than or equal to the constrained size. If unconstrained you can + * choose as large a value as you like. + * + * It's okay to return a desired size that exceeds the max size if that's + * the smallest you can be, i.e. it's your minimum size. + * + * @param aMaxElementSize an optional parameter for returning your maximum + * element size. If may be null in which case you don't have to compute + * a maximum element size. The maximum element size must be less than or + * equal to your desired size. + */ + virtual ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) = 0; + + /** + * Post-processing reflow method invoked when justification is enabled. + * This is always called after ResizeReflow/IncrementalReflow. + * + * @param aAvailableSpace The amount of available space that the frame + * should distribute internally. + */ + virtual void JustifyReflow(nsIPresContext* aPresContext, + nscoord aAvailableSpace) = 0; + + /** + * Incremental reflow. The reflow command contains information about the + * type of change. The frame is given a maximum size and asked for its + * desired size. + * + * @param aDesiredSize out parameter where you should return + * the desired size and ascent/descent info. You should + * include any space you want for border/padding in the + * desired size you return. + * + * @param aMaxSize the available space in which to lay out. Each + * dimension can either be constrained or unconstrained (a + * value of NS_UNCONSTRAINEDSIZE). If constrained you + * should choose a value that's less than or equal to the + * constrained size. If unconstrained you can choose as + * large a value as you like. It's okay to return a + * desired size that exceeds the max size if that's the + * smallest you can be, i.e. it's your minimum size. + * + * @see nsReflowCommand#GetTarget() + * @see nsReflowCommand#GetType() + */ + virtual ReflowStatus IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand) = 0; + + /** + * This call is invoked when content is appended to the content + * tree. The container frame that maps that content is asked to deal + * with the appended content by creating new frames and updating the + * index-in-parent values for it's affected children. In addition, + * the call must generate reflow commands that will incrementally + * reflow and repair the damaged portion of the frame tree. + */ + virtual void ContentAppended(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer) = 0; + + /** + * This call is invoked when content is inserted in the content + * tree. The container frame that maps that content is asked to deal + * with the inserted content by creating new frames and updating the + * index-in-parent values for it's affected children. In addition, + * the call must generate reflow commands that will incrementally + * reflow and repair the damaged portion of the frame tree. + * + * @param aIndexInParent the index in the content container where + * the new content was inserted. + */ + virtual void ContentInserted(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInParent) = 0; + + /** + * This call is invoked when content is replaced in the content + * tree. The container frame that maps that content is asked to deal + * with the replaced content by deleting old frames and then + * creating new frames and updating the index-in-parent values for + * it's affected children. In addition, the call must generate + * reflow commands that will incrementally reflow and repair the + * damaged portion of the frame tree. + * + * @param aIndexInParent the index in the content container where + * the new content was inserted. */ + virtual void ContentReplaced(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInParent) = 0; + + /** + * This call is invoked when content is deleted from the content + * tree. The container frame that maps that content is asked to deal + * with the deleted content by deleting frames and updating the + * index-in-parent values for it's affected children. In addition, + * the call must generate reflow commands that will incrementally + * reflow and repair the damaged portion of the frame tree. + * + * @param aIndexInParent the index in the content container where + * the new content was deleted. + */ + virtual void ContentDeleted(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInParent) = 0; + + /** + * Return the reflow metrics for this frame. If the frame is a + * container then the values for ascent and descent are computed + * across the the various children in the appropriate manner + * (e.g. for a line frame the ascent value would be the maximum + * ascent of the line's children). Note that the metrics returned + * apply to the frame as it exists at the time of the call. + */ + virtual void GetReflowMetrics(nsIPresContext* aPresContext, + nsReflowMetrics& aMetrics) = 0; + + /** + * Flow member functions. CreateContinuingFrame() is responsible for appending + * the continuing frame to the flow. + */ + virtual PRBool IsSplittable() const = 0; + virtual nsIFrame* CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent) = 0; + virtual nsIFrame* GetPrevInFlow() const = 0; + virtual void SetPrevInFlow(nsIFrame*) = 0; + virtual nsIFrame* GetNextInFlow() const = 0; + virtual void SetNextInFlow(nsIFrame*) = 0; + + virtual void AppendToFlow(nsIFrame* aAfterFrame) = 0; + virtual void PrependToFlow(nsIFrame* aBeforeFrame) = 0; + virtual void RemoveFromFlow() = 0; + virtual void BreakFromPrevFlow() = 0; + virtual void BreakFromNextFlow() = 0; + + /** + * Accessor functions to get/set the associated view object + */ + virtual nsIView* GetView() const = 0; // may be null + virtual void SetView(nsIView* aView) = 0; + + /** + * Find the first geometric parent that has a view + */ + virtual nsIFrame* GetParentWithView() const = 0; + + /** + * Returns the offset from this frame to the closest geometric parent that + * has a view. Also returns the containing view or null in case of error + */ + virtual nsIView* GetOffsetFromView(nsPoint& aOffset) const = 0; + + /** + * Returns the window that contains this frame. If this frame has a + * view and the view has a window, then this frames window is + * returned, otherwise this frame's geometric parent is checked + * recursively upwards. + */ + virtual nsIWidget* GetWindow() const = 0; + + /** + * Sibling pointer used to link together frames + */ + virtual nsIFrame* GetNextSibling() const = 0; + virtual void SetNextSibling(nsIFrame* aNextSibling) = 0; + + // Debugging + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const= 0; + virtual void ListTag(FILE* out = stdout) const = 0; + virtual void VerifyTree() const = 0; + + // Show frame borders when rendering + static NS_LAYOUT void ShowFrameBorders(PRBool aEnable); + static NS_LAYOUT PRBool GetShowFrameBorders(); +}; + +#endif /* nsIFrame_h___ */ diff --git a/mozilla/layout/generic/nsImageMap.cpp b/mozilla/layout/generic/nsImageMap.cpp new file mode 100644 index 00000000000..3bca969fa62 --- /dev/null +++ b/mozilla/layout/generic/nsImageMap.cpp @@ -0,0 +1,710 @@ +/* -*- 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 "nsIImageMap.h" +#include "nsString.h" +#include "nsVoidArray.h" +#include "nsCoord.h" +#include "nsIRenderingContext.h" +#include "nsIPresContext.h" +#include "nsIURL.h" + +#undef SCALE +#define SCALE(a,b) nscoord((a) * (b)) + +class Area { +public: + Area(const nsString& aBaseURL, const nsString& aHREF, + const nsString& aTarget, const nsString& aAltText, + PRBool aSuppress); + virtual ~Area(); + + void ParseCoords(const nsString& aSpec); + + virtual PRBool IsInside(nscoord x, nscoord y) = 0; + virtual void Draw(nsIPresContext& aCX, + nsIRenderingContext& aRC) = 0; + virtual void GetShapeName(nsString& aResult) = 0; + + void ToHTML(nsString& aResult); + + const nsString& GetBase() const { return mBase; } + const nsString& GetHREF() const { return mHREF; } + const nsString& GetTarget() const { return mTarget; } + const nsString& GetAltText() const { return mAltText; } + PRBool GetSuppress() const { return mSuppressFeedback; } + + nsString mBase; + nsString mHREF; + nsString mTarget; + nsString mAltText; + nscoord* mCoords; + PRInt32 mNumCoords; + PRBool mSuppressFeedback; +}; + +Area::Area(const nsString& aBaseURL, const nsString& aHREF, + const nsString& aTarget, const nsString& aAltText, + PRBool aSuppress) + : mBase(aBaseURL), mHREF(aHREF), mTarget(aTarget), mAltText(aAltText), + mSuppressFeedback(aSuppress) +{ + mCoords = nsnull; + mNumCoords = 0; +} + +Area::~Area() +{ + delete [] mCoords; +} + +// XXX move into nsCRT +#define XP_IS_SPACE(_ch) \ + (((_ch) == ' ') || ((_ch) == '\t') || ((_ch) == '\r') || ((_ch) == '\n')) + +#include +#define XP_ATOI(_s) ::atoi(_s) + +// XXX straight copy from laymap.c +static nscoord* lo_parse_coord_list(char *str, PRInt32* value_cnt) +{ + char *tptr; + char *n_str; + PRInt32 i, cnt; + PRInt32 *value_list; + + /* + * Nothing in an empty list + */ + *value_cnt = 0; + if ((str == NULL)||(*str == '\0')) + { + return((PRInt32 *)NULL); + } + + /* + * Skip beginning whitespace, all whitespace is empty list. + */ + n_str = str; + while (XP_IS_SPACE(*n_str)) + { + n_str++; + } + if (*n_str == '\0') + { + return((PRInt32 *)NULL); + } + + /* + * Make a pass where any two numbers separated by just whitespace + * are given a comma separator. Count entries while passing. + */ + cnt = 0; + while (*n_str != '\0') + { + PRBool has_comma; + + /* + * Skip to a separator + */ + tptr = n_str; + while ((!XP_IS_SPACE(*tptr))&&(*tptr != ',')&&(*tptr != '\0')) + { + tptr++; + } + n_str = tptr; + + /* + * If no more entries, break out here + */ + if (*n_str == '\0') + { + break; + } + + /* + * Skip to the end of the separator, noting if we have a + * comma. + */ + has_comma = PR_FALSE; + while ((XP_IS_SPACE(*tptr))||(*tptr == ',')) + { + if (*tptr == ',') + { + if (has_comma == PR_FALSE) + { + has_comma = PR_TRUE; + } + else + { + break; + } + } + tptr++; + } + /* + * If this was trailing whitespace we skipped, we are done. + */ + if ((*tptr == '\0')&&(has_comma == PR_FALSE)) + { + break; + } + /* + * Else if the separator is all whitespace, and this is not the + * end of the string, add a comma to the separator. + */ + else if (has_comma == PR_FALSE) + { + *n_str = ','; + } + + /* + * count the entry skipped. + */ + cnt++; + + n_str = tptr; + } + /* + * count the last entry in the list. + */ + cnt++; + + *value_cnt = cnt; + + /* + * Allocate space for the coordinate array. + */ + value_list = new nscoord[cnt]; + if (value_list == NULL) + { + return((PRInt32 *)NULL); + } + + /* + * Second pass to copy integer values into list. + */ + tptr = str; + for (i=0; i'); +} + +//---------------------------------------------------------------------- + +class DefaultArea : public Area { +public: + DefaultArea(const nsString& aBaseURL, const nsString& aHREF, + const nsString& aTarget, const nsString& aAltText, + PRBool aSuppress); + ~DefaultArea(); + + virtual PRBool IsInside(nscoord x, nscoord y); + virtual void Draw(nsIPresContext& aCX, + nsIRenderingContext& aRC); + virtual void GetShapeName(nsString& aResult); +}; + +DefaultArea::DefaultArea(const nsString& aBaseURL, const nsString& aHREF, + const nsString& aTarget, const nsString& aAltText, + PRBool aSuppress) + : Area(aBaseURL, aHREF, aTarget, aAltText, aSuppress) +{ +} + +DefaultArea::~DefaultArea() +{ +} + +PRBool DefaultArea::IsInside(nscoord x, nscoord y) +{ + return PR_TRUE; +} + +void DefaultArea::Draw(nsIPresContext& aCX, nsIRenderingContext& aRC) +{ +} + +void DefaultArea::GetShapeName(nsString& aResult) +{ + aResult.Append("default"); +} + +//---------------------------------------------------------------------- + +class RectArea : public Area { +public: + RectArea(const nsString& aBaseURL, const nsString& aHREF, + const nsString& aTarget, const nsString& aAltText, + PRBool aSuppress); + ~RectArea(); + + virtual PRBool IsInside(nscoord x, nscoord y); + virtual void Draw(nsIPresContext& aCX, + nsIRenderingContext& aRC); + virtual void GetShapeName(nsString& aResult); +}; + +RectArea::RectArea(const nsString& aBaseURL, const nsString& aHREF, + const nsString& aTarget, const nsString& aAltText, + PRBool aSuppress) + : Area(aBaseURL, aHREF, aTarget, aAltText, aSuppress) +{ +} + +RectArea::~RectArea() +{ +} + +PRBool RectArea::IsInside(nscoord x, nscoord y) +{ + if (mNumCoords >= 4) { // Note: > is for nav compatabilty + nscoord x1 = mCoords[0]; + nscoord y1 = mCoords[1]; + nscoord x2 = mCoords[2]; + nscoord y2 = mCoords[3]; + if ((x1 > x2)|| (y1 > y2)) { + // Can't be inside a screwed up rect + return PR_FALSE; + } + if ((x >= x1) && (x <= x2) && (y >= y1) && (y <= y2)) { + return PR_TRUE; + } + } + return PR_FALSE; +} + +void RectArea::Draw(nsIPresContext& aCX, nsIRenderingContext& aRC) +{ + if (mNumCoords >= 4) { + float p2t = aCX.GetPixelsToTwips(); + nscoord x1 = SCALE(p2t, mCoords[0]); + nscoord y1 = SCALE(p2t, mCoords[1]); + nscoord x2 = SCALE(p2t, mCoords[2]); + nscoord y2 = SCALE(p2t, mCoords[3]); + if ((x1 > x2)|| (y1 > y2)) { + return; + } + aRC.DrawRect(x1, y1, x2 - x1, y2 - y1); + } +} + +void RectArea::GetShapeName(nsString& aResult) +{ + aResult.Append("rect"); +} + +//---------------------------------------------------------------------- + +class PolyArea : public Area { +public: + PolyArea(const nsString& aBaseURL, const nsString& aHREF, + const nsString& aTarget, const nsString& aAltText, + PRBool aSuppress); + ~PolyArea(); + + virtual PRBool IsInside(nscoord x, nscoord y); + virtual void Draw(nsIPresContext& aCX, + nsIRenderingContext& aRC); + virtual void GetShapeName(nsString& aResult); +}; + +PolyArea::PolyArea(const nsString& aBaseURL, const nsString& aHREF, + const nsString& aTarget, const nsString& aAltText, + PRBool aSuppress) + : Area(aBaseURL, aHREF, aTarget, aAltText, aSuppress) +{ +} + +PolyArea::~PolyArea() +{ +} + +PRBool PolyArea::IsInside(nscoord x, nscoord y) +{ + if (mNumCoords >= 6) { + PRInt32 intersects = 0; + nscoord wherex = x; + nscoord wherey = y; + PRInt32 totalv = mNumCoords / 2; + PRInt32 totalc = totalv * 2; + nscoord xval = mCoords[totalc - 2]; + nscoord yval = mCoords[totalc - 1]; + PRInt32 end = totalc; + PRInt32 pointer = 1; + + if ((yval >= wherey) != (mCoords[pointer] >= wherey)) + if ((xval >= wherex) == (mCoords[0] >= wherex)) + intersects += (xval >= wherex) ? 1 : 0; + else + intersects += ((xval - (yval - wherey) * + (mCoords[0] - xval) / + (mCoords[pointer] - yval)) >= wherex) ? 1 : 0; + + // XXX I wonder what this is doing; this is a translation of ptinpoly.c + while (pointer < end) { + yval = mCoords[pointer]; + pointer += 2; + if (yval >= wherey) { + while((pointer < end) && (mCoords[pointer] >= wherey)) + pointer+=2; + if (pointer >= end) + break; + if ((mCoords[pointer-3] >= wherex) == + (mCoords[pointer-1] >= wherex)) { + intersects += (mCoords[pointer-3] >= wherex) ? 1 : 0; + } else { + intersects += + ((mCoords[pointer-3] - (mCoords[pointer-2] - wherey) * + (mCoords[pointer-1] - mCoords[pointer-3]) / + (mCoords[pointer] - mCoords[pointer - 2])) >= wherex) ? 1:0; + } + } else { + while((pointer < end) && (mCoords[pointer] < wherey)) + pointer+=2; + if (pointer >= end) + break; + if ((mCoords[pointer-3] >= wherex) == + (mCoords[pointer-1] >= wherex)) { + intersects += (mCoords[pointer-3] >= wherex) ? 1:0; + } else { + intersects += + ((mCoords[pointer-3] - (mCoords[pointer-2] - wherey) * + (mCoords[pointer-1] - mCoords[pointer-3]) / + (mCoords[pointer] - mCoords[pointer - 2])) >= wherex) ? 1:0; + } + } + } + if ((intersects & 1) != 0) { + return PR_TRUE; + } + } + return PR_FALSE; +} + +void PolyArea::Draw(nsIPresContext& aCX, nsIRenderingContext& aRC) +{ + if (mNumCoords >= 6) { + float p2t = aCX.GetPixelsToTwips(); + nscoord x0 = SCALE(p2t, mCoords[0]); + nscoord y0 = SCALE(p2t, mCoords[1]); + for (PRInt32 i = 2; i < mNumCoords; i += 2) { + nscoord x1 = SCALE(p2t, mCoords[i]); + nscoord y1 = SCALE(p2t, mCoords[i+1]); + aRC.DrawLine(x0, y0, x1, y1); + x0 = x1; + y0 = y1; + } + aRC.DrawLine(x0, y0, mCoords[0], mCoords[1]); + } +} + +void PolyArea::GetShapeName(nsString& aResult) +{ + aResult.Append("polygon"); +} + +//---------------------------------------------------------------------- + +class CircleArea : public Area { +public: + CircleArea(const nsString& aBaseURL, const nsString& aHREF, + const nsString& aTarget, const nsString& aAltText, + PRBool aSuppress); + ~CircleArea(); + + virtual PRBool IsInside(nscoord x, nscoord y); + virtual void Draw(nsIPresContext& aCX, + nsIRenderingContext& aRC); + virtual void GetShapeName(nsString& aResult); +}; + +CircleArea::CircleArea(const nsString& aBaseURL, const nsString& aHREF, + const nsString& aTarget, const nsString& aAltText, + PRBool aSuppress) + : Area(aBaseURL, aHREF, aTarget, aAltText, aSuppress) +{ +} + +CircleArea::~CircleArea() +{ +} + +PRBool CircleArea::IsInside(nscoord x, nscoord y) +{ + // Note: > is for nav compatabilty + if (mNumCoords >= 3) { + nscoord x1 = mCoords[0]; + nscoord y1 = mCoords[1]; + nscoord radius = mCoords[2]; + if (radius < 0) { + return PR_FALSE; + } + nscoord dx = x1 - x; + nscoord dy = y1 - y; + nscoord dist = (dx * dx) + (dy * dy); + if (dist <= (radius * radius)) { + return PR_TRUE; + } + } + return PR_FALSE; +} + +void CircleArea::Draw(nsIPresContext& aCX, nsIRenderingContext& aRC) +{ + if (mNumCoords >= 3) { + float p2t = aCX.GetPixelsToTwips(); + nscoord x1 = SCALE(p2t, mCoords[0]); + nscoord y1 = SCALE(p2t, mCoords[1]); + nscoord radius = SCALE(p2t, mCoords[2]); + if (radius < 0) { + return; + } + nscoord x = x1 - radius / 2; + nscoord y = y1 - radius / 2; + nscoord w = 2 * radius; + aRC.DrawEllipse(x, y, w, w); + } +} + +void CircleArea::GetShapeName(nsString& aResult) +{ + aResult.Append("circle"); +} + +//---------------------------------------------------------------------- + +static NS_DEFINE_IID(kIImageMapIID, NS_IIMAGEMAP_IID); + +class ImageMapImpl : public nsIImageMap { +public: + ImageMapImpl(nsIAtom* aTag); + ~ImageMapImpl(); + + NS_DECL_ISUPPORTS + + NS_IMETHOD SetName(const nsString& aMapName); + + NS_IMETHOD GetName(nsString& aResult); + + NS_IMETHOD AddArea(const nsString& aBaseURL, + const nsString& aShape, + const nsString& aCoords, + const nsString& aHREF, + const nsString& aTarget, + const nsString& aAltText, + PRBool aSuppress); + + NS_IMETHOD IsInside(nscoord aX, nscoord aY, + nsIURL* aDocURL, + nsString& aAbsURL, + nsString& aTarget, + nsString& aAltText, + PRBool* aSuppress); + + NS_IMETHOD IsInside(nscoord aX, nscoord aY); + + NS_IMETHOD Draw(nsIPresContext& aCX, nsIRenderingContext& aRC); + + nsString mName; + nsIAtom* mTag; + nsVoidArray mAreas; +}; + +ImageMapImpl::ImageMapImpl(nsIAtom* aTag) +{ + mTag = aTag; + NS_IF_ADDREF(aTag); +} + +ImageMapImpl::~ImageMapImpl() +{ + NS_IF_RELEASE(mTag); + PRInt32 i, n = mAreas.Count(); + for (i = 0; i < n; i++) { + Area* area = (Area*) mAreas.ElementAt(i); + delete area; + } +} + +NS_IMPL_ISUPPORTS(ImageMapImpl, kIImageMapIID); + +NS_IMETHODIMP ImageMapImpl::SetName(const nsString& aMapName) +{ + mName = aMapName; + return NS_OK; +} + +NS_IMETHODIMP ImageMapImpl::GetName(nsString& aResult) +{ + aResult = mName; + return NS_OK; +} + +NS_IMETHODIMP ImageMapImpl::AddArea(const nsString& aBaseURL, + const nsString& aShape, + const nsString& aCoords, + const nsString& aHREF, + const nsString& aTarget, + const nsString& aAltText, + PRBool aSuppress) +{ + Area* area; + if ((0 == aShape.Length()) || aShape.EqualsIgnoreCase("rect")) { + area = new RectArea(aBaseURL, aHREF, aTarget, aAltText, aSuppress); + } else if (aShape.EqualsIgnoreCase("poly") || + aShape.EqualsIgnoreCase("polygon")) { + area = new PolyArea(aBaseURL, aHREF, aTarget, aAltText, aSuppress); + } else if (aShape.EqualsIgnoreCase("circle")) { + area = new CircleArea(aBaseURL, aHREF, aTarget, aAltText, aSuppress); + } + else { + area = new DefaultArea(aBaseURL, aHREF, aTarget, aAltText, aSuppress); + } + area->ParseCoords(aCoords); + mAreas.AppendElement(area); + return NS_OK; +} + +NS_IMETHODIMP ImageMapImpl::IsInside(nscoord aX, nscoord aY, + nsIURL* aDocURL, + nsString& aAbsURL, + nsString& aTarget, + nsString& aAltText, + PRBool* aSuppress) +{ + PRInt32 i, n = mAreas.Count(); + for (i = 0; i < n; i++) { + Area* area = (Area*) mAreas.ElementAt(i); + if (area->IsInside(aX, aY)) { + NS_MakeAbsoluteURL(aDocURL, area->mBase, area->mHREF, aAbsURL); + aTarget = area->mTarget; + aAltText = area->mAltText; + *aSuppress = area->mSuppressFeedback; + return NS_OK; + } + } + return NS_NOT_INSIDE; +} + +NS_IMETHODIMP ImageMapImpl::IsInside(nscoord aX, nscoord aY) +{ + PRInt32 i, n = mAreas.Count(); + for (i = 0; i < n; i++) { + Area* area = (Area*) mAreas.ElementAt(i); + if (area->IsInside(aX, aY)) { + return NS_OK; + } + } + return NS_NOT_INSIDE; +} + +NS_IMETHODIMP ImageMapImpl::Draw(nsIPresContext& aCX, nsIRenderingContext& aRC) +{ + PRInt32 i, n = mAreas.Count(); + for (i = 0; i < n; i++) { + Area* area = (Area*) mAreas.ElementAt(i); + area->Draw(aCX, aRC); + } + return NS_OK; +} + +NS_HTML nsresult NS_NewImageMap(nsIImageMap** aInstancePtrResult, + nsIAtom* aTag) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + ImageMapImpl* it = new ImageMapImpl(aTag); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIImageMapIID, (void**) aInstancePtrResult); +} diff --git a/mozilla/layout/generic/nsInlineFrame.cpp b/mozilla/layout/generic/nsInlineFrame.cpp new file mode 100644 index 00000000000..c795cf6122e --- /dev/null +++ b/mozilla/layout/generic/nsInlineFrame.cpp @@ -0,0 +1,1030 @@ +/* -*- 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 "nsInlineFrame.h" +#include "nsSize.h" +#include "nsIContent.h" +#include "nsIContentDelegate.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsIPresContext.h" +#include "nsIPresShell.h" +#include "nsCSSLayout.h" +#include "nsPlaceholderFrame.h" +#include "nsReflowCommand.h" + +// XXX To Do: +// 2. horizontal child margins +// 3. borders/padding and splitting +// 4. child relative positioning +// 5. absolutely positioned children +// 6. direction support +// 7. CSS line-height property + +#define DEFAULT_ASCENT_LEN 10 +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); +static NS_DEFINE_IID(kStyleFontSID, NS_STYLEFONT_SID); + +class nsInlineState +{ +public: + nsStyleFont* font; // style font + nsStyleMolecule* mol; // style molecule + nsSize availSize; // available space in which to reflow (starts as max size minus insets) + nsSize* maxElementSize; // maximum element size (may be null) + nscoord x; // running x-offset (starts at left inner edge) + const nscoord y; // y-offset (top inner edge) + nscoord maxAscent; // max child ascent + nscoord maxDescent; // max child descent + nscoord* ascents; // ascent information for each child + PRBool unconstrainedWidth; + PRBool unconstrainedHeight; + + // Constructor + nsInlineState(nsStyleFont* aStyleFont, + nsStyleMolecule* aStyleMolecule, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) + : x(aStyleMolecule->borderPadding.left), // determined by inner edge + y(aStyleMolecule->borderPadding.top) // determined by inner edge + { + font = aStyleFont; + mol = aStyleMolecule; + + unconstrainedWidth = PRBool(aMaxSize.width == NS_UNCONSTRAINEDSIZE); + unconstrainedHeight = PRBool(aMaxSize.height == NS_UNCONSTRAINEDSIZE); + + // If we're constrained adjust the available size so it excludes space + // needed for border/padding + availSize.width = aMaxSize.width; + if (PR_FALSE == unconstrainedWidth) { + availSize.width -= mol->borderPadding.left + mol->borderPadding.right; + } + availSize.height = aMaxSize.height; + if (PR_FALSE == unconstrainedHeight) { + availSize.height -= mol->borderPadding.top + mol->borderPadding.bottom; + } + + // Initialize max element size + maxElementSize = aMaxElementSize; + if (nsnull != maxElementSize) { + maxElementSize->SizeTo(0, 0); + } + + ascents = ascentBuf; + maxAscent = 0; + maxDescent = 0; + } + + void SetNumAscents(PRIntn aNumAscents) { + // We keep around ascent information so that we can vertically align + // children after we figure out how many children fit. + if (aNumAscents > DEFAULT_ASCENT_LEN) { + ascents = new nscoord[aNumAscents]; + } + } + + // Destructor + ~nsInlineState() { + if (ascents != ascentBuf) { + delete ascents; + } + } + +private: + nscoord ascentBuf[DEFAULT_ASCENT_LEN]; +}; + +///////////////////////////////////////////////////////////////////////////// +// + +nsresult nsInlineFrame::NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIFrame* it = new nsInlineFrame(aContent, aIndexInParent, aParent); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aInstancePtrResult = it; + return NS_OK; +} + +nsInlineFrame::nsInlineFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) + : nsHTMLContainerFrame(aContent, aIndexInParent, aParent) +{ + NS_PRECONDITION(!IsPseudoFrame(), "can not be a pseudo frame"); +} + +nsInlineFrame::~nsInlineFrame() +{ +} + +void nsInlineFrame::PlaceChild(nsIFrame* aChild, + PRInt32 aIndex, + nsInlineState& aState, + const nsReflowMetrics& aChildSize, + const nsSize* aChildMaxElementSize) +{ + // Set the child's rect + aChild->SetRect(nsRect(aState.x, aState.y, aChildSize.width, aChildSize.height)); + + // Adjust the running x-offset + aState.x += aChildSize.width; + + // Update the array of ascents and the max ascent and descent + aState.ascents[aIndex] = aChildSize.ascent; + if (aChildSize.ascent > aState.maxAscent) { + aState.maxAscent = aChildSize.ascent; + } + if (aChildSize.descent > aState.maxDescent) { + aState.maxDescent = aChildSize.descent; + } + + // If we're constrained then update the available width + if (!aState.unconstrainedWidth) { + aState.availSize.width -= aChildSize.width; + } + + // Update the maximum element size + if (nsnull != aChildMaxElementSize) { + if (aChildMaxElementSize->width > aState.maxElementSize->width) { + aState.maxElementSize->width = aChildMaxElementSize->width; + } + if (aChildMaxElementSize->height > aState.maxElementSize->height) { + aState.maxElementSize->height = aChildMaxElementSize->height; + } + } +} + +/** + * Reflow the frames we've already created + * + * @param aPresContext presentation context to use + * @param aState current inline state + * @return true if we successfully reflowed all the mapped children and false + * otherwise, e.g. we pushed children to the next in flow + */ +PRBool nsInlineFrame::ReflowMappedChildren(nsIPresContext* aPresContext, + nsInlineState& aState) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif + NS_PRECONDITION(nsnull != mFirstChild, "no children"); + + PRInt32 childCount = 0; + nsIFrame* prevKidFrame = nsnull; + + // Remember our original mLastContentIsComplete so that if we end up + // having to push children, we have the correct value to hand to + // PushChildren. + PRBool originalLastContentIsComplete = mLastContentIsComplete; + + nsSize kidMaxElementSize; + nsSize* pKidMaxElementSize = (nsnull != aState.maxElementSize) ? &kidMaxElementSize : nsnull; + PRBool result = PR_TRUE; + + for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; ) { + nsReflowMetrics kidSize; + ReflowStatus status; + + // Reflow the child into the available space + status = ReflowChild(kidFrame, aPresContext, kidSize, aState.availSize, + pKidMaxElementSize); + + // Did the child fit? + if ((kidSize.width > aState.availSize.width) && (kidFrame != mFirstChild)) { + // The child is too wide to fit in the available space, and it's + // not our first child + + // Since we are giving the next-in-flow our last child, we + // give it our original mLastContentIsComplete too (in case we + // are pushing into an empty next-in-flow) + PushChildren(kidFrame, prevKidFrame, originalLastContentIsComplete); + SetLastContentOffset(prevKidFrame); + + result = PR_FALSE; + break; + } + + // Place and size the child. We'll deal with vertical alignment when + // we're all done + PlaceChild(kidFrame, childCount, aState, kidSize, pKidMaxElementSize); + childCount++; + + // Remember where we just were in case we end up pushing children + prevKidFrame = kidFrame; + + // Is the child complete? + mLastContentIsComplete = PRBool(status == frComplete); + if (frNotComplete == status) { + // No, the child isn't complete + nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); + PRBool lastContentIsComplete = mLastContentIsComplete; + if (nsnull == kidNextInFlow) { + // The child doesn't have a next-in-flow so create a continuing + // frame. This hooks the child into the flow + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aPresContext, this); + NS_ASSERTION(nsnull != continuingFrame, "frame creation failed"); + + // Add the continuing frame to the sibling list + nsIFrame* nextSib = kidFrame->GetNextSibling(); + continuingFrame->SetNextSibling(nextSib); + kidFrame->SetNextSibling(continuingFrame); + if (nsnull == nextSib) { + // Assume that the continuation frame we just created is + // complete, for now. It will get reflowed by our + // next-in-flow (we are going to push it now) + lastContentIsComplete = PR_TRUE; + } + } + + // We've used up all of our available space so push the remaining + // children to the next-in-flow + nsIFrame* nextSibling = kidFrame->GetNextSibling(); + if (nsnull != nextSibling) { + PushChildren(nextSibling, kidFrame, lastContentIsComplete); + SetLastContentOffset(prevKidFrame); + } + result = PR_FALSE; + break; + } + + // Get the next child frame + kidFrame = kidFrame->GetNextSibling(); + + // XXX talk with troy about checking for available space here + } + + // Update the child count member data + mChildCount = childCount; + NS_POSTCONDITION(LengthOf(mFirstChild) == mChildCount, "bad child count"); + NS_POSTCONDITION(LastChild()->GetIndexInParent() == mLastContentOffset, "bad last content offset"); +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif + return result; +} + +/** + * Try and pull-up frames from our next-in-flow + * + * @param aPresContext presentation context to use + * @param aState current inline state + * @return true if we successfully pulled-up all the children and false + * otherwise, e.g. child didn't fit + */ +PRBool nsInlineFrame::PullUpChildren(nsIPresContext* aPresContext, + nsInlineState& aState) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif + nsInlineFrame* nextInFlow = (nsInlineFrame*)mNextInFlow; + nsSize kidMaxElementSize; + nsSize* pKidMaxElementSize = (nsnull != aState.maxElementSize) ? &kidMaxElementSize : nsnull; +#ifdef NS_DEBUG + PRInt32 kidIndex = NextChildOffset(); +#endif + nsIFrame* prevKidFrame = LastChild(); + + // This will hold the prevKidFrame's mLastContentIsComplete + // status. If we have to push the frame that follows prevKidFrame + // then this will become our mLastContentIsComplete state. Since + // prevKidFrame is initially our last frame, it's completion status + // is our mLastContentIsComplete value. + PRBool prevLastContentIsComplete = mLastContentIsComplete; + + PRBool result = PR_TRUE; + + while (nsnull != nextInFlow) { + nsReflowMetrics kidSize; + ReflowStatus status; + + // Get the next child + nsIFrame* kidFrame = nextInFlow->mFirstChild; + + // Any more child frames? + if (nsnull == kidFrame) { + // No. Any frames on its overflow list? + if (nsnull != nextInFlow->mOverflowList) { + // Move the overflow list to become the child list + NS_ABORT(); + nextInFlow->AppendChildren(nextInFlow->mOverflowList); + nextInFlow->mOverflowList = nsnull; + kidFrame = nextInFlow->mFirstChild; + } else { + // We've pulled up all the children, so move to the next-in-flow. + nextInFlow = (nsInlineFrame*)nextInFlow->GetNextInFlow(); + continue; + } + } + + // See if the child fits in the available space. If it fits or + // it's splittable then reflow it. The reason we can't just move + // it is that we still need ascent/descent information + if ((kidFrame->GetWidth() > aState.availSize.width) && + !kidFrame->IsSplittable()) { + result = PR_FALSE; + mLastContentIsComplete = prevLastContentIsComplete; + break; + } + status = ReflowChild(kidFrame, aPresContext, kidSize, aState.availSize, + pKidMaxElementSize); + + // Did the child fit? + if ((kidSize.width > aState.availSize.width) && (nsnull != mFirstChild)) { + // The child is too wide to fit in the available space, and it's + // not our first child + result = PR_FALSE; + mLastContentIsComplete = prevLastContentIsComplete; + break; + } + + // Place and size the child. We'll deal with vertical alignment when + // we're all done + PlaceChild(kidFrame, mChildCount, aState, kidSize, pKidMaxElementSize); + + // Remove the frame from its current parent + nextInFlow->mFirstChild = kidFrame->GetNextSibling(); + nextInFlow->mChildCount--; + // Update the next-in-flows first content offset + if (nsnull != nextInFlow->mFirstChild) { + nextInFlow->SetFirstContentOffset(nextInFlow->mFirstChild); + } + + // Link the frame into our list of children + kidFrame->SetGeometricParent(this); + if (nextInFlow == kidFrame->GetContentParent()) { + kidFrame->SetContentParent(this); + } + if (nsnull == prevKidFrame) { + mFirstChild = kidFrame; + SetFirstContentOffset(kidFrame); + } else { + prevKidFrame->SetNextSibling(kidFrame); + } + kidFrame->SetNextSibling(nsnull); + mChildCount++; + + // Remember where we just were in case we end up pushing children + prevKidFrame = kidFrame; + prevLastContentIsComplete = mLastContentIsComplete; + + // Is the child we just pulled up complete? + mLastContentIsComplete = PRBool(status == frComplete); + if (frNotComplete == status) { + // No the child isn't complete + nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); + if (nsnull == kidNextInFlow) { + // The child doesn't have a next-in-flow so create a + // continuing frame. The creation appends it to the flow and + // prepares it for reflow. + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aPresContext, this); + NS_ASSERTION(nsnull != continuingFrame, "frame creation failed"); + + // Add the continuing frame to our sibling list and then push + // it to the next-in-flow. This ensures the next-in-flow's + // content offsets and child count are set properly. Note that + // we can safely assume that the continuation is complete so + // we pass PR_TRUE into PushChidren in case our next-in-flow + // was just drained and now needs to know it's + // mLastContentIsComplete state. + kidFrame->SetNextSibling(continuingFrame); + + PushChildren(continuingFrame, kidFrame, PR_TRUE); + + // After we push the continuation frame we don't need to fuss + // with mLastContentIsComplete beause the continuation frame + // is no longer on *our* list. + } + + // If the child isn't complete then it means that we've used up + // all of our available space. + result = PR_FALSE; + break; + } + } + + // Update our last content offset + if (nsnull != prevKidFrame) { + NS_ASSERTION(LastChild() == prevKidFrame, "bad last child"); + SetLastContentOffset(prevKidFrame); + } + + // We need to make sure the first content offset is correct for any empty + // next-in-flow frames (frames where we pulled up all the child frames) + nextInFlow = (nsInlineFrame*)mNextInFlow; + if ((nsnull != nextInFlow) && (nsnull == nextInFlow->mFirstChild)) { + // We have at least one empty frame. Did we succesfully pull up all the + // child frames? + if (PR_FALSE == result) { + // No, so we need to adjust the first content offset of all the empty + // frames + AdjustOffsetOfEmptyNextInFlows(); +#ifdef NS_DEBUG + } else { + // Yes, we successfully pulled up all the child frames which means all + // the next-in-flows must be empty. Do a sanity check + while (nsnull != nextInFlow) { + NS_ASSERTION(nsnull == nextInFlow->mFirstChild, "non-empty next-in-flow"); + nextInFlow = (nsInlineFrame*)nextInFlow->GetNextInFlow(); + } +#endif + } + } + +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif + return result; +} + +/** + * Create new frames for content we haven't yet mapped + * + * @param aPresContext presentation context to use + * @param aState current inline state + * @return frComplete if all content has been mapped and frNotComplete + * if we should be continued + */ +nsIFrame::ReflowStatus +nsInlineFrame::ReflowUnmappedChildren(nsIPresContext* aPresContext, + nsInlineState& aState) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif + nsIFrame* kidPrevInFlow = nsnull; + ReflowStatus result = frNotComplete; + + // If we have no children and we have a prev-in-flow then we need to pick + // up where it left off. If we have children, e.g. we're being resized, then + // our content offset should already be set correctly... + if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) { + nsInlineFrame* prev = (nsInlineFrame*)mPrevInFlow; + NS_ASSERTION(prev->mLastContentOffset >= prev->mFirstContentOffset, "bad prevInFlow"); + + mFirstContentOffset = prev->NextChildOffset(); + if (!prev->mLastContentIsComplete) { + // Our prev-in-flow's last child is not complete + kidPrevInFlow = prev->LastChild(); + } + } + mLastContentIsComplete = PR_TRUE; + + // Place our children, one at a time until we are out of children + nsSize kidMaxElementSize; + nsSize* pKidMaxElementSize = (nsnull != aState.maxElementSize) ? &kidMaxElementSize : nsnull; + PRInt32 kidIndex = NextChildOffset(); + nsIFrame* prevKidFrame = LastChild(); + + for (;;) { + // Get the next content object + nsIContent* kid = mContent->ChildAt(kidIndex); + if (nsnull == kid) { + result = frComplete; + break; + } + + // Make sure we still have room left + if (aState.availSize.width <= 0) { + // Note: return status was set to frNotComplete above... + NS_RELEASE(kid); + break; + } + + // Resolve style for the child + nsIStyleContext* kidStyleContext = + aPresContext->ResolveStyleContextFor(kid, this); + + // Figure out how we should treat the child + nsIFrame* kidFrame; + nsStyleMolecule* kidMol = + (nsStyleMolecule*)kidStyleContext->GetData(kStyleMoleculeSID); + + if (kidMol->floats != NS_STYLE_FLOAT_NONE) { + PlaceholderFrame::NewFrame(&kidFrame, kid, kidIndex, this); + kidFrame->SetStyleContext(kidStyleContext); + + } else if (nsnull == kidPrevInFlow) { + nsIContentDelegate* kidDel; + switch (kidMol->display) { + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + if (kidIndex != mFirstContentOffset) { + // We don't allow block elements to be placed in us anywhere + // other than at our left margin. + NS_RELEASE(kidStyleContext); + NS_RELEASE(kid); + goto done; + } + // FALLTHROUGH + + case NS_STYLE_DISPLAY_INLINE: + kidDel = kid->GetDelegate(aPresContext); + kidFrame = kidDel->CreateFrame(aPresContext, kid, kidIndex, this); + NS_RELEASE(kidDel); + break; + + default: + NS_ASSERTION(nsnull == kidPrevInFlow, "bad prev in flow"); + nsFrame::NewFrame(&kidFrame, kid, kidIndex, this); + break; + } + kidFrame->SetStyleContext(kidStyleContext); + } else { + kidFrame = kidPrevInFlow->CreateContinuingFrame(aPresContext, this); + } + NS_RELEASE(kid); + NS_RELEASE(kidStyleContext); + + // Try to reflow the child into the available space. It might not + // fit or might need continuing. + nsReflowMetrics kidSize; + ReflowStatus status = ReflowChild(kidFrame,aPresContext, kidSize, + aState.availSize, pKidMaxElementSize); + + // Did the child fit? + if ((kidSize.width > aState.availSize.width) && (nsnull != mFirstChild)) { + // The child is too wide to fit in the available space, and it's + // not our first child. Add the frame to our overflow list + NS_ASSERTION(nsnull == mOverflowList, "bad overflow list"); + mOverflowList = kidFrame; + prevKidFrame->SetNextSibling(nsnull); + break; + } + + // Place and size the child. We'll deal with vertical alignment when + // we're all done + PlaceChild(kidFrame, mChildCount, aState, kidSize, pKidMaxElementSize); + + // Link child frame into the list of children + if (nsnull != prevKidFrame) { + prevKidFrame->SetNextSibling(kidFrame); + } else { + mFirstChild = kidFrame; // our first child + SetFirstContentOffset(kidFrame); + } + prevKidFrame = kidFrame; + mChildCount++; + kidIndex++; + + // Did the child complete? + if (frNotComplete == status) { + // If the child isn't complete then it means that we've used up + // all of our available space + mLastContentIsComplete = PR_FALSE; + break; + } + kidPrevInFlow = nsnull; + } + +done:; + // Update the content mapping + NS_ASSERTION(LastChild() == prevKidFrame, "bad last child"); + SetLastContentOffset(prevKidFrame); +#ifdef NS_DEBUG + PRInt32 len = LengthOf(mFirstChild); + NS_ASSERTION(len == mChildCount, "bad child count"); +#endif +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif + return result; +} + +nsIFrame::ReflowStatus +nsInlineFrame::ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ +#ifdef NS_DEBUG + PreReflowCheck(); +#endif +//XXX not now NS_PRECONDITION((aMaxSize.width > 0) && (aMaxSize.height > 0), "unexpected max size"); + + PRBool reflowMappedOK = PR_TRUE; + ReflowStatus status = frComplete; + + // Get the style molecule + nsStyleFont* styleFont = + (nsStyleFont*)mStyleContext->GetData(kStyleFontSID); + nsStyleMolecule* styleMolecule = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + + // Check for an overflow list + MoveOverflowToChildList(); + + // Initialize our reflow state. We must wait until after we've processed + // the overflow list, because our first content offset might change + nsInlineState state(styleFont, styleMolecule, aMaxSize, aMaxElementSize); + state.SetNumAscents(mContent->ChildCount() - mFirstContentOffset); + + // Reflow any existing frames + if (nsnull != mFirstChild) { + reflowMappedOK = ReflowMappedChildren(aPresContext, state); + + if (PR_FALSE == reflowMappedOK) { + status = frNotComplete; + } + } + + // Did we successfully relow our mapped children? + if (PR_TRUE == reflowMappedOK) { + // Any space left? + if (state.availSize.width <= 0) { + // No space left. Don't try to pull-up children or reflow unmapped + if (NextChildOffset() < mContent->ChildCount()) { + status = frNotComplete; + } + } else if (NextChildOffset() < mContent->ChildCount()) { + // Try and pull-up some children from a next-in-flow + if (PullUpChildren(aPresContext, state)) { + // If we still have unmapped children then create some new frames + if (NextChildOffset() < mContent->ChildCount()) { + status = ReflowUnmappedChildren(aPresContext, state); + } + } else { + // We were unable to pull-up all the existing frames from the next in flow + status = frNotComplete; + } + } + } + + const nsMargin& insets = styleMolecule->borderPadding; + + // Vertically align the children + nscoord lineHeight = + nsCSSLayout::VerticallyAlignChildren(aPresContext, this, styleFont, + insets.top, mFirstChild, mChildCount, + state.ascents, state.maxAscent); + + // XXX I don't think our return size properly accounts for the lineHeight + // (which may not == state.maxAscent + state.maxDescent) + // Return our size and our status + aDesiredSize.width = state.x + insets.right; + aDesiredSize.ascent = insets.top + state.maxAscent; + aDesiredSize.descent = state.maxDescent + insets.bottom; + aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; + +#ifdef NS_DEBUG + PostReflowCheck(status); +#endif + return status; +} + +///////////////////////////////////////////////////////////////////////////// + +PRIntn nsInlineFrame::GetSkipSides() const +{ + PRIntn skip = 0; + if (nsnull != mPrevInFlow) { + skip |= 1 << NS_SIDE_LEFT; + } + if (nsnull != mNextInFlow) { + skip |= 1 << NS_SIDE_RIGHT; + } + return skip; +} + +///////////////////////////////////////////////////////////////////////////// + +// Incremental reflow support + +void nsInlineFrame::GetReflowMetrics(nsIPresContext* aPresContext, + nsReflowMetrics& aMetrics) +{ + nscoord maxAscent = 0; + nscoord maxDescent = 0; + nsIFrame* kid = mFirstChild; + while (nsnull != kid) { + nsReflowMetrics kidMetrics; + kid->GetReflowMetrics(aPresContext, kidMetrics); + if (kidMetrics.ascent > maxAscent) maxAscent = kidMetrics.ascent; + if (kidMetrics.descent > maxDescent) maxDescent = kidMetrics.descent; + kid = kid->GetNextSibling(); + } + + // XXX what about border & padding + aMetrics.width = mRect.width; + aMetrics.height = mRect.height; + aMetrics.ascent = maxAscent; + aMetrics.descent = maxDescent; +} + +/** + * Setup aState to the state it would have had we just reflowed our + * children up to, but not including, aSkipChild. Return the index + * of aSkipChild in our list of children. + */ +PRIntn nsInlineFrame::RecoverState(nsIPresContext* aPresContext, + nsInlineState& aState, + nsIFrame* aSkipChild) +{ + // Get ascent & descent info for all the children up to but not + // including aSkipChild. Also compute the x coordinate for where + // aSkipChild will be place after it is reflowed. + PRIntn i = 0; + nsIFrame* kid = mFirstChild; + nscoord x = aState.x; + nscoord maxAscent = 0; + nscoord maxDescent = 0; + while (kid != aSkipChild) { + nsReflowMetrics kidMetrics; + kid->GetReflowMetrics(aPresContext, kidMetrics); + aState.ascents[i] = kidMetrics.ascent; + if (kidMetrics.ascent > maxAscent) maxAscent = kidMetrics.ascent; + if (kidMetrics.descent > maxDescent) maxDescent = kidMetrics.descent; + + // XXX Factor in left and right margins + x += kidMetrics.width; + + kid = kid->GetNextSibling(); + i++; + } + aState.maxAscent = maxAscent; + aState.maxDescent = maxDescent; + aState.x = x; + return (nsnull == aSkipChild) ? 0 : i; +} + +nsIFrame::ReflowStatus +nsInlineFrame::IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand) +{ + ReflowStatus status = frComplete; + +#if 0 + if (aReflowCommand.GetTarget() == this) { + // NOTE: target frame is first in flow even when reflow commands + // applies to some piece of content in any of the next-in-flows + nsInlineFrame* flow = this; + + switch (aReflowCommand.GetType()) { + case nsReflowCommand::rcContentAppended: + // Get to last-in-flow where the append is occuring + while (nsnull != flow->mNextInFlow) { + flow = flow->mNextInFlow; + } + status = flow->ReflowUnmappedChildren(...); + break; + + case nsReflowCommand::rcContentInserted: + // XXX where did the insertion point go? + + // Get to correct next-in-flow + // XXX this is more complicated when dealing with pseudo children + PRInt32 contentIndex = 0; + while (nsnull != flow->mNextInFlow) { + // XXX the last child we have may be continued into our + // next-in-flow which means that endIndex is wrong??? + PRInt32 endIndex = contentIndex + mChildCount; + if ((contentIndex <= aIndexInParent) && (aIndexInParent < endIndex)) { + break; + } + flow = flow->mNextInFlow; + contentIndex = endIndex; + } + + // Create frame and insert it into the sibling list at the right + // spot. Reflow it. Adjust position of siblings including + // pushing frames that don't fit. + flow->ReflowUnmappedChild(..., index information); + break; + + case nsReflowCommand::rcContentDeleted: + // XXX what about will-delete, did-delete? + + // Find the affected flow blocks and remove the child and any + // continuations it has from the flow. Every flow block except + // the first one will recieve a reflow command to cleanup after + // the first flow block does it's clean up. Except for the + // post-processing (impacting sibling frames) the code is + // generic across container types. + break; + + case nsReflowCommand::rcContentChanged: + // XXX The piece of content affected may change stylistically + // from inline to block. If it does and it's not our first kid + // then we just push it and let our next-in-flow reflow it. + + // Either: a) delete the old frame, create a new frame, reflow -or- + // b) ResizeReflow the affected child + + // If the reflow status is incomplete then the remaining + // children on the line get pushed; else only push children that + // don't fit. If no pushing occurs then maybe we can pullup a + // child; if we do then generate reflow commands for our + // next-in-flows to deal with a pull event. + break; + } + + } else { + // XXX Tuneup? if we save the child's continuation status and its + // current bounding rect and then pass the command down and it + // comes back with the same bounds in aDesiredSize and with the + // same continuation status then we are done, right? + + // Get the next frame that the reflow command is targeted at. + // This will be one of my children. + nsIFrame* nextInChain = aReflowCommand.GetNext(); + NS_ASSERTION(this == nextInChain->GetGeometricParent(), "bad reflow cmd"); + + // Recover the reflow state as if we had reflowed our children up + // to but not including the child that is next in the reflow chain + nsStyleMolecule* styleMolecule = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + nsInlineState state(styleMolecule, aMaxSize, nsnull); + state.SetNumAscents(mChildCount); + PRIntn nextIndex = RecoverState(aPresContext, state, nextInChain); + + // Save away the current location and size of the child which the + // reflow command is targeted towards. This isn't strictly + // necessary, but our child might tamper with it's x/y + // XXX bother? + nsRect oldBounds; + nextInChain->GetRect(oldBounds); + + // Now pass reflow command down to our child to handle + nsReflowMetrics kidMetrics; + status = aReflowCommand.Next(kidMetrics, aMaxSize, kid); + // XXX what do we do when the nextInChain's completion status changes? + // XXX if kid == LastChild() then mLastContentIsComplete needs updating + + // Update placement information for the impacted child frame and + // any other frames following the child frame. + if ((oldBounds.width == kidMetrics.width) && + (oldBounds.height == kidMetrics.height)) { + // The child didn't change as far as we can tell. Nobody needs + // to be moved. + + // XXX what about a child who's shape is the same but who's + // reflow status is frNotComplete? + + // Note: a child that used to be continued and is no longer + // continued and whose size is unchanged: we don't care because + // as far as we are concerned nothing happened to us. However, + // our next-in-flow might get torched (our parent will deal with + // that). + + // XXX figure out the right status to return + } else { + // Factor in ascent information from the updated child + state.ascents[nextIndex] = kidMetrics.ascent; + if (kidMetrics.ascent > state.maxAscent) { + state.maxAscent = kidMetrics.ascent; + } + if (kidMetrics.descent > state.maxDescent) { + state.maxDescent = kidMetrics.descent; + } + + // Update other children that are impacted by the change in + // nextInChain. In addition, re-apply vertical alignment and + // relative positioning to the children on the line. + status = AdjustChildren(aPresContext, aDesiredSize, aState, kid, + kidMetrics, status); + } + } +#endif + + return status; +} + + +// In order to execute the vertical alignment code after incremental +// reflow of the inline frame, we need to reposition any child frames +// that were relatively positioned back to their computed x origin. +// This should probably be done as a pre-alignment computation (and it +// can be avoided if there are no relatively positioned children). + +/** + * Adjust the position of all the children in this frame. + * + * The children after aKid in the list of children are slid over by + * dx. + * + * Once the x and y coordinates have been set, then the vertical + * alignment code is executed to place the children vertically and to + * compute the final height of our frame. + * + * If one of our children spills over the end then push it to the + * next-in-flow or to our overflow list. + */ +nsIFrame::ReflowStatus +nsInlineFrame::AdjustChildren(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + nsInlineState& aState, + nsIFrame* aKid, + nsReflowMetrics& aKidMetrics, + ReflowStatus aKidReflowStatus) +{ + nsStyleMolecule* mol = aState.mol; + nscoord xr = aState.availSize.width + mol->borderPadding.left; + nscoord remainingSpace = xr - aState.x; + nscoord x = aState.x; + + // Slide all of the children over following aKid + nsIFrame* kid = aKid; + nsRect r; + while (nsnull != kid) { + kid->GetRect(r); + if (r.x != x) { + kid->MoveTo(x, r.y); + } + x += r.width; + // XXX factor in left and right margins + kid = kid->GetNextSibling(); + } + + // Vertically align the children + const nsMargin& insets = mol->borderPadding; + nsCSSLayout::VerticallyAlignChildren(aPresContext, this, aState.font, + insets.top, mFirstChild, mChildCount, + aState.ascents, aState.maxAscent); + + // XXX relative position children, if any + + // XXX adjust mLastContentOffset if we push + // XXX if we push, generate a reflow command + + return frComplete; +} + +// My container has new content at the end of it. Create frames for +// the appended content and then generate an incremental reflow +// command for ourselves. +void nsInlineFrame::ContentAppended(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer) +{ + // Zip down to the end-of-flow + nsInlineFrame* flow = this; + for (;;) { + nsInlineFrame* next = (nsInlineFrame*) flow->GetNextInFlow(); + if (nsnull == next) { + break; + } + flow = next; + } + + // Get index of where the content has been appended + PRInt32 kidIndex = flow->NextChildOffset(); + PRInt32 startIndex = kidIndex; + nsIFrame* prevKidFrame = flow->LastChild(); + + // Create frames for each new child + for (;;) { + // Get the next content object + nsIContent* kid = mContent->ChildAt(kidIndex); + if (nsnull == kid) { + break; + } + + nsIContentDelegate* del = kid->GetDelegate(aPresContext); + nsIFrame* kidFrame = del->CreateFrame(aPresContext, kid, kidIndex, flow); + NS_RELEASE(del); + NS_RELEASE(kid); + + // Append kidFrame to the sibling list + prevKidFrame->SetNextSibling(kidFrame); + prevKidFrame = kidFrame; + kidIndex++; + } + flow->SetLastContentOffset(prevKidFrame); + + // Now generate a reflow command for flow + if (aContainer == mContent) { + nsReflowCommand* rc = + new nsReflowCommand(aPresContext, flow, nsReflowCommand::FrameAppended, + startIndex); + aShell->AppendReflowCommand(rc); + } +} diff --git a/mozilla/layout/generic/nsLeafFrame.cpp b/mozilla/layout/generic/nsLeafFrame.cpp new file mode 100644 index 00000000000..052f6bd8ea2 --- /dev/null +++ b/mozilla/layout/generic/nsLeafFrame.cpp @@ -0,0 +1,117 @@ +/* -*- 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 "nsLeafFrame.h" +#include "nsIStyleContext.h" +#include "nsCSSRendering.h" + +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); +static NS_DEFINE_IID(kStyleColorSID, NS_STYLECOLOR_SID); + +nsLeafFrame::nsLeafFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsFrame(aContent, aIndexInParent, aParentFrame) +{ +} + +nsLeafFrame::~nsLeafFrame() +{ +} + +void nsLeafFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + nsStyleColor* myColor = + (nsStyleColor*)mStyleContext->GetData(kStyleColorSID); + nsStyleMolecule* myMol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this, + aDirtyRect, mRect, *myColor); + nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, + aDirtyRect, mRect, *myMol, 0); +} + +nsIFrame::ReflowStatus +nsLeafFrame::ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ + // XXX add in code to check for width/height being set via css + // and if set use them instead of calling GetDesiredSize. + + GetDesiredSize(aPresContext, aDesiredSize, aMaxSize); + AddBordersAndPadding(aPresContext, aDesiredSize); + if (nsnull != aMaxElementSize) { + aMaxElementSize->width = aDesiredSize.width; + aMaxElementSize->height = aDesiredSize.height; + } + return frComplete; +} + +nsIFrame::ReflowStatus +nsLeafFrame::IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand) +{ + // XXX Unless the reflow command is a style change, we should + // just return the current size, otherwise we should invoke + // GetDesiredSize + + // XXX add in code to check for width/height being set via css + // and if set use them instead of calling GetDesiredSize. + GetDesiredSize(aPresContext, aDesiredSize, aMaxSize); + AddBordersAndPadding(aPresContext, aDesiredSize); + + return frComplete; +} + +// XXX how should border&padding effect baseline alignment? +// => descent = borderPadding.bottom for example +void nsLeafFrame::AddBordersAndPadding(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize) +{ + nsStyleMolecule* mol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + aDesiredSize.width += mol->borderPadding.left + mol->borderPadding.right; + aDesiredSize.height += mol->borderPadding.top + mol->borderPadding.bottom; + aDesiredSize.ascent = aDesiredSize.height; + aDesiredSize.descent = 0; +} + +void nsLeafFrame::GetInnerArea(nsIPresContext* aPresContext, + nsRect& aInnerArea) const +{ + nsStyleMolecule* mol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + aInnerArea.x = mol->borderPadding.left; + aInnerArea.y = mol->borderPadding.top; + aInnerArea.width = mRect.width - + (mol->borderPadding.left + mol->borderPadding.right); + aInnerArea.height = mRect.height - + (mol->borderPadding.top + mol->borderPadding.bottom); +} + +nsIFrame* nsLeafFrame::CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent) +{ + NS_NOTREACHED("Attempt to split the unsplittable"); + return nsnull; +} diff --git a/mozilla/layout/generic/nsLeafFrame.h b/mozilla/layout/generic/nsLeafFrame.h new file mode 100644 index 00000000000..6798e154a77 --- /dev/null +++ b/mozilla/layout/generic/nsLeafFrame.h @@ -0,0 +1,77 @@ +/* -*- 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. + */ +#ifndef nsLeafFrame_h___ +#define nsLeafFrame_h___ + +#include "nsFrame.h" + +/** + * Abstract class that provides simple fixed-size layout for leaf objects + * (e.g. images, form elements, etc.). Deriviations provide the implementation + * of the GetDesiredSize method. The rendering method knows how to render + * borders and backgrounds. + */ +class nsLeafFrame : public nsFrame { +public: + virtual void Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + virtual ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + + virtual ReflowStatus IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand); + + virtual nsIFrame* CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent); + +protected: + nsLeafFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + virtual ~nsLeafFrame(); + + /** + * Return the desired size of the frame. Note that this method + * doesn't need to deal with padding or borders (the caller will + * deal with it). In addition, the ascent will be set to the height + * and the descent will be set to zero. + */ + virtual void GetDesiredSize(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize) = 0; + + /** + * Get the inner rect of this frame. This takes the outer size (mRect) + * and subtracts off the borders and padding. + */ + void GetInnerArea(nsIPresContext* aPresContext, nsRect& aInnerArea) const; + + /** + * Subroutine to add in borders and padding + */ + void AddBordersAndPadding(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize); +}; + +#endif /* nsLeafFrame_h___ */ diff --git a/mozilla/layout/generic/nsPageFrame.cpp b/mozilla/layout/generic/nsPageFrame.cpp new file mode 100644 index 00000000000..858422d7f5c --- /dev/null +++ b/mozilla/layout/generic/nsPageFrame.cpp @@ -0,0 +1,178 @@ +/* -*- 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 "nsPageFrame.h" +#include "nsIContent.h" +#include "nsIContentDelegate.h" +#include "nsIPresContext.h" +#include "nsIStyleContext.h" +#include "nsReflowCommand.h" +#include "nsIRenderingContext.h" + +PageFrame::PageFrame(nsIContent* aContent, nsIFrame* aParent) + : nsContainerFrame(aContent, aParent->GetIndexInParent(), aParent) +{ +} + +void PageFrame::CreateFirstChild(nsIPresContext* aPresContext) +{ + // Create a frame for our one and only content child + if (mContent->ChildCount() > 0) { + nsIContent* child = mContent->ChildAt(0); + + if (nsnull != child) { + // Create a frame + nsIContentDelegate* cd = child->GetDelegate(aPresContext); + if (nsnull != cd) { + mFirstChild = cd->CreateFrame(aPresContext, child, 0, this); + if (nsnull != mFirstChild) { + mChildCount = 1; + mLastContentOffset = mFirstContentOffset; + + // Resolve style and set the style context + nsIStyleContext* kidStyleContext = + aPresContext->ResolveStyleContextFor(child, this); + mFirstChild->SetStyleContext(kidStyleContext); + NS_RELEASE(kidStyleContext); + } + NS_RELEASE(cd); + } + NS_RELEASE(child); + } + } +} + +nsIFrame::ReflowStatus +PageFrame::ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ +#ifdef NS_DEBUG + PreReflowCheck(); +#endif + ReflowStatus result = frComplete; + + // Do we have any children? + if (nsnull == mFirstChild) { + if (nsnull == mPrevInFlow) { + // Create the first child frame + CreateFirstChild(aPresContext); + } else { + PageFrame* prevPage = (PageFrame*)mPrevInFlow; + + NS_ASSERTION(!prevPage->mLastContentIsComplete, "bad continuing page"); + nsIFrame* prevLastChild = prevPage->LastChild(); + + // Create a continuing child of the previous page's last child + mFirstChild = prevLastChild->CreateContinuingFrame(aPresContext, this); + mChildCount = 1; + mLastContentOffset = mFirstContentOffset; + } + } + + // Resize our frame allowing it only to be as big as we are + // XXX Pay attention to the page's border and padding... + if (nsnull != mFirstChild) { + // Get the child's desired size + result = ReflowChild(mFirstChild, aPresContext, aDesiredSize, aMaxSize, + aMaxElementSize); + mLastContentIsComplete = PRBool(result == frComplete); + + // Make sure the child is at least as tall as our max size (the containing window) + if (aDesiredSize.height < aMaxSize.height) { + aDesiredSize.height = aMaxSize.height; + } + + // Place and size the child + nsRect rect(0, 0, aDesiredSize.width, aDesiredSize.height); + mFirstChild->SetRect(rect); + + // Is the frame complete? + if (frComplete == result) { + NS_ASSERTION(nsnull == mFirstChild->GetNextInFlow(), "bad child flow list"); + } + } + + // Return our desired size + aDesiredSize.width = aMaxSize.width; + aDesiredSize.height = aMaxSize.height; + +#ifdef NS_DEBUG + PostReflowCheck(result); +#endif + return result; +} + +// XXX Do something sensible in page mode... +nsIFrame::ReflowStatus +PageFrame::IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand) +{ + // We don't expect the target of the reflow command to be page frame + NS_ASSERTION(aReflowCommand.GetTarget() != this, "page frame is reflow command target"); + + nsSize maxSize(aMaxSize.width, NS_UNCONSTRAINEDSIZE); + ReflowStatus status; + nsIFrame* child; + + // Dispatch the reflow command to our pseudo frame. Allow it to be as high + // as it wants + status = aReflowCommand.Next(aDesiredSize, maxSize, child); + + // Place and size the child. Make sure the child is at least as + // tall as our max size (the containing window) + if (nsnull != child) { + NS_ASSERTION(child == mFirstChild, "unexpected reflow command frame"); + if (aDesiredSize.height < aMaxSize.height) { + aDesiredSize.height = aMaxSize.height; + } + + nsRect rect(0, 0, aDesiredSize.width, aDesiredSize.height); + child->SetRect(rect); + } + + return status; +} + +nsIFrame* PageFrame::CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent) +{ + PageFrame* cf = new PageFrame(mContent, aParent); + PrepareContinuingFrame(aPresContext, aParent, cf); + return cf; +} + +void PageFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + nsContainerFrame::Paint(aPresContext, aRenderingContext, aDirtyRect); + + // For the time being paint a border around the page so we know + // where each page begins and ends + aRenderingContext.SetColor(NS_RGB(0, 0, 0)); + aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height); +} + +void PageFrame::ListTag(FILE* out) const +{ + fprintf(out, "*PAGE@%p", this); +} + diff --git a/mozilla/layout/generic/nsPageFrame.h b/mozilla/layout/generic/nsPageFrame.h new file mode 100644 index 00000000000..b3d8387c8f5 --- /dev/null +++ b/mozilla/layout/generic/nsPageFrame.h @@ -0,0 +1,53 @@ +/* -*- 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. + */ +#ifndef nsPageFrame_h___ +#define nsPageFrame_h___ + +#include "nsHTMLContainerFrame.h" + +// Pseudo frame created by the root content frame +class PageFrame : public nsContainerFrame { +public: + PageFrame(nsIContent* aContent, nsIFrame* aParent); + + virtual ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + + virtual ReflowStatus IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand); + + virtual nsIFrame* CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent); + + virtual void Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + // Debugging + virtual void ListTag(FILE* out = stdout) const; + +protected: + void CreateFirstChild(nsIPresContext* aPresContext); +}; + +#endif /* nsPageFrame_h___ */ + diff --git a/mozilla/layout/generic/nsPlaceholderFrame.cpp b/mozilla/layout/generic/nsPlaceholderFrame.cpp new file mode 100644 index 00000000000..1028f477461 --- /dev/null +++ b/mozilla/layout/generic/nsPlaceholderFrame.cpp @@ -0,0 +1,101 @@ +/* -*- 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 "nsPlaceholderFrame.h" +#include "nsIContent.h" +#include "nsIContentDelegate.h" +#include "nsIFloaterContainer.h" + +static NS_DEFINE_IID(kIFloaterContainerIID, NS_IFLOATERCONTAINER_IID); + +nsresult +PlaceholderFrame::NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIFrame* it = new PlaceholderFrame(aContent, aIndexInParent, aParent); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aInstancePtrResult = it; + return NS_OK; +} + +PlaceholderFrame::PlaceholderFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) + : nsFrame(aContent, aIndexInParent, aParent) +{ + mAnchoredItem = nsnull; +} + +PlaceholderFrame::~PlaceholderFrame() +{ +} + +nsIFrame::ReflowStatus +PlaceholderFrame::ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ + // Get the floater container in which we're inserted + nsIFloaterContainer* container = nsnull; + + for (nsIFrame* parent = mGeometricParent; parent; parent = parent->GetGeometricParent()) { + if (NS_OK == parent->QueryInterface(kIFloaterContainerIID, (void**)&container)) { + break; + } + } + NS_ASSERTION(nsnull != container, "no floater container"); + + // Have we created the anchored item yet? + if (nsnull == mAnchoredItem) { + // Create the anchored item + nsIContentDelegate* delegate = mContent->GetDelegate(aPresContext); + + mAnchoredItem = delegate->CreateFrame(aPresContext, mContent, mIndexInParent, + mGeometricParent); + NS_RELEASE(delegate); + + // Set the style context for the frame + mAnchoredItem->SetStyleContext(mStyleContext); + + // Resize reflow the anchored item into the available space + // XXX Check for complete? + mAnchoredItem->ResizeReflow(aPresContext, aDesiredSize, aMaxSize, nsnull); + mAnchoredItem->SizeTo(aDesiredSize.width, aDesiredSize.height); + + // Now notify our containing block that there's a new floater + container->AddFloater(aPresContext, mAnchoredItem, this); + } else { + container->PlaceFloater(aPresContext, mAnchoredItem, this); + } + + return nsFrame::ResizeReflow(aPresContext, aDesiredSize, aMaxSize, aMaxElementSize); +} + +void PlaceholderFrame::ListTag(FILE* out) const +{ + fputs("*placeholder", out); + fprintf(out, "(%d)@%p", mIndexInParent, this); +} diff --git a/mozilla/layout/generic/nsPlaceholderFrame.h b/mozilla/layout/generic/nsPlaceholderFrame.h new file mode 100644 index 00000000000..b3b87673539 --- /dev/null +++ b/mozilla/layout/generic/nsPlaceholderFrame.h @@ -0,0 +1,57 @@ +/* -*- 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. + */ +#ifndef nsPlaceholderFrame_h___ +#define nsPlaceholderFrame_h___ + +#include "nsFrame.h" + +// Implementation of a frame that's used as a placeholder for an anchored item +class PlaceholderFrame : public nsFrame +{ +public: + /** + * Create a new placeholder frame + */ + static nsresult NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + // Returns the associated anchored item + nsIFrame* GetAnchoredItem() const {return mAnchoredItem;} + + // Resize reflow methods + virtual ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + virtual void ListTag(FILE* out = stdout) const; + +protected: + // Constructor. Takes as arguments the content object, the index in parent, + // and the Frame for the content parent + PlaceholderFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + virtual ~PlaceholderFrame(); + + nsIFrame* mAnchoredItem; +}; + +#endif /* nsPlaceholderFrame_h___ */ diff --git a/mozilla/layout/generic/nsSpaceManager.cpp b/mozilla/layout/generic/nsSpaceManager.cpp new file mode 100644 index 00000000000..fc937046036 --- /dev/null +++ b/mozilla/layout/generic/nsSpaceManager.cpp @@ -0,0 +1,549 @@ +/* -*- 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 "nsSpaceManager.h" +#include "nsPoint.h" +#include "nsRect.h" +#include "nsSize.h" +#include + +static NS_DEFINE_IID(kISpaceManagerIID, NS_ISPACEMANAGER_IID); + +///////////////////////////////////////////////////////////////////////////// +// nsSpaceManager + +SpaceManager::SpaceManager(nsIFrame* aFrame) + : mFrame(aFrame) +{ + NS_INIT_REFCNT(); + mX = mY = 0; +} + +NS_IMPL_ISUPPORTS(SpaceManager, kISpaceManagerIID); + +nsIFrame* SpaceManager::GetFrame() const +{ + return mFrame; +} + +void SpaceManager::Translate(nscoord aDx, nscoord aDy) +{ + mX += aDx; + mY += aDy; +} + +void SpaceManager::GetTranslation(nscoord& aX, nscoord& aY) const +{ + aX = mX; + aY = mY; +} + +nscoord SpaceManager::YMost() const +{ + if (mRectArray.mCount > 0) { + return mRectArray.YMost(); + } else { + return 0; + } +} + +/** + * Internal function that returns the available space within the band + * + * @param aBand the first rect in the band + * @param aIndex aBand's index in the rect array + * @param aY the y-offset in world coordinates + * @param aMaxSize the size to use to constrain the band data + * @param aAvailableBand + */ +PRInt32 SpaceManager::GetBandAvailableSpace(const nsRect* aBand, + PRInt32 aIndex, + nscoord aY, + const nsSize& aMaxSize, + nsBandData& aAvailableSpace) const +{ + PRInt32 numRects = LengthOfBand(aBand, aIndex); + nscoord localY = aY - mY; + nscoord height = PR_MIN(aBand->YMost() - aY, aMaxSize.height); + nsRect* rect = aAvailableSpace.rects; + nscoord rightEdge = mX + aMaxSize.width; + + // Initialize the band data + aAvailableSpace.count = 0; + rect->x = mX; + + // Skip any rectangles that are to the left of the local coordinate space + while (numRects > 0) { + if (aBand->XMost() >= mX) { + break; + } + + // Get the next rect in the band + aBand++; + numRects--; + } + + // Process all the remaining rectangles that are within the clip width + while ((numRects > 0) && (aBand->x < rightEdge)) { + if (aBand->x > rect->x) { + // We found some available space + rect->width = aBand->x - rect->x; + rect->x -= mX; // convert from world to local coordinates + rect->y = localY; + rect->height = height; + + // Move to the next output rect + rect++; + aAvailableSpace.count++; + } + + rect->x = aBand->XMost(); + + // Move to the next rect in the band + numRects--; + aBand++; + } + + // No more rects left in the band. If we haven't yet reached the right edge + // then all the remaining space is available + if (rect->x < rightEdge) { + rect->width = rightEdge - rect->x; + rect->x -= mX; // convert from world to local coordinates + rect->y = localY; + rect->height = height; + aAvailableSpace.count++; + } + + return aAvailableSpace.count; +} + +PRInt32 SpaceManager::GetBandData(nscoord aYOffset, + const nsSize& aMaxSize, + nsBandData& aAvailableSpace) const +{ + // Convert the y-offset to world coordinates + nscoord y = mY + aYOffset; + + // If there are no unavailable rects or the offset is below the bottommost + // band then all the space is available + if ((0 == mRectArray.mCount) || (y >= mRectArray.YMost())) { + aAvailableSpace.count = 1; + aAvailableSpace.rects[0].x = 0; + aAvailableSpace.rects[0].y = aYOffset; + aAvailableSpace.rects[0].width = aMaxSize.width; + aAvailableSpace.rects[0].height = aMaxSize.height; + } else { + // Find the first band that contains the y-offset or is below the y-offset + nsRect* band = mRectArray.mRects; + + for (PRInt32 i = 0; i < mRectArray.mCount; ) { + if (band->y > y) { + // The band is below the y-offset + aAvailableSpace.count = 1; + aAvailableSpace.rects[0].x = 0; + aAvailableSpace.rects[0].y = aYOffset; + aAvailableSpace.rects[0].width = aMaxSize.width; + aAvailableSpace.rects[0].height = PR_MIN(band->y - y, aMaxSize.height); + break; + } else if (y < band->YMost()) { + // The band contains the y-offset + return GetBandAvailableSpace(band, i, y, aMaxSize, aAvailableSpace); + } else { + // Skip to the next band + GetNextBand(band, i); + } + } + } + + return aAvailableSpace.count; +} + +/** + * Skips to the start of the next band. + * + * @param aRect in out paremeter. A rect in the band + * @param aIndex in out parameter. aRect's index in the rect array + * @returns PR_TRUE if successful and PR_FALSE if this is the last band. + * If successful aRect and aIndex are updated to point to the + * next band. If there is no next band then aRect is undefined + * and aIndex is set to the number of rects in the rect array + */ +PRBool SpaceManager::GetNextBand(nsRect*& aRect, PRInt32& aIndex) const +{ + nscoord topOfBand = aRect->y; + + while (++aIndex < mRectArray.mCount) { + // Get the next rect and check whether it's part of the same band + aRect++; + + if (aRect->y != topOfBand) { + // We found the start of the next band + return PR_TRUE; + } + } + + // No bands left + return PR_FALSE; +} + +/** + * Returns the number of rectangles in the band + * + * @param aBand the first rect in the band + * @param aIndex aBand's index in the rect array + */ +PRInt32 SpaceManager::LengthOfBand(const nsRect* aBand, PRInt32 aIndex) const +{ + nscoord topOfBand = aBand->y; + PRInt32 result = 1; + + while (++aIndex < mRectArray.mCount) { + // Get the next rect and check whether it's part of the same band + aBand++; + + if (aBand->y != topOfBand) { + // We found the start of the next band + break; + } + + result++; + } + + return result; +} + +/** + * Tries to coalesce horizontally overlapping rectangles within a band + * + * @param aRect a rect in the band + * @param aIndex aRect's index in the rect array + */ +void SpaceManager::CoalesceBand(nsRect* aRect, PRInt32 aIndex) +{ + while ((aIndex + 1) < mRectArray.mCount) { + // Is there another rect in this band? + nsRect* nextRect = aRect + 1; + + if (nextRect->y == aRect->y) { + // Yes. Do the two rects overlap horizontally? + if (aRect->XMost() > nextRect->x) { + // Yes. Extend the right edge of aRect + aRect->width = nextRect->XMost() - aRect->x; + + // Remove the next rect + mRectArray.RemoveAt(aIndex + 1); + aRect = mRectArray.mRects + aIndex; // memory may have changed... + + } else { + // No. We're all done + break; + } + } else { + // The next rect is part of a different band, so we're all done + break; + } + } +} + +/** + * Divides the current band into two vertically + * + * @param aBand the first rect in the band + * @param aIndex aBand's index in the rect array + * @param aB1Height the height of the new band to create + */ +void SpaceManager::DivideBand(nsRect* aBand, PRInt32 aIndex, nscoord aB1Height) +{ + NS_PRECONDITION(aB1Height < aBand->height, "bad height"); + + PRInt32 numRects = LengthOfBand(aBand, aIndex); + nscoord aB2Height = aBand->height - aB1Height; + + // Index where we'll insert the new band + PRInt32 insertAt = aIndex + numRects; + + while (numRects-- > 0) { + // Insert a new bottom band + nsRect r(aBand->x, aBand->y + aB1Height, aBand->width, aB2Height); + + mRectArray.InsertAt(r, insertAt); + aBand = mRectArray.mRects + aIndex; // memory may have changed... + + // Adjust the height of the top band + aBand->height = aB1Height; + + // Move to the next rect in the band + aBand++; + insertAt++; + } +} + +/** + * Adds a new rect to a band. + * + * @param aBand the first rect in the band + * @param aIndex aBand's index in the rect array + * @param aRect the rect to add to the band + * @returns PR_TRUE if successful and PR_FALSE if this is the last band + */ +void SpaceManager::AddRectToBand(nsRect* aBand, + PRInt32 aIndex, + const nsRect& aRect) +{ + NS_PRECONDITION((aBand->y == aRect.y) && (aBand->height == aRect.height), "bad band"); + + nscoord topOfBand = aBand->y; + + // Figure out where in the band to horizontally insert the rect. Try and + // coalesce it with an existing rect if possible. + do { + // Compare the left edge of the new rect with the left edge of the existing + // rect + if (aRect.x <= aBand->x) { + // The new rect's left edge is to the left of the existing rect's left + // edge. Does the new rect overlap the existing rect? + if (aRect.XMost() >= aBand->x) { + // Yes. Extend the existing rect + if (aRect.XMost() > aBand->XMost()) { + aBand->x = aRect.x; + aBand->width = aRect.width; + + // We're extending the right edge of the existing rect which may + // cause the rect to overlap the remaining rects in the band + CoalesceBand(aBand, aIndex); + } else { + aBand->width = aBand->XMost() - aRect.x; + aBand->x = aRect.x; + } + } else { + // No, it's completely to the left of the existing rect. Insert a new + // rect + mRectArray.InsertAt(aRect, aIndex); + } + return; + + } else if (aRect.x <= aBand->XMost()) { + // The two rects are overlapping or adjoining. Extend the right edge of + // the existing rect + aBand->width = aRect.XMost() - aBand->x; + + // Since we extended the right edge of the existing rect it may now + // overlap the remaining rects in the band + CoalesceBand(aBand, aIndex); + return; + } + + // Move to the next rect in the band + aBand++; aIndex++; + } while ((aIndex < mRectArray.mCount) && (aBand->y == topOfBand)); + + // Insert a new rect + mRectArray.InsertAt(aRect, aIndex); +} + +// When comparing a rect to a band there are seven cases to consider. +// 'R' is the rect and 'B' is the band. +// +// Case 1 Case 2 Case 3 Case 4 +// ------ ------ ------ ------ +// +-----+ +-----+ +-----+ +-----+ +// | R | | R | +-----+ +-----+ | | | | +// +-----+ +-----+ | | | R | | B | | B | +// +-----+ | B | +-----+ | | +-----+ | | +// | | | | +-----+ | R | +-----+ +// | B | +-----+ +-----+ +// | | +// +-----+ +// +// +// +// Case 5 Case 6 Case 7 +// ------ ------ ------ +// +-----+ +-----+ +-----+ +-----+ +// | | | R | | B | | | +-----+ +// | B | +-----+ +-----+ | R | | B | +// | | | | +-----+ +// +-----+ +-----+ +// +-----+ +// | R | +// +-----+ +// +void SpaceManager::AddRectRegion(const nsRect& aUnavailableSpace) +{ + // Convert from local to world coordinates + nsRect rect(aUnavailableSpace.x + mX, aUnavailableSpace.y + mY, + aUnavailableSpace.width, aUnavailableSpace.height); + + // If there are no existing bands or this rect is below the bottommost band, + // then add a new band + if ((0 == mRectArray.mCount) || (rect.y >= mRectArray.YMost())) { + // Append a new bottommost band + mRectArray.Append(rect); + return; + } + + // Examine each band looking for a band that intersects this rect + nsRect* band = mRectArray.mRects; + + for (PRInt32 i = 0; i < mRectArray.mCount; ) { + // Compare the top edge of this rect with the top edge of the band + if (rect.y < band->y) { + // The top edge of the rect is above the top edge of the band. + // Is there any overlap? + if (rect.YMost() <= band->y) { + // Case #1. This rect is completely above the band, so insert a + // new band + mRectArray.InsertAt(rect, i); + break; // we're all done + } + + // Case #2 and case #7. Divide this rect, creating a new rect for the + // part that's above the band + nsRect r1(rect.x, rect.y, rect.width, band->y - rect.y); + + // Insert r1 as a new band + mRectArray.InsertAt(r1, i); + i++; + band = mRectArray.mRects + i; // memory may have changed... + + // Modify rect to exclude the part above the band + rect.height = rect.YMost() - band->y; + rect.y = band->y; + + } else if (rect.y > band->y) { + // The top edge of the rect is below the top edge of the band. Is there + // any overlap? + if (rect.y >= band->YMost()) { + // Case #5. This rect is below the current band. Skip to the next band + GetNextBand(band, i); + continue; + } + + // Case #3 and case #4. Divide the current band into two bands with the + // top band being the part that's above the rect + DivideBand(band, i, rect.y - band->y); + band = mRectArray.mRects + i; // memory may have changed... + + // Skip to the bottom band that we just created + GetNextBand(band, i); + } + + // At this point the rect and the band should have the same y-offset + NS_ASSERTION(rect.y == band->y, "unexpected band"); + + // Is the band higher than the rect? + if (band->height > rect.height) { + // Divide the band into two bands with the top band the same height + // as the rect + DivideBand(band, i, rect.height); + band = mRectArray.mRects + i; // memory may have changed... + } + + if (rect.height == band->height) { + // Add the rect to the band + AddRectToBand(band, i, rect); + break; + + } else { + // Case #4 and case #7. The rect contains the band vertically. Divide + // the rect, creating a new rect for the part that overlaps the band + nsRect r1(rect.x, rect.y, rect.width, band->YMost() - rect.y); + + // Add r1 to the band + AddRectToBand(band, i, r1); + band = mRectArray.mRects + i; // memory may have changed... + + // Modify rect to be the part below the band + rect.height = rect.YMost() - band->YMost(); + rect.y = band->YMost(); + + // Continue with the next band + if (!GetNextBand(band, i)) { + // Append a new bottommost band + mRectArray.Append(rect); + break; + } + } + } +} + +void SpaceManager::ClearRegions() +{ + mRectArray.Clear(); +} + +///////////////////////////////////////////////////////////////////////////// +// RectArray + +SpaceManager::RectArray::RectArray() +{ + mRects = nsnull; + mCount = mMax = 0; +} + +SpaceManager::RectArray::~RectArray() +{ + if (nsnull != mRects) { + free(mRects); + } +} + +nscoord SpaceManager::RectArray::YMost() const +{ + return mRects[mCount - 1].YMost(); +} + +void SpaceManager::RectArray::Append(const nsRect& aRect) +{ + // Ensure there's enough capacity + if (mCount >= mMax) { + mMax += 8; + mRects = (nsRect*)realloc(mRects, mMax * sizeof(nsRect)); + } + + mRects[mCount++] = aRect; +} + +void SpaceManager::RectArray::InsertAt(const nsRect& aRect, PRInt32 aIndex) +{ + NS_PRECONDITION(aIndex <= mCount, "bad index"); // no holes in the array + + // Ensure there's enough capacity + if (mCount >= mMax) { + mMax += 8; + mRects = (nsRect*)realloc(mRects, mMax * sizeof(nsRect)); + } + + memmove(&mRects[aIndex + 1], &mRects[aIndex], (mCount - aIndex) * sizeof(nsRect)); + mRects[aIndex] = aRect; + mCount++; +} + +void SpaceManager::RectArray::RemoveAt(PRInt32 aIndex) +{ + NS_PRECONDITION(aIndex < mCount, "bad index"); + + mCount--; + if (aIndex < mCount) { + memmove(&mRects[aIndex], &mRects[aIndex + 1], (mCount - aIndex) * sizeof(nsRect)); + } +} + +void SpaceManager::RectArray::Clear() +{ + mCount = 0; +} diff --git a/mozilla/layout/generic/nsSpaceManager.h b/mozilla/layout/generic/nsSpaceManager.h new file mode 100644 index 00000000000..978d6ae5cf8 --- /dev/null +++ b/mozilla/layout/generic/nsSpaceManager.h @@ -0,0 +1,91 @@ +/* -*- 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. + */ +#ifndef nsSpaceManager_h___ +#define nsSpaceManager_h___ + +#include "nsISpaceManager.h" + +/** + * Implementation of nsISpaceManager that maintains a region data structure of + * unavailable space + */ +class SpaceManager : public nsISpaceManager { +public: + SpaceManager(nsIFrame* aFrame); + + // nsISupports + NS_DECL_ISUPPORTS + + virtual nsIFrame* GetFrame() const; + + virtual void Translate(nscoord aDx, nscoord aDy); + virtual void GetTranslation(nscoord& aX, nscoord& aY) const; + virtual nscoord YMost() const; + virtual PRInt32 GetBandData(nscoord aYOffset, + const nsSize& aMaxSize, + nsBandData& aAvailableSpace) const; + virtual void AddRectRegion(const nsRect& aUnavailableSpace); + virtual void ClearRegions(); + +protected: + class RectArray { + public: + RectArray(); + ~RectArray(); + + // Functions to add rects + void Append(const nsRect& aRect); + void InsertAt(const nsRect& aRect, PRInt32 aIndex); + void RemoveAt(PRInt32 aIndex); + + // Clear the list of rectangles + void Clear(); + + // Returns the y-most of the bottom band + nscoord YMost() const; + + public: + // Access to the underlying storage + nsRect* mRects; // y-x banded array of rectangles of unavailable space + PRInt32 mCount; // current number of rects + PRInt32 mMax; // capacity of rect array + }; + + nsIFrame* const mFrame; // frame associated with the space manager + nscoord mX, mY; // translation from local to global coordinate space + RectArray mRectArray; // y-x banded array of rectangles of unavailable space + +protected: + PRBool GetNextBand(nsRect*& aRect, PRInt32& aIndex) const; + PRInt32 LengthOfBand(const nsRect* aBand, PRInt32 aIndex) const; + void CoalesceBand(nsRect* aBand, PRInt32 aIndex); + void DivideBand(nsRect* aBand, PRInt32 aIndex, nscoord aB1Height); + void AddRectToBand(nsRect* aBand, PRInt32 aIndex, const nsRect& aRect); + PRInt32 GetBandAvailableSpace(const nsRect* aBand, + PRInt32 aIndex, + nscoord aY, + const nsSize& aMaxSize, + nsBandData& aAvailableSpace) const; + +private: + SpaceManager(const SpaceManager&); // no implementation + void operator=(const SpaceManager&); // no implementation +}; + +#endif /* nsSpaceManager_h___ */ + diff --git a/mozilla/layout/html/Makefile b/mozilla/layout/html/Makefile new file mode 100644 index 00000000000..c398fa8ab75 --- /dev/null +++ b/mozilla/layout/html/Makefile @@ -0,0 +1,26 @@ +#!gmake +# +# 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. + +DEPTH = ../.. + +# Don't do tests for now +#DIRS = base document forms style table build tests +DIRS = base document forms style table + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/layout/html/base/Makefile b/mozilla/layout/html/base/Makefile new file mode 100644 index 00000000000..b0ff7c06fd4 --- /dev/null +++ b/mozilla/layout/html/base/Makefile @@ -0,0 +1,24 @@ +#!gmake +# +# 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. + +DEPTH = ../../.. + +DIRS = src + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/layout/html/base/makefile.win b/mozilla/layout/html/base/makefile.win new file mode 100644 index 00000000000..fd332714cf2 --- /dev/null +++ b/mozilla/layout/html/base/makefile.win @@ -0,0 +1,23 @@ +#!nmake +# +# 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. + +DEPTH=..\..\.. +IGNORE_MANIFEST=1 + +DIRS=src + +include <$(DEPTH)\config\rules.mak> diff --git a/mozilla/layout/html/base/src/Makefile b/mozilla/layout/html/base/src/Makefile new file mode 100644 index 00000000000..868b38f7956 --- /dev/null +++ b/mozilla/layout/html/base/src/Makefile @@ -0,0 +1,70 @@ +#!gmake +# +# 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. + +DEPTH=../../../.. + +LIBRARY_NAME = raptorhtmlbase_s + +INCLUDES += \ + -I../../dom \ + $(NULL) + +# Note the sophisticated alphabetical ordering :-| +CPPSRCS = \ + nsBRPart.cpp \ + nsBlockFrame.cpp \ + nsBodyFrame.cpp \ + nsBodyPart.cpp \ + nsColumnFrame.cpp \ + nsGlobalVariables.cpp \ + nsHRPart.cpp \ + nsHTMLAtoms.cpp \ + nsHTMLContainer.cpp \ + nsHTMLContainerFrame.cpp \ + nsHTMLContent.cpp \ + nsHTMLIIDs.cpp \ + nsHTMLImage.cpp \ + nsHTMLTagContent.cpp \ + nsHTMLTags.cpp \ + nsImageMap.cpp \ + nsInlineFrame.cpp \ + nsLeafFrame.cpp \ + nsListItemFrame.cpp \ + nsPageFrame.cpp \ + nsPlaceholderFrame.cpp \ + nsRootPart.cpp \ + nsSpacerPart.cpp \ + nsTextContent.cpp \ + nsWBRPart.cpp \ + nsDOMIterator.cpp \ + nsDOMAttributes.cpp \ + $(NULL) +EXPORTS = \ + nsGlobalVariables.h \ + $(NULL) + +MODULE = raptor + +REQUIRES = xpcom raptor dom + +include $(DEPTH)/config/config.mk + +LCFLAGS += -D_IMPL_NS_HTML + +INCLUDES += -I../../style/src -I../../document/src + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/layout/html/base/src/deadnsInlineFrame.h b/mozilla/layout/html/base/src/deadnsInlineFrame.h new file mode 100644 index 00000000000..836a8f3082f --- /dev/null +++ b/mozilla/layout/html/base/src/deadnsInlineFrame.h @@ -0,0 +1,86 @@ +/* -*- 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. + */ +#ifndef nsInlineFrame_h___ +#define nsInlineFrame_h___ + +#include "nsHTMLContainerFrame.h" + +class nsInlineState; + +// Inline container class. Does not support being used as a pseudo frame +class nsInlineFrame : public nsHTMLContainerFrame +{ +public: + static nsresult NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + virtual ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + + virtual ReflowStatus IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand); + + virtual void ContentAppended(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer); + + virtual void GetReflowMetrics(nsIPresContext* aPresContext, + nsReflowMetrics& aMetrics); + +protected: + nsInlineFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + virtual ~nsInlineFrame(); + + virtual PRIntn GetSkipSides() const; + + PRBool ReflowMappedChildren(nsIPresContext* aPresContext, + nsInlineState& aState); + + PRBool PullUpChildren(nsIPresContext* aPresContext, + nsInlineState& aState); + + ReflowStatus ReflowUnmappedChildren(nsIPresContext* aPresContext, + nsInlineState& aState); + + void PlaceChild(nsIFrame* aChild, + PRInt32 aIndex, // in the child frame list + nsInlineState& aState, + const nsReflowMetrics& aChildSize, + const nsSize* aChildMaxElementSize); + + PRIntn RecoverState(nsIPresContext* aCX, nsInlineState& aState, + nsIFrame* aSkipChild); + + ReflowStatus AdjustChildren(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + nsInlineState& aState, + nsIFrame* aKid, + nsReflowMetrics& aKidMetrics, + ReflowStatus aKidReflowStatus); +}; + +#endif /* nsInlineFrame_h___ */ diff --git a/mozilla/layout/html/base/src/makefile.win b/mozilla/layout/html/base/src/makefile.win new file mode 100644 index 00000000000..cea04cf4fa6 --- /dev/null +++ b/mozilla/layout/html/base/src/makefile.win @@ -0,0 +1,101 @@ +#!nmake +# +# 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. + +DEPTH=..\..\..\.. +IGNORE_MANIFEST=1 + +LIBRARY_NAME=raptorhtmlbase_s +MODULE=raptor +REQUIRES=xpcom raptor +DEFINES=-D_IMPL_NS_HTML -I..\..\style\src -I$(PUBLIC)\dom + +CPPSRCS= \ + nsBRPart.cpp \ + nsBlockFrame.cpp \ + nsBodyFrame.cpp \ + nsBodyPart.cpp \ + nsColumnFrame.cpp \ + nsGlobalVariables.cpp \ + nsHRPart.cpp \ + nsHTMLAtoms.cpp \ + nsHTMLContainer.cpp \ + nsHTMLContainerFrame.cpp \ + nsHTMLContent.cpp \ + nsHTMLIIDs.cpp \ + nsHTMLImage.cpp \ + nsHTMLTagContent.cpp \ + nsHTMLTags.cpp \ + nsImageMap.cpp \ + nsInlineFrame.cpp \ + nsLeafFrame.cpp \ + nsListItemFrame.cpp \ + nsPageFrame.cpp \ + nsPlaceholderFrame.cpp \ + nsRootPart.cpp \ + nsSpacerPart.cpp \ + nsTextContent.cpp \ + nsWBRPart.cpp \ + nsDOMIterator.cpp \ + nsDOMAttributes.cpp \ + $(NULL) + +CPP_OBJS= \ + .\$(OBJDIR)\nsBRPart.obj \ + .\$(OBJDIR)\nsBlockFrame.obj \ + .\$(OBJDIR)\nsBodyFrame.obj \ + .\$(OBJDIR)\nsBodyPart.obj \ + .\$(OBJDIR)\nsColumnFrame.obj \ + .\$(OBJDIR)\nsGlobalVariables.obj \ + .\$(OBJDIR)\nsHRPart.obj \ + .\$(OBJDIR)\nsHTMLAtoms.obj \ + .\$(OBJDIR)\nsHTMLContainer.obj \ + .\$(OBJDIR)\nsHTMLContainerFrame.obj \ + .\$(OBJDIR)\nsHTMLContent.obj \ + .\$(OBJDIR)\nsHTMLIIDs.obj \ + .\$(OBJDIR)\nsHTMLImage.obj \ + .\$(OBJDIR)\nsHTMLTagContent.obj \ + .\$(OBJDIR)\nsHTMLTags.obj \ + .\$(OBJDIR)\nsImageMap.obj \ + .\$(OBJDIR)\nsInlineFrame.obj \ + .\$(OBJDIR)\nsLeafFrame.obj \ + .\$(OBJDIR)\nsListItemFrame.obj \ + .\$(OBJDIR)\nsPageFrame.obj \ + .\$(OBJDIR)\nsPlaceholderFrame.obj \ + .\$(OBJDIR)\nsRootPart.obj \ + .\$(OBJDIR)\nsSpacerPart.obj \ + .\$(OBJDIR)\nsTextContent.obj \ + .\$(OBJDIR)\nsWBRPart.obj \ + .\$(OBJDIR)\nsDOMIterator.obj \ + .\$(OBJDIR)\nsDOMAttributes.obj \ + $(NULL) + +EXPORTS=nsGlobalVariables.h + +LINCS=-I$(XPDIST)\public\xpcom -I$(XPDIST)\public\raptor + +LCFLAGS = \ + $(LCFLAGS) \ + $(DEFINES) \ + $(NULL) + +include <$(DEPTH)\config\rules.mak> + +libs:: $(LIBRARY) + $(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib + +clobber:: + rm -f $(DIST)\lib\$(LIBRARY_NAME).lib diff --git a/mozilla/layout/html/base/src/nsBRPart.cpp b/mozilla/layout/html/base/src/nsBRPart.cpp new file mode 100644 index 00000000000..2a731bc7bf4 --- /dev/null +++ b/mozilla/layout/html/base/src/nsBRPart.cpp @@ -0,0 +1,238 @@ +/* -*- 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 "nsHTMLParts.h" +#include "nsHTMLTagContent.h" +#include "nsIAtom.h" +#include "nsFrame.h" +#include "nsHTMLIIDs.h" +#include "nsIPresContext.h" +#include "nsIPresShell.h" +#include "nsBlockFrame.h" +#include "nsStyleConsts.h" +#include "nsHTMLAtoms.h" +#include "nsIHTMLAttributes.h" +#include "nsIStyleContext.h" +#include "nsIFontMetrics.h" + +static NS_DEFINE_IID(kStyleFontSID, NS_STYLEFONT_SID); + +class BRFrame : public nsFrame +{ +public: + BRFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + virtual ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + virtual void GetReflowMetrics(nsIPresContext* aPresContext, + nsReflowMetrics& aMetrics); + +protected: + virtual ~BRFrame(); +}; + +BRFrame::BRFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsFrame(aContent, aIndexInParent, aParentFrame) +{ +} + +BRFrame::~BRFrame() +{ +} + +void BRFrame::GetReflowMetrics(nsIPresContext* aPresContext, nsReflowMetrics& aMetrics) +{ + // We have no width, but we're the height of the default font + nsStyleFont* font = + (nsStyleFont*)mStyleContext->GetData(kStyleFontSID); + nsIFontMetrics* fm = aPresContext->GetMetricsFor(font->mFont); + aMetrics.width = 0; + aMetrics.height = fm->GetHeight(); + aMetrics.ascent = fm->GetMaxAscent(); + aMetrics.descent = fm->GetMaxDescent(); + NS_RELEASE(fm); +} + +nsIFrame::ReflowStatus +BRFrame::ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ + // Get cached state for containing block frame + nsBlockReflowState* state = nsnull; + nsIFrame* parent = mGeometricParent; + while (nsnull != parent) { + nsIHTMLFrameType* ft; + nsresult status = parent->QueryInterface(kIHTMLFrameTypeIID, (void**) &ft); + if (NS_OK == status) { + nsHTMLFrameType type = ft->GetFrameType(); + if (eHTMLFrame_Block == type) { + break; + } + } + parent = parent->GetGeometricParent(); + } + if (nsnull != parent) { + nsIPresShell* shell = aPresContext->GetShell(); + state = (nsBlockReflowState*) shell->GetCachedData(parent); + NS_RELEASE(shell); + } + if (nsnull != state) { + // XXX
+ state->breakAfterChild = PR_TRUE; + } + + GetReflowMetrics(aPresContext, aDesiredSize); + return frComplete; +} + +//---------------------------------------------------------------------- + +class BRPart : public nsHTMLTagContent { +public: + BRPart(nsIAtom* aTag); + + virtual void SetAttribute(nsIAtom* aAttribute, const nsString& aValue); + + virtual nsContentAttr GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aResult) const; + + virtual void UnsetAttribute(nsIAtom* aAttribute); + + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + PRInt32 GetClear() { + return mClear; + } + + void SetClear(PRInt32 aValue) { + mClear = aValue; + } + +protected: + virtual ~BRPart(); + virtual nsContentAttr AttributeToString(nsIAtom* aAttribute, + nsHTMLValue& aValue, + nsString& aResult) const; + + PRInt32 mClear; +}; + +BRPart::BRPart(nsIAtom* aTag) + : nsHTMLTagContent(aTag) +{ +} + +BRPart::~BRPart() +{ +} + +nsIFrame* BRPart::CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + nsIFrame* rv = new BRFrame(this, aIndexInParent, aParentFrame); + return rv; +} + +//---------------------------------------------------------------------- +// Attributes + +static nsHTMLTagContent::EnumTable kClearTable[] = { + { "left", NS_STYLE_CLEAR_LEFT }, + { "right", NS_STYLE_CLEAR_RIGHT }, + { "all", NS_STYLE_CLEAR_BOTH }, + { "both", NS_STYLE_CLEAR_BOTH }, + { 0 } +}; + +void BRPart::SetAttribute(nsIAtom* aAttribute, const nsString& aString) +{ + if (aAttribute == nsHTMLAtoms::clear) { + nsHTMLValue value; + if (ParseEnumValue(aString, kClearTable, value)) { + mClear = value.GetIntValue(); + } + else { + mClear = NS_STYLE_CLEAR_NONE; + } + return; + } + nsHTMLTagContent::SetAttribute(aAttribute, aString); +} + +nsContentAttr BRPart::GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aResult) const +{ + nsContentAttr ca = eContentAttr_NotThere; + if (aAttribute == nsHTMLAtoms::clear) { + aResult.Reset(); + if (NS_STYLE_CLEAR_NONE != mClear) { + aResult.Set(mClear, eHTMLUnit_Enumerated); + ca = eContentAttr_HasValue; + } + } + else { + ca = nsHTMLTagContent::GetAttribute(aAttribute, aResult); + } + return ca; +} + +void BRPart::UnsetAttribute(nsIAtom* aAttribute) +{ + if (aAttribute == nsHTMLAtoms::clear) { + mClear = NS_STYLE_CLEAR_NONE; + } +} + +nsContentAttr BRPart::AttributeToString(nsIAtom* aAttribute, + nsHTMLValue& aValue, + nsString& aResult) const +{ + if (aAttribute == nsHTMLAtoms::clear) { + if ((eHTMLUnit_Enumerated == aValue.GetUnit()) && + (NS_STYLE_CLEAR_NONE != aValue.GetIntValue())) { + EnumValueToString(aValue, kClearTable, aResult); + return eContentAttr_HasValue; + } + } + return eContentAttr_NotThere; +} + +//---------------------------------------------------------------------- + +nsresult +NS_NewHTMLBreak(nsIHTMLContent** aInstancePtrResult, nsIAtom* aTag) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIHTMLContent* it = new BRPart(aTag); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIHTMLContentIID, (void**) aInstancePtrResult); +} diff --git a/mozilla/layout/html/base/src/nsBlockFrame.cpp b/mozilla/layout/html/base/src/nsBlockFrame.cpp new file mode 100644 index 00000000000..de26654f45d --- /dev/null +++ b/mozilla/layout/html/base/src/nsBlockFrame.cpp @@ -0,0 +1,2030 @@ +/* -*- 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 "nsBlockFrame.h" +#include "nsSize.h" +#include "nsIAnchoredItems.h" +#include "nsIContent.h" +#include "nsIContentDelegate.h" +#include "nsISpaceManager.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsIPresContext.h" +#include "nsMargin.h" +#include "nsHTMLIIDs.h" +#include "nsCSSLayout.h" +#include "nsCRT.h" +#include "nsIPresShell.h" +#include "nsReflowCommand.h" +#include "nsPlaceholderFrame.h" +#include "nsHTMLAtoms.h" +#include "nsHTMLValue.h" +#include "nsIHTMLContent.h" + +#ifdef NS_DEBUG +#undef NOISY +#undef NOISY_FLOW +#else +#undef NOISY +#undef NOISY_FLOW +#endif + +static NS_DEFINE_IID(kIRunaroundIID, NS_IRUNAROUND_IID); +static NS_DEFINE_IID(kIFloaterContainerIID, NS_IFLOATERCONTAINER_IID); +static NS_DEFINE_IID(kIAnchoredItemsIID, NS_IANCHOREDITEMS_IID); +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); +static NS_DEFINE_IID(kStyleFontSID, NS_STYLEFONT_SID); + +struct BlockBandData : public nsBandData { + nsRect data[5]; + + BlockBandData() {size = 5; rects = data;} +}; + +// XXX Bugs +// 1. right to left reflow can generate negative x coordinates. + +// XXX Speedup idea (all containers) + +// If I reflow a child and it gives back not-complete status then +// there is no sense in trying to pullup children. For blocks, it's a +// little more complicated unless the child is a block - if the child +// is a block, then we must be out of room hence we should stop. If +// the child is not a block then our line should be flushed (see #2 +// below) if our line is already empty then we must be out of room. + +// For inline frames and column frames, if we reflow a child and get +// back not-complete status then we should bail immediately because we +// are out of room. + +// XXX Speedup ideas: +// 1. change pullup code to use line information from next in flow +// 2. we can advance to next line immediately after reflowing something +// and noticing that it's not complete. +// 3. pass down last child information in aState so that pullup, etc., +// don't need to recompute it + +// XXX TODO: +// 0. Move justification into line flushing code + +// 1. To get ebina margins I need "auto" information from the style +// system margin's. A bottom/top margin of auto will then be computed like +// ebina computes it [however the heck that is]. + +// 2. kicking out floaters and talking with floater container to adjust +// left and right margins + +nsBlockReflowState::nsBlockReflowState() +{ +} + +void nsBlockReflowState::Init(const nsSize& aMaxSize, + nsSize* aMaxElementSize, + nsStyleFont* aFont, + nsStyleMolecule* aMol, + nsISpaceManager* aSpaceManager) +{ + firstLine = PR_TRUE; + allowLeadingWhitespace = PR_FALSE; + breakAfterChild = PR_FALSE; + breakBeforeChild = PR_FALSE; + firstChildIsInsideBullet = PR_FALSE; + nextListOrdinal = -1; + column = 0; + + spaceManager = aSpaceManager; + currentBand = new BlockBandData; + font = aFont; + mol = aMol; + availSize.width = aMaxSize.width; + availSize.height = aMaxSize.height; + maxElementSize = aMaxElementSize; + if (nsnull != aMaxElementSize) { + aMaxElementSize->width = 0; + aMaxElementSize->height = 0; + } + + kidXMost = 0; + x = 0; + y = 0; + + isInline = PR_FALSE; + currentLineNumber = 0; + lineStart = nsnull; + lineLength = 0; + ascents = ascentBuf; + maxAscent = 0; + maxDescent = 0; + lineWidth = 0; + maxPosBottomMargin = 0; + maxNegBottomMargin = 0; + lineMaxElementSize.width = 0; + lineMaxElementSize.height = 0; + lastContentIsComplete = PR_TRUE; + + maxAscents = sizeof(ascentBuf) / sizeof(ascentBuf[0]); + needRelativePos = PR_FALSE; + + prevLineLastFrame = nsnull; + prevLineHeight = 0; + topMargin = 0; + prevMaxPosBottomMargin = 0; + prevMaxNegBottomMargin = 0; + prevLineLastContentIsComplete = PR_TRUE; + + unconstrainedWidth = PRBool(aMaxSize.width == NS_UNCONSTRAINEDSIZE); + unconstrainedHeight = PRBool(aMaxSize.height == NS_UNCONSTRAINEDSIZE); + + justifying = (NS_STYLE_TEXT_ALIGN_JUSTIFY == mol->textAlign) && + (NS_STYLE_WHITESPACE_PRE != mol->whiteSpace); + reflowStatus = nsIFrame::frNotComplete; +} + +nsBlockReflowState::~nsBlockReflowState() +{ + if (ascents != ascentBuf) { + delete ascents; + } + delete currentBand; +} + +void nsBlockReflowState::AddAscent(nscoord aAscent) +{ + NS_PRECONDITION(lineLength <= maxAscents, "bad line length"); + if (lineLength == maxAscents) { + maxAscents *= 2; + nscoord* newAscents = new nscoord[maxAscents]; + if (nsnull != newAscents) { + nsCRT::memcpy(newAscents, ascents, sizeof(nscoord) * lineLength); + if (ascents != ascentBuf) { + delete ascents; + } + ascents = newAscents; + } else { + // Yikes! Out of memory! + return; + } + } + ascents[lineLength] = aAscent; +} + +void nsBlockReflowState::AdvanceToNextLine(nsIFrame* aPrevLineLastFrame, + nscoord aPrevLineHeight) +{ + firstLine = PR_FALSE; + allowLeadingWhitespace = PR_FALSE; + column = 0; + breakAfterChild = PR_FALSE; + breakBeforeChild = PR_FALSE; + lineStart = nsnull; + lineLength = 0; + currentLineNumber++; + maxAscent = 0; + maxDescent = 0; + lineWidth = 0; + needRelativePos = PR_FALSE; + + prevLineLastFrame = aPrevLineLastFrame; + prevLineHeight = aPrevLineHeight; + prevMaxPosBottomMargin = maxPosBottomMargin; + prevMaxNegBottomMargin = maxNegBottomMargin; + + // Remember previous line's lastContentIsComplete + prevLineLastContentIsComplete = lastContentIsComplete; + lastContentIsComplete = PR_TRUE; + + topMargin = 0; + maxPosBottomMargin = 0; + maxNegBottomMargin = 0; +} + +#ifdef NS_DEBUG +void nsBlockReflowState::DumpLine() +{ + nsIFrame* f = lineStart; + PRInt32 ll = lineLength; + while (--ll >= 0) { + printf(" "); + ((nsFrame*)f)->ListTag(stdout);/* XXX */ + printf("\n"); + f = f->GetNextSibling(); + } +} + +void nsBlockReflowState::DumpList() +{ + nsIFrame* f = lineStart; + while (nsnull != f) { + printf(" "); + ((nsFrame*)f)->ListTag(stdout);/* XXX */ + printf("\n"); + f = f->GetNextSibling(); + } +} +#endif + +//---------------------------------------------------------------------- + +nsresult nsBlockFrame::NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIFrame* it = new nsBlockFrame(aContent, aIndexInParent, aParent); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aInstancePtrResult = it; + return NS_OK; +} + +nsBlockFrame::nsBlockFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) + : nsHTMLContainerFrame(aContent, aIndexInParent, aParent) +{ +} + +nsBlockFrame::~nsBlockFrame() +{ + if (nsnull != mLines) { + delete mLines; + } +} + +nsresult +nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) +{ + NS_PRECONDITION(0 != aInstancePtr, "null ptr"); + if (NULL == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kIHTMLFrameTypeIID)) { + *aInstancePtr = (void*) ((nsIHTMLFrameType*) this); + return NS_OK; + } else if (aIID.Equals(kIRunaroundIID)) { + *aInstancePtr = (void*) ((nsIRunaround*) this); + return NS_OK; + } else if (aIID.Equals(kIFloaterContainerIID)) { + *aInstancePtr = (void*) ((nsIFloaterContainer*) this); + return NS_OK; + } + return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr); +} + +// Computes the top margin to use for this child frames based on its display +// type and the display type of the previous child frame. +// +// Adjacent vertical margins between block-level elements are collapsed. +nscoord nsBlockFrame::GetTopMarginFor(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsStyleMolecule* aKidMol, + PRBool aIsInline) +{ + if (aIsInline) { + // Just use whatever the previous bottom margin was + return aState.prevMaxPosBottomMargin - aState.prevMaxNegBottomMargin; + } else { + nscoord maxNegTopMargin = 0; + nscoord maxPosTopMargin = 0; + if (aKidMol->margin.top < 0) { + maxNegTopMargin = -aKidMol->margin.top; + } else { + maxPosTopMargin = aKidMol->margin.top; + } + + nscoord maxPos = PR_MAX(aState.prevMaxPosBottomMargin, maxPosTopMargin); + nscoord maxNeg = PR_MAX(aState.prevMaxNegBottomMargin, maxNegTopMargin); + return maxPos - maxNeg; + } +} + +void nsBlockFrame::PlaceBelowCurrentLineFloaters(nsIPresContext* aCX, + nsBlockReflowState& aState, + nscoord aY) +{ + NS_PRECONDITION(aState.floaterToDo.Count() > 0, "no floaters"); + + // XXX Factor this code with PlaceFloater()... + PRInt32 numFloaters = aState.floaterToDo.Count(); + + for (PRInt32 i = 0; i < numFloaters; i++) { + nsIFrame* floater = (nsIFrame*)aState.floaterToDo[i]; + nsRect region; + + // Get the band of available space + // XXX This is inefficient to do this inside the loop... + GetAvailableSpaceBand(aState, aY); + + // Get the type of floater + nsIStyleContext* styleContext = floater->GetStyleContext(aCX); + nsStyleMolecule* mol = (nsStyleMolecule*)styleContext->GetData(kStyleMoleculeSID); + NS_RELEASE(styleContext); + + floater->GetRect(region); + region.y = mCurrentState->currentBand->rects[0].y; + + if (NS_STYLE_FLOAT_LEFT == mol->floats) { + region.x = mCurrentState->currentBand->rects[0].x; + } else { + NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == mol->floats, "bad float type"); + region.x = mCurrentState->currentBand->rects[0].XMost() - region.width; + } + + // XXX Don't forget the floater's margins... + mCurrentState->spaceManager->Translate(mCurrentState->borderPadding.left, 0); + mCurrentState->spaceManager->AddRectRegion(region); + + // Set the origin of the floater in world coordinates + nscoord worldX, worldY; + + mCurrentState->spaceManager->GetTranslation(worldX, worldY); + floater->MoveTo(region.x + worldX, region.y + worldY); + mCurrentState->spaceManager->Translate(-mCurrentState->borderPadding.left, 0); + } + aState.floaterToDo.Clear(); +} + +/** + * Flush a line out. Return true if the line fits in our available + * height. If the line does not fit then return false. When the line + * fits we advance the y coordinate, reset the x coordinate and + * prepare the nsBlockReflowState for the next line. + */ +PRBool nsBlockFrame::AdvanceToNextLine(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ + NS_PRECONDITION(aState.lineLength > 0, "bad line"); + NS_PRECONDITION(nsnull != aState.lineStart, "bad line"); + + nscoord y = aState.y + aState.topMargin; + nscoord lineHeight; + + if (aState.isInline) { + // Vertically align the children on this line, returning the height of + // the line upon completion. + lineHeight = nsCSSLayout::VerticallyAlignChildren(aCX, this, aState.font, y, + aState.lineStart, aState.lineLength, + aState.ascents, aState.maxAscent); + + // Any below current line floaters to place? + if (aState.floaterToDo.Count() > 0) { + PlaceBelowCurrentLineFloaters(aCX, aState, y + lineHeight); + // XXX Factor in the height of the floaters as well when considering + // whether the line fits. + // The default policy is that if there isn't room for the floaters then + // both the line and the floaters are pushed to the next-in-flow... + } + } else { + lineHeight = aState.lineStart->GetHeight(); + } + + // The first line always fits + if (aState.currentLineNumber > 0) { + nscoord yb = aState.borderPadding.top + aState.availSize.height; + if (y + lineHeight > yb) { + // After vertical alignment of the children and factoring in the + // proper margin, the line doesn't fit. + return PR_FALSE; + } + } + + if (aState.isInline) { + // Check if the right-edge of the line exceeds our running x-most + nscoord xMost = aState.borderPadding.left + aState.lineWidth; + if (xMost > aState.kidXMost) { + aState.kidXMost = xMost; + } + } + + // Advance the y coordinate to the new position where the next + // line or block element will go. + aState.y = y + lineHeight; + aState.x = 0; + + // Now that the vertical alignment is done we can perform horizontal + // alignment and relative positioning. Skip all of these if we are + // doing an unconstrained (in x) reflow. There's no point in doing + // the work if we *know* we are going to reflowed again. + if (!aState.unconstrainedWidth) { + nsCSSLayout::HorizontallyPlaceChildren(aCX, this, aState.mol, + aState.lineStart, aState.lineLength, + aState.lineWidth, + aState.availSize.width); + + // Finally, now that the in-flow positions of the line's frames are + // known we can apply relative positioning if any of them need it. + if (!aState.justifying) { + nsCSSLayout::RelativePositionChildren(aCX, this, aState.mol, + aState.lineStart, + aState.lineLength); + } + } + + // Record line length + aState.lineLengths.AppendElement((void*)aState.lineLength); + + // Find the last frame in the line + // XXX keep this as running state in the nsBlockReflowState + nsIFrame* lastFrame = aState.lineStart; + PRInt32 lineLen = aState.lineLength - 1; + while (--lineLen >= 0) { + lastFrame = lastFrame->GetNextSibling(); + } + + // Update maxElementSize + if (nsnull != aState.maxElementSize) { + nsSize& lineMax = aState.lineMaxElementSize; + nsSize* maxMax = aState.maxElementSize; + if (lineMax.width > maxMax->width) { + maxMax->width = lineMax.width; + } + if (lineMax.height > maxMax->height) { + maxMax->height = lineMax.height; + } + aState.lineMaxElementSize.width = 0; + aState.lineMaxElementSize.height = 0; + } + + // Advance to the next line + aState.AdvanceToNextLine(lastFrame, lineHeight); + + return PR_TRUE; +} + +/** + * Add an inline child to the current line. Advance various running + * values after placement. + */ +void nsBlockFrame::AddInlineChildToLine(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsIFrame* aKidFrame, + nsReflowMetrics& aKidSize, + nsSize* aKidMaxElementSize, + nsStyleMolecule* aKidMol) +{ + NS_PRECONDITION(nsnull != aState.lineStart, "bad line"); + + PRIntn direction = aState.mol->direction; + if (NS_STYLE_POSITION_RELATIVE == aKidMol->positionFlags) { + aState.needRelativePos = PR_TRUE; + } + + // Place and size the child + // XXX add in left margin from kid + nsRect r; + r.y = aState.y; + r.width = aKidSize.width; + r.height = aKidSize.height; + if (NS_STYLE_DIRECTION_LTR == aState.mol->direction) { + // Left to right positioning. + r.x = aState.borderPadding.left + aState.x + aKidMol->margin.left; + aState.x += aKidSize.width + aKidMol->margin.left + aKidMol->margin.right; + } else { + // Right to left positioning + // XXX what should we do when aState.x goes negative??? + r.x = aState.x - aState.borderPadding.right - aKidMol->margin.right - aKidSize.width; + aState.x -= aKidSize.width + aKidMol->margin.right + aKidMol->margin.left; + } + aKidFrame->SetRect(r); + aState.AddAscent(aKidSize.ascent); + aState.lineWidth += aKidSize.width; + aState.lineLength++; + + // Update maximums for the line + if (aKidSize.ascent > aState.maxAscent) { + aState.maxAscent = aKidSize.ascent; + } + if (aKidSize.descent > aState.maxDescent) { + aState.maxDescent = aKidSize.descent; + } + // Update running margin maximums + if (aState.firstChildIsInsideBullet && (aKidFrame == mFirstChild)) { + // XXX temporary code. Since the molecule for the bullet frame + // is the same as the LI frame, we get bad style information. + // ignore it. + } else { + nscoord margin; +#if 0 + // XXX CSS2 spec says that top/bottom margin don't affect line height + // calculation. We're waiting for clarification on this issue... + if ((margin = aKidMol->margin.top) < 0) { + margin = -margin; + if (margin > aState.maxNegTopMargin) { + aState.maxNegTopMargin = margin; + } + } else { + if (margin > aState.maxPosTopMargin) { + aState.maxPosTopMargin = margin; + } + } +#endif + if ((margin = aKidMol->margin.bottom) < 0) { + margin = -margin; + if (margin > aState.maxNegBottomMargin) { + aState.maxNegBottomMargin = margin; + } + } else { + if (margin > aState.maxPosBottomMargin) { + aState.maxPosBottomMargin = margin; + } + } + } + + // Update line max element size + nsSize& mes = aState.lineMaxElementSize; + if (nsnull != aKidMaxElementSize) { + if (aKidMaxElementSize->width > mes.width) { + mes.width = aKidMaxElementSize->width; + } + if (aKidMaxElementSize->height > mes.height) { + mes.height = aKidMaxElementSize->height; + } + } +} + +// Places and sizes the block-level element, and advances the line. +// The rect is in the local coordinate space of the kid frame. +void nsBlockFrame::AddBlockChild(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsIFrame* aKidFrame, + nsRect& aKidRect, + nsSize* aKidMaxElementSize, + nsStyleMolecule* aKidMol) +{ + NS_PRECONDITION(nsnull != aState.lineStart, "bad line"); + + if (NS_STYLE_POSITION_RELATIVE == aKidMol->positionFlags) { + aState.needRelativePos = PR_TRUE; + } + + // Translate from the kid's coordinate space to our coordinate space + aKidRect.x += aState.borderPadding.left + aKidMol->margin.left; + aKidRect.y += aState.y + aState.topMargin; + + // Place and size the child + aKidFrame->SetRect(aKidRect); + + aState.AddAscent(aKidRect.height); + aState.lineLength++; + + // Is this the widest child frame? + nscoord xMost = aKidRect.XMost() + aKidMol->margin.right; + if (xMost > aState.kidXMost) { + aState.kidXMost = xMost; + } + + // Update the max element size + if (nsnull != aKidMaxElementSize) { + if (aKidMaxElementSize->width > aState.maxElementSize->width) { + aState.maxElementSize->width = aKidMaxElementSize->width; + } + if (aKidMaxElementSize->height > aState.maxElementSize->height) { + aState.maxElementSize->height = aKidMaxElementSize->height; + } + } + + // and the bottom line margin information which we'll use when placing + // the next child + if (aKidMol->margin.bottom < 0) { + aState.maxNegBottomMargin = -aKidMol->margin.bottom; + } else { + aState.maxPosBottomMargin = aKidMol->margin.bottom; + } + + // Update the running y-offset + aState.y += aKidRect.height + aState.topMargin; + + // Apply relative positioning if necessary + nsCSSLayout::RelativePositionChildren(aCX, this, aState.mol, aKidFrame, 1); + + // Advance to the next line + aState.AdvanceToNextLine(aKidFrame, aKidRect.height); +} + +/** + * Compute the available size for reflowing the given child at the + * current x,y position in the state. Note that this may return + * negative or zero width/height's if we are out of room. + */ +void nsBlockFrame::GetAvailSize(nsSize& aResult, + nsBlockReflowState& aState, + nsStyleMolecule* aKidMol, + PRBool aIsInline) +{ + // Determine the maximum available reflow height for the child + nscoord yb = aState.borderPadding.top + aState.availSize.height; + aResult.height = aState.unconstrainedHeight ? NS_UNCONSTRAINEDSIZE : + yb - aState.y - aState.topMargin; + + // Determine the maximum available reflow width for the child + if (aState.unconstrainedWidth) { + aResult.width = NS_UNCONSTRAINEDSIZE; + } else if (aIsInline) { + if (NS_STYLE_DIRECTION_LTR == aState.mol->direction) { + aResult.width = aState.currentBand->rects[0].XMost() - aState.x; + } else { + aResult.width = aState.x - aState.currentBand->rects[0].x; + } + } else { + // It's a block + aResult.width = aState.availSize.width - aKidMol->margin.left - + aKidMol->margin.right; + } +} + +/** + * Push all of the kids that we have not reflowed, starting at + * aState.lineStart. aPrevKid is the kid previous to aState.lineStart + * and is also our last child. Note that line length is NOT a + * reflection of the number of children we are actually pushing + * (because we don't break the sibling list as we add children to the + * line). + */ +void nsBlockFrame::PushKids(nsBlockReflowState& aState) +{ + nsIFrame* prevFrame = aState.prevLineLastFrame; + NS_PRECONDITION(nsnull != prevFrame, "pushing all kids"); + NS_PRECONDITION(prevFrame->GetNextSibling() == aState.lineStart, + "bad prev line"); + +#ifdef NS_DEBUG + PRInt32 numKids = LengthOf(mFirstChild); + NS_ASSERTION(numKids == mChildCount, "bad child count"); +#endif + +#ifdef NOISY + ListTag(stdout); + printf(": push kids (childCount=%d)\n", mChildCount); + DumpFlow(); +#endif + + PushChildren(aState.lineStart, prevFrame, mLastContentIsComplete); + SetLastContentOffset(prevFrame); + + // Set mLastContentIsComplete to the previous lines last content is + // complete now that the previous line's last child is our last + // child. + mLastContentIsComplete = aState.prevLineLastContentIsComplete; + + // Fix up child count + // XXX is there a better way? aState.lineLength doesn't work because + // we might be pushing more than just the pending line. + nsIFrame* kid = mFirstChild; + PRInt32 kids = 0; + while (nsnull != kid) { + kids++; + kid = kid->GetNextSibling(); + } + mChildCount = kids; + + // Make sure we have no lingering line data + aState.lineLength = 0; + aState.lineStart = nsnull; + +#ifdef NOISY + ListTag(stdout); + printf(": push kids done (childCount=%d) [%c]\n", mChildCount, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif +} + +/** + * Gets a band of available space starting at the specified y-offset. Assumes + * the local coordinate space is currently set to the upper-left origin of the + * bounding rect + * + * Updates "currentBand" and "x" member data of the block reflow state + */ +void nsBlockFrame::GetAvailableSpaceBand(nsBlockReflowState& aState, nscoord aY) +{ + // Gets a band of available space. + aState.spaceManager->Translate(aState.borderPadding.left, 0); + aState.spaceManager->GetBandData(aY, aState.availSize, *aState.currentBand); + + // XXX This is hack code that needs to change when the space manager interface + // changes to return both the available and unavailable space + // + // We'll get back anywhere between 1 and 3 rects depending on how many floaters + // there are. Actually the way it currently works we could get back zero rects + // if there are overlapping left and right floaters occupying all the space + if (aState.currentBand->count > 1) { + // If there are three rects then let's assume that there are floaters on the + // left and right and that only the middle rect is available + if (aState.currentBand->count == 3) { + aState.currentBand->rects[0] = aState.currentBand->rects[1]; + } else { + // There are two rects. That means either a left or right floater. Just use + // whichever space is larger. + if (aState.currentBand->rects[1].width > aState.currentBand->rects[0].width) { + aState.currentBand->rects[0] = aState.currentBand->rects[1]; + } + } + } + aState.spaceManager->Translate(-aState.borderPadding.left, 0); + aState.x = aState.currentBand->rects[0].x; +} + +void nsBlockFrame::ClearFloaters(nsBlockReflowState& aState, PRUint32 aClear) +{ + // Translate the coordinate space + aState.spaceManager->Translate(aState.borderPadding.left, 0); + +getBand: + nscoord y = aState.y + aState.topMargin; + PRBool isLeftFloater = PR_FALSE; + PRBool isRightFloater = PR_FALSE; + + // Get a band of available space + aState.spaceManager->GetBandData(y, aState.availSize, *aState.currentBand); + + if (aState.currentBand->count == 1) { + if (aState.currentBand->rects[0].width != aState.availSize.width) { + // Some of the space is taken up by floaters + if (aState.currentBand->rects[0].x > 0) { + isLeftFloater = PR_TRUE; + } + + if (aState.currentBand->rects[0].XMost() < aState.availSize.width) { + isRightFloater = PR_TRUE; + } + } + } else if (aState.currentBand->count == 2) { + if (aState.currentBand->rects[0].width > aState.currentBand->rects[1].width) { + isRightFloater = PR_TRUE; + } else { + isLeftFloater = PR_TRUE; + + // There may also be a right floater + if (aState.currentBand->rects[1].XMost() < aState.availSize.width) { + isRightFloater = PR_TRUE; + } + } + } else { + // Must be both left and right floaters + isLeftFloater = PR_TRUE; + isRightFloater = PR_TRUE; + } + + if (isLeftFloater) { + if ((aClear == NS_STYLE_CLEAR_LEFT) || (aClear == NS_STYLE_CLEAR_BOTH)) { + aState.y += aState.currentBand->rects[0].height; + goto getBand; + } + } + if (isRightFloater) { + if ((aClear == NS_STYLE_CLEAR_RIGHT) || (aClear == NS_STYLE_CLEAR_BOTH)) { + aState.y += aState.currentBand->rects[0].height; + goto getBand; + } + } + + aState.spaceManager->Translate(-aState.borderPadding.left, 0); +} + +// Bit's for PlaceAndReflowChild return value +#define PLACE_FIT 0x1 +#define PLACE_FLOWED 0x2 + +PRIntn +nsBlockFrame::PlaceAndReflowChild(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsIFrame* kidFrame, + nsStyleMolecule* aKidMol) +{ + nsSize kidMaxElementSize; + nsSize* pKidMaxElementSize = + (nsnull != aState.maxElementSize) ? &kidMaxElementSize : nsnull; + + // Get line start setup if we are at the start of a new line + if (nsnull == aState.lineStart) { + NS_ASSERTION(0 == aState.lineLength, "bad line length"); + aState.lineStart = kidFrame; + } + + // Get kid and its style + // XXX How is this any different than what was passed in to us as aKidMol? + nsIContent* kid = kidFrame->GetContent(); + nsIStyleContext* kidSC = kidFrame->GetStyleContext(aCX); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + NS_RELEASE(kid); + + // Figure out if kid is a block element or not + PRBool isInline = PR_TRUE; + PRIntn display = kidMol->display; + if (aState.firstChildIsInsideBullet && (mFirstChild == kidFrame)) { + // XXX Special hack for properly reflowing bullets that have the + // inside value for list-style-position. + display = NS_STYLE_DISPLAY_INLINE; + } + if ((NS_STYLE_DISPLAY_BLOCK == display) || + (NS_STYLE_DISPLAY_LIST_ITEM == display)) { + // Block elements always end up on the next line (unless they are + // already at the start of the line). + isInline = PR_FALSE; + if (aState.lineLength > 0) { + aState.breakAfterChild = PR_TRUE; + } + } + + // Handle forced break first + if (aState.breakAfterChild) { + NS_ASSERTION(aState.lineStart != kidFrame, "bad line"); + + // Get the last child in the current line + nsIFrame* lastFrame = aState.lineStart; + PRInt32 lineLen = aState.lineLength - 1; + while (--lineLen >= 0) { + lastFrame = lastFrame->GetNextSibling(); + } + + if (!AdvanceToNextLine(aCX, aState)) { + // The previous line didn't fit. + return 0; + } + aState.lineStart = kidFrame; + + // Get the style for the last child, and see if it wanted to clear floaters. + // This handles the BR tag, which is the only inline element for which clear + // applies + nsIStyleContext* lastChildSC = lastFrame->GetStyleContext(aCX); + nsStyleMolecule* lastChildMol = (nsStyleMolecule*)lastChildSC->GetData(kStyleMoleculeSID); + if (lastChildMol->clear != NS_STYLE_CLEAR_NONE) { + ClearFloaters(aState, lastChildMol->clear); + } + NS_RELEASE(lastChildSC); + } + + // Now that we've handled force breaks (and maybe called AdvanceToNextLine() + // which checks), remember whether it's an inline frame + aState.isInline = isInline; + + // If we're at the beginning of a line then compute the top margin that we + // should use + if (aState.lineStart == kidFrame) { + // Compute the top margin to use for this line + aState.topMargin = GetTopMarginFor(aCX, aState, kidMol, aState.isInline); + + // If it's an inline element then get a band of available space + // + // XXX If we have a current band and there's unused space in that band + // then avoid this call to get a band... + if (aState.isInline) { + GetAvailableSpaceBand(aState, aState.y + aState.topMargin); + } + } + + // Compute the available space to reflow the child into and then + // reflow it into that space. + nsSize kidAvailSize; + GetAvailSize(kidAvailSize, aState, kidMol, aState.isInline); + if ((aState.currentLineNumber > 0) && (kidAvailSize.height <= 0)) { + // No more room + return 0; + } + + ReflowStatus status; + + if (aState.isInline) { + nsReflowMetrics kidSize; + + // Inline elements are never passed the space manager + status = ReflowChild(kidFrame, aCX, kidSize, kidAvailSize, + pKidMaxElementSize); + + // For first children, we skip all the fit checks because we must + // fit at least one child for a parent to figure what to do with us. + if ((aState.currentLineNumber > 0) || (aState.lineLength > 0)) { + NS_ASSERTION(nsnull != aState.lineStart, "bad line start"); + + if (kidFrame == aState.lineStart) { + // Width always fits when we are at the logical left margin. + // Just check the height. + // + // XXX This height check isn't correct now that we have bands of + // available space... + if (kidSize.height > kidAvailSize.height) { + // It's too tall + return PLACE_FLOWED; + } + } else { + // Examine state and if the breakBeforeChild is set and we + // aren't already on the new line, do the forcing now. + // XXX Why aren't we doing this check BEFORE we resize reflow the child? + if (aState.breakBeforeChild) { + aState.breakBeforeChild = PR_FALSE; + if (kidFrame != aState.lineStart) { + if (!AdvanceToNextLine(aCX, aState)) { + // Flushing out the line failed. + return PLACE_FLOWED; + } + aState.lineStart = kidFrame; + + // Get a band of available space + GetAvailableSpaceBand(aState, aState.y + aState.topMargin); + + // Reflow child now that it has the line to itself + GetAvailSize(kidAvailSize, aState, kidMol, PR_TRUE); + status = ReflowChild(kidFrame, aCX, kidSize, kidAvailSize, + pKidMaxElementSize); + } + } + + // When we are not at the logical left margin then we need + // to check the width first. If we are too wide then advance + // to the next line and try reflowing again. + if (kidSize.width > kidAvailSize.width) { + // Too wide. Try next line + if (!AdvanceToNextLine(aCX, aState)) { + // Flushing out the line failed. + return PLACE_FLOWED; + } + aState.lineStart = kidFrame; + + // Get a band of available space + GetAvailableSpaceBand(aState, aState.y + aState.topMargin); + + // Reflow splittable children + if (kidFrame->IsSplittable()) { + // Update size info now that we are on the next line. Then + // reflow the child into the new available space. + GetAvailSize(kidAvailSize, aState, kidMol, PR_TRUE); + status = ReflowChild(kidFrame, aCX, kidSize, kidAvailSize, + pKidMaxElementSize); + + // If we just reflowed our last child then update the + // mLastContentIsComplete state. + if (nsnull == kidFrame->GetNextSibling()) { + // Use state from the reflow we just did + mLastContentIsComplete = PRBool(status == frComplete); + } + } + + // XXX This height check isn't correct now that we have bands of + // available space... + if (kidSize.height > kidAvailSize.height) { + // It's too tall on the next line + return PLACE_FLOWED; + } + // It's ok if it's too wide on the next line. + } + } + } + + // Add child to the line + AddInlineChildToLine(aCX, aState, kidFrame, kidSize, pKidMaxElementSize, kidMol); + + } else { + nsRect kidRect; + + // Does the block-level element want to clear any floaters that impact + // it? Note that the clear property only applies to block-level elements + // and the BR tag + if (aKidMol->clear != NS_STYLE_CLEAR_NONE) { + ClearFloaters(aState, aKidMol->clear); + GetAvailSize(kidAvailSize, aState, kidMol, PR_FALSE); + if ((aState.currentLineNumber > 0) && (kidAvailSize.height <= 0)) { + // No more room + return 0; + } + } + + // Give the block its own local coordinate space. + // + // XXX This is wrong to have the parent try and account for the kid's + // left margin here, because we have to wait until we know what the + // left edge is and that means resolving any floaters that impact the + // block. If the kid wants to interact with the space manager then it + // will have to deal with left/right margins itself + nscoord tx = aState.borderPadding.left + aKidMol->margin.left; + nscoord ty = aState.y + aState.topMargin; + + // Give the block-level element the opportunity to use the space manager + aState.spaceManager->Translate(tx, ty); + status = ReflowChild(kidFrame, aCX, aState.spaceManager, kidAvailSize, + kidRect, pKidMaxElementSize); + aState.spaceManager->Translate(-tx, -ty); + + // For first children, we skip all the fit checks because we must + // fit at least one child for a parent to figure what to do with us. + if ((aState.currentLineNumber > 0) || (aState.lineLength > 0)) { + // Block elements always fit horizontally (because they are + // always placed at the logical left margin). Check to see if + // the block fits vertically + if (kidRect.YMost() > kidAvailSize.height) { + // Nope + return PLACE_FLOWED; + } + } + + // Add block child + AddBlockChild(aCX, aState, kidFrame, kidRect, pKidMaxElementSize, kidMol); + } + + // If we just reflowed our last child then update the + // mLastContentIsComplete state. + if (nsnull == kidFrame->GetNextSibling()) { + // Use state from the reflow we just did + mLastContentIsComplete = PRBool(status == frComplete); + } + + aState.lastContentIsComplete = PRBool(status == frComplete); + if (aState.isInline && (frNotComplete == status)) { + // Since the inline child didn't complete its reflow we *know* + // that a continuation of it can't possibly fit on the current + // line. Therefore, set a flag in the state that will cause the + // a line break before the next frame is placed. + aState.breakAfterChild = PR_TRUE; + } + NS_RELEASE(kidSC); + + aState.reflowStatus = status; + return PLACE_FLOWED | PLACE_FIT; +} + +/** + * Reflow the existing frames. + * + * @param aCX presentation context to use + * @param aState in out parameter which tracks the state of + * reflow for the block frame. + * @return true if we successfully reflowed all the mapped children and false + * otherwise, e.g. we pushed children to the next in flow + */ +PRBool +nsBlockFrame::ReflowMappedChildren(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": reflow mapped (childCount=%d) [%d,%d,%c]\n", + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif + + PRBool result = PR_TRUE; + nsIFrame* kidFrame; + nsIFrame* prevKidFrame = nsnull; + + for (kidFrame = mFirstChild; nsnull != kidFrame; ) { + nsIContent* kid = kidFrame->GetContent(); + nsIStyleContext* kidSC = aCX->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + NS_RELEASE(kid); + + // Attempt to place and reflow the child + + // XXX if child is not splittable and it fits just place it where + // it is, otherwise advance to the next line and place it there if + // possible + + PRIntn placeStatus = PlaceAndReflowChild(aCX, aState, kidFrame, kidMol); + ReflowStatus status = aState.reflowStatus; + NS_RELEASE(kidSC); + if (0 == (placeStatus & PLACE_FIT)) { + // The child doesn't fit. Push it and any remaining children. + PushKids(aState); + result = PR_FALSE; + goto push_done; + } + + // Is the child complete? + if (frComplete == status) { + // Yes, the child is complete + NS_ASSERTION(nsnull == kidFrame->GetNextInFlow(), "bad child flow list"); + } else { + // No the child isn't complete + nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); + if (nsnull == kidNextInFlow) { + // The child doesn't have a next-in-flow so create a continuing + // frame. This hooks the child into the flow + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aCX, this); + NS_ASSERTION(nsnull != continuingFrame, "frame creation failed"); + + // Add the continuing frame to the sibling list + nsIFrame* nextSib = kidFrame->GetNextSibling(); + continuingFrame->SetNextSibling(nextSib); + kidFrame->SetNextSibling(continuingFrame); + mChildCount++; + } + + // Unlike the inline frame code we can't assume that we used + // up all of our space because the child's reflow status is + // frNotComplete. Instead, the child is probably split and + // we need to reflow the continuations as well. + } + + // Get the next child frame + prevKidFrame = kidFrame; + kidFrame = kidFrame->GetNextSibling(); + } + + push_done:; + // Update the child count member data + NS_POSTCONDITION(LastChild()->GetIndexInParent() == mLastContentOffset, "bad last content offset"); + +#ifdef NS_DEBUG + PRInt32 len = LengthOf(mFirstChild); + NS_POSTCONDITION(len == mChildCount, "bad child count"); + VerifyLastIsComplete(); +#endif + +#ifdef NOISY + ListTag(stdout); + printf(": reflow mapped %sok (childCount=%d) [%d,%d,%c]\n", + (result ? "" : "NOT "), + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif + return result; +} + +PRBool nsBlockFrame::MoreToReflow(nsIPresContext* aCX) +{ + PRBool rv = PR_FALSE; + if (IsPseudoFrame()) { + // Get the next content object that we would like to reflow + PRInt32 kidIndex = NextChildOffset(); + nsIContent* kid = mContent->ChildAt(kidIndex); + if (nsnull != kid) { + // Resolve style for the kid + nsIStyleContext* kidSC = aCX->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + switch (kidMol->display) { + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + // Block pseudo-frames do not contain other block elements + break; + + default: + rv = PR_TRUE; + break; + } + NS_RELEASE(kidSC); + NS_RELEASE(kid); + } + } else { + if (NextChildOffset() < mContent->ChildCount()) { + rv = PR_TRUE; + } + } + return rv; +} + +/** + * Create new frames for content we haven't yet mapped + * + * @param aCX presentation context to use + * @return frComplete if all content has been mapped and frNotComplete + * if we should be continued + */ +nsIFrame::ReflowStatus +nsBlockFrame::ReflowAppendedChildren(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif + nsIFrame* kidPrevInFlow = nsnull; + ReflowStatus result = frNotComplete; + + // If we have no children and we have a prev-in-flow then we need to pick + // up where it left off. If we have children, e.g. we're being resized, then + // our content offset should already be set correctly... + if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) { + nsBlockFrame* prev = (nsBlockFrame*) mPrevInFlow; + NS_ASSERTION(prev->mLastContentOffset >= prev->mFirstContentOffset, "bad prevInFlow"); + mFirstContentOffset = prev->NextChildOffset(); + if (PR_FALSE == prev->mLastContentIsComplete) { + // Our prev-in-flow's last child is not complete + kidPrevInFlow = prev->LastChild(); + } + } + + // Place our children, one at a time until we are out of children + PRInt32 kidIndex = NextChildOffset(); + nsIFrame* prevKidFrame = LastChild(); + nsIFrame* kidFrame = nsnull; + for (;;) { + // Get the next content object + nsIContent* kid = mContent->ChildAt(kidIndex); + if (nsnull == kid) { + result = frComplete; + break; + } + + // Resolve style for the kid + nsIStyleContext* kidSC = aCX->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + + // Is it a floater? + if (kidMol->floats != NS_STYLE_FLOAT_NONE) { + PlaceholderFrame::NewFrame(&kidFrame, kid, kidIndex, this); + kidFrame->SetStyleContext(kidSC); + } else if (nsnull == kidPrevInFlow) { + // Create initial frame for the child + nsIContentDelegate* kidDel; + nsresult fr; + switch (kidMol->display) { + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + // Pseudo block frames do not contain other block elements + // unless the block element would be the first child. + if (IsPseudoFrame()) { + // If we're being used as a pseudo frame, i.e. we map the same + // content as our parent then we want to indicate we're complete; + // otherwise we'll be continued and go on mapping children... + + // It better be true that we are not being asked to flow a + // block element as our first child. That means the body + // decided it needed a pseudo-frame when it shouldn't have. + NS_ASSERTION(nsnull != mFirstChild, "bad body"); + + NS_RELEASE(kidSC); + NS_RELEASE(kid); + result = frComplete; + goto done; + } + // FALL THROUGH (and create frame) + + case NS_STYLE_DISPLAY_INLINE: + kidDel = kid->GetDelegate(aCX); + kidFrame = kidDel->CreateFrame(aCX, kid, kidIndex, this); + NS_RELEASE(kidDel); + break; + + default: + NS_ASSERTION(nsnull == kidPrevInFlow, "bad prev in flow"); + fr = nsFrame::NewFrame(&kidFrame, kid, kidIndex, this); + break; + } + kidFrame->SetStyleContext(kidSC); + } else { + // Since kid has a prev-in-flow, use that to create the next + // frame. + kidFrame = kidPrevInFlow->CreateContinuingFrame(aCX, this); + } + + // Link child frame into the list of children. If the frame ends + // up not fitting and getting pushed, the PushKids code will fixup + // the child count for us. + if (nsnull != prevKidFrame) { + NS_ASSERTION(nsnull == prevKidFrame->GetNextSibling(), "bad append"); + prevKidFrame->SetNextSibling(kidFrame); + } else { + NS_ASSERTION(nsnull == mFirstChild, "bad create"); + mFirstChild = kidFrame; + SetFirstContentOffset(kidFrame); + } + prevKidFrame = kidFrame; + mChildCount++; + + // Reflow child frame as many times as necessary until it is + // complete. + ReflowStatus status; + do { + PRIntn placeStatus = PlaceAndReflowChild(aCX, aState, kidFrame, kidMol); + status = aState.reflowStatus; + if (0 == (placeStatus & PLACE_FIT)) { + // We ran out of room. + mLastContentIsComplete = PRBool(nsnull == kidFrame->GetNextInFlow()); + PushKids(aState); + + NS_RELEASE(kid); + NS_RELEASE(kidSC); + goto push_done; + } + + // Did the child complete? + prevKidFrame = kidFrame; + if (frNotComplete == status) { + // Child didn't complete so create a continuing frame + kidPrevInFlow = kidFrame; + nsIFrame* continuingFrame = kidFrame->CreateContinuingFrame(aCX, this); + + // Add the continuing frame to the sibling list + continuingFrame->SetNextSibling(kidFrame->GetNextSibling()); + kidFrame->SetNextSibling(continuingFrame); + kidFrame = continuingFrame; + mChildCount++; + + // Switch to new kid style + NS_RELEASE(kidSC); + kidSC = kidFrame->GetStyleContext(aCX); + kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + } + NS_ASSERTION(nsnull == kidFrame->GetNextInFlow(), "huh?"); + } while (frNotComplete == status); + NS_RELEASE(kid); + NS_RELEASE(kidSC); + + // The child that we just reflowed is complete + NS_ASSERTION(nsnull == kidFrame->GetNextInFlow(), "bad child flow list"); + kidIndex++; + kidPrevInFlow = nsnull; + } + + done: + // To get here we either completely reflowed all our appended + // children OR we are a pseudo-frame and we ran into a block + // element. In either case our last content MUST be complete. + NS_ASSERTION(PR_TRUE == aState.lastContentIsComplete, "bad state"); + + NS_ASSERTION(LastChild() == prevKidFrame, "bad last child"); + SetLastContentOffset(prevKidFrame); + + push_done: +#ifdef NS_DEBUG + PRInt32 len = LengthOf(mFirstChild); + NS_ASSERTION(len == mChildCount, "bad child count"); + VerifyLastIsComplete(); +#endif + return result; +} + +/** + * Pullup frames from our next in flow and try to place them. Before + * this is called our previously mapped children, if any have been + * reflowed which means that the block reflow state's x and y + * coordinates and other data are ready to go. + * + * Return true if we pulled everything up. + */ +PRBool +nsBlockFrame::PullUpChildren(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": pullup (childCount=%d) [%d,%d,%c]\n", + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif + + PRBool result = PR_TRUE; + nsBlockFrame* nextInFlow = (nsBlockFrame*) mNextInFlow; + nsIFrame* prevKidFrame = LastChild(); + while (nsnull != nextInFlow) { + // Get first available frame from the next-in-flow + nsIFrame* kidFrame = PullUpOneChild(nextInFlow, prevKidFrame); + if (nsnull == kidFrame) { + // We've pulled up all the children from that next-in-flow, so + // move to the next next-in-flow. + nextInFlow = (nsBlockFrame*) nextInFlow->mNextInFlow; + continue; + } + + // Get style information for the pulled up kid + nsIContent* kid = kidFrame->GetContent(); + nsIStyleContext* kidSC = aCX->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + + ReflowStatus status; + do { + PRIntn placeStatus = PlaceAndReflowChild(aCX, aState, kidFrame, kidMol); + status = aState.reflowStatus; + if (0 == (placeStatus & PLACE_FIT)) { + // Push the kids that didn't fit back down to the next-in-flow + mLastContentIsComplete = PRBool(nsnull == kidFrame->GetNextInFlow()); + PushKids(aState); + + result = PR_FALSE; + NS_RELEASE(kid); + NS_RELEASE(kidSC); + goto push_done; + } + + if (frNotComplete == status) { + // Child is not complete + nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); + if (nsnull == kidNextInFlow) { + // Create a continuing frame for the incomplete child + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aCX, this); + + // Add the continuing frame to our sibling list. + continuingFrame->SetNextSibling(kidFrame->GetNextSibling()); + kidFrame->SetNextSibling(continuingFrame); + prevKidFrame = kidFrame; + kidFrame = continuingFrame; + mChildCount++; + + // Switch to new kid style + NS_RELEASE(kidSC); + kidSC = kidFrame->GetStyleContext(aCX); + kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + } else { + // The child has a next-in-flow, but it's not one of ours. + // It *must* be in one of our next-in-flows. Collect it + // then. + NS_ASSERTION(kidNextInFlow->GetGeometricParent() != this, + "busted kid next-in-flow"); + break; + } + } + } while (frNotComplete == status); + NS_RELEASE(kid); + NS_RELEASE(kidSC); + + prevKidFrame = kidFrame; + } + + if (nsnull != prevKidFrame) { + // The only way we can get here is by pulling up every last child + // in our next-in-flows (and reflowing any continunations they + // have). Therefore we KNOW that our last child is complete. + NS_ASSERTION(PR_TRUE == aState.lastContentIsComplete, "bad state"); + NS_ASSERTION(LastChild() == prevKidFrame, "bad last child"); + SetLastContentOffset(prevKidFrame); + } + + push_done:; + + if (result == PR_FALSE) { + // If our next-in-flow is empty OR our next next-in-flow is empty + // then adjust the offsets of all of the empty next-in-flows. + nextInFlow = (nsBlockFrame*) mNextInFlow; + if ((0 == nextInFlow->mChildCount) || + ((nsnull != nextInFlow->mNextInFlow) && + (0 == ((nsBlockFrame*)(nextInFlow->mNextInFlow))->mChildCount))) { + // We didn't pullup everything and we need to fixup one of our + // next-in-flows content offsets. + AdjustOffsetOfEmptyNextInFlows(); + } + } + + +#ifdef NS_DEBUG + PRInt32 len = LengthOf(mFirstChild); + NS_ASSERTION(len == mChildCount, "bad child count"); + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": pullup %sok (childCount=%d) [%d,%d,%c]\n", + (result ? "" : "NOT "), + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif + return result; +} + +void nsBlockFrame::SetupState(nsIPresContext* aCX, + nsBlockReflowState& aState, + const nsSize& aMaxSize, + nsSize* aMaxElementSize, + nsISpaceManager* aSpaceManager) +{ + // Setup reflow state + nsStyleMolecule* mol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + nsStyleFont* font = + (nsStyleFont*)mStyleContext->GetData(kStyleFontSID); + aState.Init(aMaxSize, aMaxElementSize, font, mol, aSpaceManager); + + // Apply border and padding adjustments for regular frames only + if (PR_FALSE == IsPseudoFrame()) { + aState.borderPadding = mol->borderPadding; + aState.y = mol->borderPadding.top; + aState.availSize.width -= + (mol->borderPadding.left + mol->borderPadding.right); + aState.availSize.height -= + (mol->borderPadding.top + mol->borderPadding.bottom); + } else { + aState.borderPadding.SizeTo(0, 0, 0, 0); + } + + // Setup initial list ordinal value + nsIAtom* tag = mContent->GetTag(); + if ((tag == nsHTMLAtoms::ul) || (tag == nsHTMLAtoms::ol) || + (tag == nsHTMLAtoms::menu) || (tag == nsHTMLAtoms::dir)) { + nsHTMLValue value; + if (eContentAttr_HasValue == + ((nsIHTMLContent*)mContent)->GetAttribute(nsHTMLAtoms::start, value)) { + if (eHTMLUnit_Absolute == value.GetUnit()) { + aState.nextListOrdinal = value.GetIntValue(); + } + } + } + NS_RELEASE(tag); + + mCurrentState = &aState; +} + +#include "nsUnitConversion.h"/* XXX */ +nsIFrame::ReflowStatus +nsBlockFrame::ResizeReflow(nsIPresContext* aCX, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsSize* aMaxElementSize) +{ + nsBlockReflowState state; + SetupState(aCX, state, aMaxSize, aMaxElementSize, aSpaceManager); + return DoResizeReflow(aCX, state, aDesiredRect); +} + +nsIFrame::ReflowStatus +nsBlockFrame::DoResizeReflow(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsRect& aDesiredRect) +{ +#ifdef NS_DEBUG + PreReflowCheck(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": resize reflow %g,%g\n", + NS_TWIPS_TO_POINTS_FLOAT(aState.availSize.width), + NS_TWIPS_TO_POINTS_FLOAT(aState.availSize.height)); + DumpFlow(); +#endif + + // Zap old line data + if (nsnull != mLines) { + delete mLines; + mLines = nsnull; + } + mNumLines = 0; + + // Check for an overflow list + MoveOverflowToChildList(); + + // Before we start reflowing, cache a pointer to our state structure + // so that inline frames can find it. + nsIPresShell* shell = aCX->GetShell(); + shell->PutCachedData(this, &aState); + + // First reflow any existing frames + PRBool reflowMappedOK = PR_TRUE; + ReflowStatus status = frComplete; + if (nsnull != mFirstChild) { + reflowMappedOK = ReflowMappedChildren(aCX, aState); + if (!reflowMappedOK) { + status = frNotComplete; + } + } + + if (reflowMappedOK) { + // Any space left? + nscoord yb = aState.borderPadding.top + aState.availSize.height; + if ((nsnull != mFirstChild) && (aState.y >= yb)) { + // No space left. Don't try to pull-up children or reflow + // unmapped. We need to return the correct completion status, + // so see if there is more to reflow. + if (MoreToReflow(aCX)) { + status = frNotComplete; + } + } else if (MoreToReflow(aCX)) { + // Try and pull-up some children from a next-in-flow + if ((nsnull == mNextInFlow) || PullUpChildren(aCX, aState)) { + // If we still have unmapped children then create some new frames + if (MoreToReflow(aCX)) { + status = ReflowAppendedChildren(aCX, aState); + } + } else { + // We were unable to pull-up all the existing frames from the + // next in flow + status = frNotComplete; + } + } + } + + // Deal with last line - make sure it gets vertically and + // horizontally aligned. This also updates the state's y coordinate + // which is good because that's how we size ourselves. + if (0 != aState.lineLength) { + if (!AdvanceToNextLine(aCX, aState)) { + // The last line of output doesn't fit. Push all of the kids to + // the next in flow and change our reflow status to not complete + // so that we are continued. +#ifdef NOISY + ListTag(stdout); + printf(": pushing kids since last line doesn't fit\n"); +#endif + + PushKids(aState); + status = frNotComplete; + } + } + + if (frComplete == status) { + // Don't forget to add in the bottom margin from our last child. + // Only add it in if there is room for it. + nscoord margin = aState.prevMaxPosBottomMargin - + aState.prevMaxNegBottomMargin; + nscoord y = aState.y + margin; + if (y <= aState.borderPadding.top + aState.availSize.height) { + aState.y = y; + } + } + + // Now that reflow has finished, remove the cached pointer + shell->RemoveCachedData(this); + NS_RELEASE(shell); + + // Translate state.lineLengths into an integer array + mNumLines = aState.lineLengths.Count(); + if (mNumLines > 0) { + mLines = new PRInt32[mNumLines]; + for (PRInt32 i = 0; i < mNumLines; i++) { + PRInt32 ll = (PRInt32) aState.lineLengths.ElementAt(i); + mLines[i] = ll; + } + } + + if (!aState.unconstrainedWidth && aState.justifying) { + // Perform justification now that we know how many lines we have. + JustifyLines(aCX, aState); + } + + // Return our desired rect and our status + aDesiredRect.x = 0; + aDesiredRect.y = 0; + aDesiredRect.width = aState.kidXMost + aState.borderPadding.right; + if (!aState.unconstrainedWidth) { + // Make sure we're at least as wide as the max size we were given + nscoord maxWidth = aState.availSize.width + aState.borderPadding.left + + aState.borderPadding.right; + + if (aDesiredRect.width < maxWidth) { + aDesiredRect.width = maxWidth; + } + } + aState.y += aState.borderPadding.bottom; + aDesiredRect.height = aState.y; + +#ifdef NS_DEBUG + PostReflowCheck(status); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": resize reflow %g,%g %scomplete [%d,%d,%c]\n", + NS_TWIPS_TO_POINTS_FLOAT(aState.availSize.width), + NS_TWIPS_TO_POINTS_FLOAT(aState.availSize.height), + ((status == frNotComplete) ? "NOT " : ""), + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F') + ); + DumpFlow(); +#endif + mCurrentState = nsnull; + return status; +} + +void nsBlockFrame::JustifyLines(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ + // XXX we don't justify the last line; what if we are continued, + // should we do it then? + nsIFrame* kid = mFirstChild; + for (PRInt32 i = 0; i < mNumLines; i++) { + nsIFrame* lineStart = kid; + PRInt32 lineLength = mLines[i]; + if (i < mNumLines - 1) { + if (1 == lineLength) { + // For lines with one element on them we can take a shortcut and + // let them do the justification. Note that we still call + // JustifyReflow even if the available space is zero in case the + // child is a hunk of text that ends in whitespace. The whitespace + // will be distributed elsewhere causing a proper flush right look + // for the last word. + nsRect r; + kid->GetRect(r); + nscoord maxWidth = aState.availSize.width; + nscoord availableSpace = maxWidth - r.width; + nscoord maxAvailSpace = nscoord(maxWidth * 0.1f); + if ((availableSpace >= 0) && (availableSpace < maxAvailSpace)) { + kid->JustifyReflow(aCX, availableSpace); + kid->SizeTo(r.width + availableSpace, r.height); + } + kid = kid->GetNextSibling(); + } else { + // XXX Get justification of multiple elements working + while (--lineLength >= 0) { + kid = kid->GetNextSibling(); + } + } + } + + // Finally, now that the in-flow positions of the line's frames are + // known we can apply relative positioning if any of them need it. + nsCSSLayout::RelativePositionChildren(aCX, this, aState.mol, + lineStart, mLines[i]); + } +} + +nsIFrame* nsBlockFrame::CreateContinuingFrame(nsIPresContext* aCX, + nsIFrame* aParent) +{ + nsBlockFrame* cf = new nsBlockFrame(mContent, mIndexInParent, aParent); + PrepareContinuingFrame(aCX, aParent, cf); + return cf; +} + +nsIFrame::ReflowStatus +nsBlockFrame::IncrementalReflow(nsIPresContext* aCX, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsReflowCommand& aReflowCommand) +{ + ReflowStatus status = frComplete; + + if (aReflowCommand.GetTarget() == this) { + // XXX for now, just do a complete reflow mapped (it'll kinda + // work, but it's slow) + + nsBlockReflowState state; + SetupState(aCX, state, aMaxSize, nsnull, aSpaceManager); + PRBool reflowMappedOK = ReflowMappedChildren(aCX, state); + if (!reflowMappedOK) { + status = frNotComplete; + } + } else { + // XXX not yet implemented + NS_ABORT(); + // XXX work to compute initial state goes *HERE* + aDesiredRect.x = 0; + aDesiredRect.y = 0; + aDesiredRect.width = 0; + aDesiredRect.height = 0; + } + + mCurrentState = nsnull; + return status; +} + +PRBool nsBlockFrame::IsLeftMostChild(nsIFrame* aFrame) +{ + do { + nsIFrame* parent = aFrame->GetGeometricParent(); + + // See if there are any non-zero sized child frames that precede aFrame + // in the child list + nsIFrame* child = parent->FirstChild(); + + while ((nsnull != child) && (aFrame != child)) { + // Is the child zero-sized? + if ((child->GetWidth() > 0) || (child->GetHeight() > 0)) { + // We found a non-zero sized child frame that precedes aFrame + return PR_FALSE; + } + + child = child->GetNextSibling(); + } + + // aFrame is the left-most non-zero sized frame in its geometric parent. + // Walk up one level and check that its parent is left-most as well + aFrame = parent; + } while (aFrame != this); + + return PR_TRUE; +} + +PRBool nsBlockFrame::AddFloater(nsIPresContext* aCX, + nsIFrame* aFloater, + PlaceholderFrame* aPlaceholder) +{ + // Get the frame associated with the space manager, and get its nsIAnchoredItems + // interface + nsIFrame* frame = mCurrentState->spaceManager->GetFrame(); + nsIAnchoredItems* anchoredItems = nsnull; + + frame->QueryInterface(kIAnchoredItemsIID, (void**)&anchoredItems); + NS_ASSERTION(nsnull != anchoredItems, "no anchored items interface"); + + if (nsnull != anchoredItems) { + anchoredItems->AddAnchoredItem(aFloater, nsIAnchoredItems::anHTMLFloater, this); + PlaceFloater(aCX, aFloater, aPlaceholder); + return PR_TRUE; + } + + return PR_FALSE; +} + +// XXX The size of the floater needs to be taken into consideration if we're +// computing a maximum element size +void nsBlockFrame::PlaceFloater(nsIPresContext* aCX, + nsIFrame* aFloater, + PlaceholderFrame* aPlaceholder) +{ + // If the floater is the left-most non-zero size child frame then insert + // it before the current line; otherwise add it to the below-current-line + // todo list and we'll handle it when we flush out the line + if (IsLeftMostChild(aPlaceholder)) { + // Get the type of floater + nsIStyleContext* styleContext = aFloater->GetStyleContext(aCX); + nsStyleMolecule* mol = (nsStyleMolecule*)styleContext->GetData(kStyleMoleculeSID); + NS_RELEASE(styleContext); + + if (!mCurrentState->isInline) { + // Get the current band for this line + GetAvailableSpaceBand(*mCurrentState, mCurrentState->y + mCurrentState->topMargin); + } + + // Commit some space in the space manager + nsRect region; + + aFloater->GetRect(region); + region.y = mCurrentState->currentBand->rects[0].y; + + if (NS_STYLE_FLOAT_LEFT == mol->floats) { + region.x = mCurrentState->currentBand->rects[0].x; + } else { + NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == mol->floats, "bad float type"); + region.x = mCurrentState->currentBand->rects[0].XMost() - region.width; + } + + // XXX Don't forget the floater's margins... + mCurrentState->spaceManager->Translate(mCurrentState->borderPadding.left, 0); + mCurrentState->spaceManager->AddRectRegion(region); + + // Set the origin of the floater in world coordinates + nscoord worldX, worldY; + + mCurrentState->spaceManager->GetTranslation(worldX, worldY); + aFloater->MoveTo(region.x + worldX, region.y + worldY); + mCurrentState->spaceManager->Translate(-mCurrentState->borderPadding.left, 0); + + // Update the band of available space to reflect space taken up by the floater + GetAvailableSpaceBand(*mCurrentState, mCurrentState->y + mCurrentState->topMargin); + } else { + // Add the floater to our to-do list + mCurrentState->floaterToDo.AppendElement(aFloater); + } +} + +void nsBlockFrame::ContentAppended(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer) +{ + // Zip down to the end-of-flow + nsBlockFrame* flow = this; + for (;;) { + nsBlockFrame* next = (nsBlockFrame*) flow->GetNextInFlow(); + if (nsnull == next) { + break; + } + flow = next; + } + + PRInt32 kidIndex = flow->NextChildOffset(); + PRInt32 startIndex = kidIndex; + nsIFrame* prevKidFrame = flow->LastChild(); + nsIFrame* kidFrame = nsnull; + for (;;) { + // Get the next content object + nsIContent* kid = mContent->ChildAt(kidIndex); + if (nsnull == kid) { + break; + } + + // Resolve style for the kid + nsIStyleContext* kidSC = aPresContext->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + + // Is it a floater? + if (kidMol->floats != NS_STYLE_FLOAT_NONE) { + PlaceholderFrame::NewFrame(&kidFrame, kid, kidIndex, this); + } else { + // Create initial frame for the child + nsIContentDelegate* kidDel; + nsresult fr; + switch (kidMol->display) { + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + // Pseudo block frames do not contain other block elements + // unless the block element would be the first child. + if (IsPseudoFrame()) { + // Update last content offset now that we are done drawing + // children from our parent. + SetLastContentOffset(prevKidFrame); + + // It better be true that we are not being asked to flow a + // block element as our first child. That means the body + // decided it needed a pseudo-frame when it shouldn't have. + NS_ASSERTION(nsnull != mFirstChild, "bad body"); + + NS_RELEASE(kidSC); + NS_RELEASE(kid); + + return; + } + // FALL THROUGH (and create frame) + + case NS_STYLE_DISPLAY_INLINE: + kidDel = kid->GetDelegate(aPresContext); + kidFrame = kidDel->CreateFrame(aPresContext, kid, kidIndex, this); + NS_RELEASE(kidDel); + break; + + default: + fr = nsFrame::NewFrame(&kidFrame, kid, kidIndex, this); + break; + } + } + kidFrame->SetStyleContext(kidSC); + NS_RELEASE(kidSC); + NS_RELEASE(kid); + + // Link child frame into the list of children + if (nsnull != prevKidFrame) { + NS_ASSERTION(nsnull == prevKidFrame->GetNextSibling(), "bad append"); + prevKidFrame->SetNextSibling(kidFrame); + } else { + NS_ASSERTION(nsnull == mFirstChild, "bad create"); + mFirstChild = kidFrame; + SetFirstContentOffset(kidFrame); + } + prevKidFrame = kidFrame; + kidIndex++; + mChildCount++; + } + SetLastContentOffset(prevKidFrame); + + // If this is a pseudo-frame then our parent will generate the + // reflow command. Otherwise, if the container is us then we should + // generate the reflow command because we were directly called. + if (!IsPseudoFrame() && (aContainer == mContent)) { + nsReflowCommand* rc = + new nsReflowCommand(aPresContext, flow, nsReflowCommand::FrameAppended, + startIndex); + aShell->AppendReflowCommand(rc); + } +} + +PRIntn nsBlockFrame::GetSkipSides() const +{ + PRIntn skip = 0; + if (nsnull != mPrevInFlow) { + skip |= 1 << NS_SIDE_TOP; + } + if (nsnull != mNextInFlow) { + skip |= 1 << NS_SIDE_BOTTOM; + } + return skip; +} + +nsHTMLFrameType nsBlockFrame::GetFrameType() const +{ + return eHTMLFrame_Block; +} + +void nsBlockFrame::ListTag(FILE* out) const +{ + if ((nsnull != mGeometricParent) && IsPseudoFrame()) { + fprintf(out, "*block(%d)@%p", mIndexInParent, this); + } else { + nsHTMLContainerFrame::ListTag(out); + } +} + +#ifdef NS_DEBUG +void nsBlockFrame::DumpFlow() const +{ +#ifdef NOISY_FLOW + nsBlockFrame* flow = (nsBlockFrame*) mNextInFlow; + while (flow != 0) { + printf(" %p: [%d,%d,%c]\n", + flow, flow->mFirstContentOffset, flow->mLastContentOffset, + (flow->mLastContentIsComplete ? 'T' : 'F')); + flow = (nsBlockFrame*) flow->mNextInFlow; + } +#endif +} +#endif diff --git a/mozilla/layout/html/base/src/nsBlockFrame.h b/mozilla/layout/html/base/src/nsBlockFrame.h new file mode 100644 index 00000000000..ab55c5dbeed --- /dev/null +++ b/mozilla/layout/html/base/src/nsBlockFrame.h @@ -0,0 +1,318 @@ +/* -*- 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. + */ +#ifndef nsBlockFrame_h___ +#define nsBlockFrame_h___ + +#include "nsHTMLContainerFrame.h" +#include "nsIFloaterContainer.h" +#include "nsIHTMLFrameType.h" +#include "nsIRunaround.h" +#include "nsVoidArray.h" +struct BlockBandData; +struct nsMargin; +struct nsStyleFont; + +/** + * Block frames have some state which needs to be made + * available to child frames for proper reflow. This structure + * describes that state. + */ +struct nsBlockReflowState { + // True if this is the first line of text in a block container + PRPackedBool firstLine; + + // True if leading whitespace is allowed to show + PRPackedBool allowLeadingWhitespace; + + // This is set when some child frame needs a break after it's placed + PRPackedBool breakAfterChild; + + // This is set when a child needs a break before it's placed. Note + // that this value is set by a child AFTER we have called it's + // ResizeReflow method. + PRPackedBool breakBeforeChild; + + // This is set when the first child should be treated specially + // because it's an inside list item bullet. + // XXX this can go away once we have a way for the bullet's style + // molecule to *not* be the same as it's parent's + PRPackedBool firstChildIsInsideBullet; + + // For pre-formatted text, this is our current column + PRIntn column; + + // The next list ordinal value + PRInt32 nextListOrdinal; + + //---------------------------------------------------------------------- + // State from here on down is not to be used by block child frames! + + // Space manager to use + nsISpaceManager* spaceManager; + + // Block's style data + nsStyleFont* font; + nsStyleMolecule* mol; + + // Block's available size (computed from the block's parent) + nsSize availSize; + + // Current band of available space. Used for doing runaround + BlockBandData* currentBand; + + // Pointer to a max-element-size (nsnull if none required) + nsSize* maxElementSize; + + // The maximum x-most of our lines and block-level elements. This is used to + // compute our desired size, and includes our left border/padding. For block- + // level elements this also includes the block's right margin. + nscoord kidXMost; + + // Current reflow position + nscoord y; + + // Current line state + nscoord x; // inline elements only. not include border/padding + PRBool isInline; // whether the current is inline or block + nsVoidArray lineLengths; // line length temporary storage + PRIntn currentLineNumber; // index into mLines + nsIFrame* lineStart; // frame starting the line + PRInt32 lineLength; // length of line + nscoord* ascents; // ascent information for each child + nscoord maxAscent; // max ascent for this line + nscoord maxDescent; // max descent for this line + nscoord lineWidth; // current width of line +#if 0 + nscoord maxPosTopMargin; // maximum positive top margin + nscoord maxNegTopMargin; // maximum negative top margin +#else + nscoord topMargin; // current top margin +#endif + nscoord maxPosBottomMargin; // maximum positive bottom margin + nscoord maxNegBottomMargin; // maximum negative bottom margin + nsSize lineMaxElementSize; // max element size for current line + PRBool lastContentIsComplete; // reflow status of last child on line + nsVoidArray floaterToDo; // list of floaters to place below current line + + PRInt32 maxAscents; // size of ascent buffer + nscoord ascentBuf[20]; + + PRPackedBool needRelativePos; // some kid in line needs relative pos + + // Previous line state that we carry forward to the next line + nsIFrame* prevLineLastFrame; + nscoord prevLineHeight; // height of the previous line + nscoord prevMaxPosBottomMargin; // maximum posative bottom margin + nscoord prevMaxNegBottomMargin; // maximum negative bottom margin + PRBool prevLineLastContentIsComplete; + + // Sanitized version of mol->borderPadding; if this block frame is a + // pseudo-frame then the margin will be zero'd. + nsMargin borderPadding; + + PRPackedBool justifying; // we are justifying + + // Status from last PlaceAndReflowChild + nsIFrame::ReflowStatus reflowStatus; + + // Flags for whether the max size is unconstrained + PRBool unconstrainedWidth; + PRBool unconstrainedHeight; + + nsBlockReflowState(); + + ~nsBlockReflowState(); + + void Init(const nsSize& aMaxSize, nsSize* aMaxElementSize, + nsStyleFont* aFont, nsStyleMolecule* aMol, nsISpaceManager* aSpaceManager); + + void AddAscent(nscoord aAscent); + void AdvanceToNextLine(nsIFrame* aPrevLineLastFrame, nscoord aPrevLineHeight); + +#ifdef NS_DEBUG + void DumpLine(); + void DumpList(); +#endif +}; + +//---------------------------------------------------------------------- + +/** + *

Block Reflow

+ * + * The block frame reflow machinery performs "2D" layout. Inline + * elements are flowed into logical lines (left to right or right to + * left) and the lines are stacked vertically. Block elements are + * flowed onto their own line after flushing out any preceeding line.

+ * + * After a line is ready to be flushed out, vertical alignment is + * performed. Vertical alignment may require the line to consume more + * vertical space than is available thus causing the entire line to + * be pushed.

+ * + * After vertical alignment is done, horizontal alignment (including + * justification) is performed. Finally, relative positioning is done + * on any elements that require it.

+ * + * During reflow, the block frame will make available to child frames + * it's reflow state using the presentation shell's cached data + * mechanism.

+ * + *

Reflowing Mapped Content

+ *

Pullup

+ *

Reflowing Unmapped Content

+ *

Content Insertion Handling

+ *

Content Deletion Handling

+ *

Style Change Handling

+ * + *

Assertions

+ * mLastContentIsComplete always reflects the state of the last + * child frame on our chlid list. + */ +class nsBlockFrame : public nsHTMLContainerFrame, public nsIHTMLFrameType, + public nsIRunaround, public nsIFloaterContainer +{ +public: + /** + * Create a new block frame that maps the given piece of content. + */ + static nsresult NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); + + virtual ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsSize* aMaxElementSize); + + virtual ReflowStatus IncrementalReflow(nsIPresContext* aPresContext, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsReflowCommand& aReflowCommand); + + virtual void ContentAppended(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer); + + virtual nsIFrame* CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent); + + virtual PRBool AddFloater(nsIPresContext* aCX, + nsIFrame* aFloater, + PlaceholderFrame* aPlaceholder); + virtual void PlaceFloater(nsIPresContext* aCX, + nsIFrame* aFloater, + PlaceholderFrame* aPlaceholder); + + virtual void ListTag(FILE* out = stdout) const; + + virtual nsHTMLFrameType GetFrameType() const; + +protected: + nsBlockFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + virtual ~nsBlockFrame(); + + virtual PRIntn GetSkipSides() const; + + PRBool MoreToReflow(nsIPresContext* aCX); + + nscoord GetTopMarginFor(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsStyleMolecule* aKidMol, + PRBool aIsInline); + + PRBool AdvanceToNextLine(nsIPresContext* aPresContext, + nsBlockReflowState& aState); + + void AddInlineChildToLine(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsIFrame* aKidFrame, + nsReflowMetrics& aKidSize, + nsSize* aKidMaxElementSize, + nsStyleMolecule* aKidMol); + + void AddBlockChild(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsIFrame* aKidFrame, + nsRect& aKidRect, + nsSize* aKidMaxElementSize, + nsStyleMolecule* aKidMol); + + void GetAvailSize(nsSize& aResult, + nsBlockReflowState& aState, + nsStyleMolecule* aKidMol, + PRBool aIsInline); + + PRIntn PlaceAndReflowChild(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsIFrame* kidFrame, + nsStyleMolecule* aKidMol); + + void PushKids(nsBlockReflowState& aState); + + void SetupState(nsIPresContext* aCX, nsBlockReflowState& aState, + const nsSize& aMaxSize, nsSize* aMaxElementSize, + nsISpaceManager* aSpaceManager); + + ReflowStatus DoResizeReflow(nsIPresContext* aPresContext, + nsBlockReflowState& aState, + nsRect& aDesiredRect); + + PRBool ReflowMappedChildren(nsIPresContext* aPresContext, + nsBlockReflowState& aState); + + PRBool PullUpChildren(nsIPresContext* aCX, + nsBlockReflowState& aState); + + ReflowStatus ReflowAppendedChildren(nsIPresContext* aPresContext, + nsBlockReflowState& aState); + + void JustifyLines(nsIPresContext* aPresContext, nsBlockReflowState& aState); + + PRBool IsLeftMostChild(nsIFrame* aFrame); + + void GetAvailableSpaceBand(nsBlockReflowState& aState, nscoord aY); + + void PlaceBelowCurrentLineFloaters(nsIPresContext* aCX, + nsBlockReflowState& aState, + nscoord aY); + + void ClearFloaters(nsBlockReflowState& aState, PRUint32 aClear); + +#ifdef NS_DEBUG + void DumpFlow() const; +#endif + + /** + * Array of lines lengths. For each logical line of children, this array + * contains a count of the number of children on the line. + */ + PRInt32* mLines; + PRInt32 mNumLines; + nsBlockReflowState* mCurrentState; +}; + +#endif /* nsBlockFrame_h___ */ diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.cpp b/mozilla/layout/html/base/src/nsBlockReflowState.cpp new file mode 100644 index 00000000000..de26654f45d --- /dev/null +++ b/mozilla/layout/html/base/src/nsBlockReflowState.cpp @@ -0,0 +1,2030 @@ +/* -*- 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 "nsBlockFrame.h" +#include "nsSize.h" +#include "nsIAnchoredItems.h" +#include "nsIContent.h" +#include "nsIContentDelegate.h" +#include "nsISpaceManager.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsIPresContext.h" +#include "nsMargin.h" +#include "nsHTMLIIDs.h" +#include "nsCSSLayout.h" +#include "nsCRT.h" +#include "nsIPresShell.h" +#include "nsReflowCommand.h" +#include "nsPlaceholderFrame.h" +#include "nsHTMLAtoms.h" +#include "nsHTMLValue.h" +#include "nsIHTMLContent.h" + +#ifdef NS_DEBUG +#undef NOISY +#undef NOISY_FLOW +#else +#undef NOISY +#undef NOISY_FLOW +#endif + +static NS_DEFINE_IID(kIRunaroundIID, NS_IRUNAROUND_IID); +static NS_DEFINE_IID(kIFloaterContainerIID, NS_IFLOATERCONTAINER_IID); +static NS_DEFINE_IID(kIAnchoredItemsIID, NS_IANCHOREDITEMS_IID); +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); +static NS_DEFINE_IID(kStyleFontSID, NS_STYLEFONT_SID); + +struct BlockBandData : public nsBandData { + nsRect data[5]; + + BlockBandData() {size = 5; rects = data;} +}; + +// XXX Bugs +// 1. right to left reflow can generate negative x coordinates. + +// XXX Speedup idea (all containers) + +// If I reflow a child and it gives back not-complete status then +// there is no sense in trying to pullup children. For blocks, it's a +// little more complicated unless the child is a block - if the child +// is a block, then we must be out of room hence we should stop. If +// the child is not a block then our line should be flushed (see #2 +// below) if our line is already empty then we must be out of room. + +// For inline frames and column frames, if we reflow a child and get +// back not-complete status then we should bail immediately because we +// are out of room. + +// XXX Speedup ideas: +// 1. change pullup code to use line information from next in flow +// 2. we can advance to next line immediately after reflowing something +// and noticing that it's not complete. +// 3. pass down last child information in aState so that pullup, etc., +// don't need to recompute it + +// XXX TODO: +// 0. Move justification into line flushing code + +// 1. To get ebina margins I need "auto" information from the style +// system margin's. A bottom/top margin of auto will then be computed like +// ebina computes it [however the heck that is]. + +// 2. kicking out floaters and talking with floater container to adjust +// left and right margins + +nsBlockReflowState::nsBlockReflowState() +{ +} + +void nsBlockReflowState::Init(const nsSize& aMaxSize, + nsSize* aMaxElementSize, + nsStyleFont* aFont, + nsStyleMolecule* aMol, + nsISpaceManager* aSpaceManager) +{ + firstLine = PR_TRUE; + allowLeadingWhitespace = PR_FALSE; + breakAfterChild = PR_FALSE; + breakBeforeChild = PR_FALSE; + firstChildIsInsideBullet = PR_FALSE; + nextListOrdinal = -1; + column = 0; + + spaceManager = aSpaceManager; + currentBand = new BlockBandData; + font = aFont; + mol = aMol; + availSize.width = aMaxSize.width; + availSize.height = aMaxSize.height; + maxElementSize = aMaxElementSize; + if (nsnull != aMaxElementSize) { + aMaxElementSize->width = 0; + aMaxElementSize->height = 0; + } + + kidXMost = 0; + x = 0; + y = 0; + + isInline = PR_FALSE; + currentLineNumber = 0; + lineStart = nsnull; + lineLength = 0; + ascents = ascentBuf; + maxAscent = 0; + maxDescent = 0; + lineWidth = 0; + maxPosBottomMargin = 0; + maxNegBottomMargin = 0; + lineMaxElementSize.width = 0; + lineMaxElementSize.height = 0; + lastContentIsComplete = PR_TRUE; + + maxAscents = sizeof(ascentBuf) / sizeof(ascentBuf[0]); + needRelativePos = PR_FALSE; + + prevLineLastFrame = nsnull; + prevLineHeight = 0; + topMargin = 0; + prevMaxPosBottomMargin = 0; + prevMaxNegBottomMargin = 0; + prevLineLastContentIsComplete = PR_TRUE; + + unconstrainedWidth = PRBool(aMaxSize.width == NS_UNCONSTRAINEDSIZE); + unconstrainedHeight = PRBool(aMaxSize.height == NS_UNCONSTRAINEDSIZE); + + justifying = (NS_STYLE_TEXT_ALIGN_JUSTIFY == mol->textAlign) && + (NS_STYLE_WHITESPACE_PRE != mol->whiteSpace); + reflowStatus = nsIFrame::frNotComplete; +} + +nsBlockReflowState::~nsBlockReflowState() +{ + if (ascents != ascentBuf) { + delete ascents; + } + delete currentBand; +} + +void nsBlockReflowState::AddAscent(nscoord aAscent) +{ + NS_PRECONDITION(lineLength <= maxAscents, "bad line length"); + if (lineLength == maxAscents) { + maxAscents *= 2; + nscoord* newAscents = new nscoord[maxAscents]; + if (nsnull != newAscents) { + nsCRT::memcpy(newAscents, ascents, sizeof(nscoord) * lineLength); + if (ascents != ascentBuf) { + delete ascents; + } + ascents = newAscents; + } else { + // Yikes! Out of memory! + return; + } + } + ascents[lineLength] = aAscent; +} + +void nsBlockReflowState::AdvanceToNextLine(nsIFrame* aPrevLineLastFrame, + nscoord aPrevLineHeight) +{ + firstLine = PR_FALSE; + allowLeadingWhitespace = PR_FALSE; + column = 0; + breakAfterChild = PR_FALSE; + breakBeforeChild = PR_FALSE; + lineStart = nsnull; + lineLength = 0; + currentLineNumber++; + maxAscent = 0; + maxDescent = 0; + lineWidth = 0; + needRelativePos = PR_FALSE; + + prevLineLastFrame = aPrevLineLastFrame; + prevLineHeight = aPrevLineHeight; + prevMaxPosBottomMargin = maxPosBottomMargin; + prevMaxNegBottomMargin = maxNegBottomMargin; + + // Remember previous line's lastContentIsComplete + prevLineLastContentIsComplete = lastContentIsComplete; + lastContentIsComplete = PR_TRUE; + + topMargin = 0; + maxPosBottomMargin = 0; + maxNegBottomMargin = 0; +} + +#ifdef NS_DEBUG +void nsBlockReflowState::DumpLine() +{ + nsIFrame* f = lineStart; + PRInt32 ll = lineLength; + while (--ll >= 0) { + printf(" "); + ((nsFrame*)f)->ListTag(stdout);/* XXX */ + printf("\n"); + f = f->GetNextSibling(); + } +} + +void nsBlockReflowState::DumpList() +{ + nsIFrame* f = lineStart; + while (nsnull != f) { + printf(" "); + ((nsFrame*)f)->ListTag(stdout);/* XXX */ + printf("\n"); + f = f->GetNextSibling(); + } +} +#endif + +//---------------------------------------------------------------------- + +nsresult nsBlockFrame::NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIFrame* it = new nsBlockFrame(aContent, aIndexInParent, aParent); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aInstancePtrResult = it; + return NS_OK; +} + +nsBlockFrame::nsBlockFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) + : nsHTMLContainerFrame(aContent, aIndexInParent, aParent) +{ +} + +nsBlockFrame::~nsBlockFrame() +{ + if (nsnull != mLines) { + delete mLines; + } +} + +nsresult +nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) +{ + NS_PRECONDITION(0 != aInstancePtr, "null ptr"); + if (NULL == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kIHTMLFrameTypeIID)) { + *aInstancePtr = (void*) ((nsIHTMLFrameType*) this); + return NS_OK; + } else if (aIID.Equals(kIRunaroundIID)) { + *aInstancePtr = (void*) ((nsIRunaround*) this); + return NS_OK; + } else if (aIID.Equals(kIFloaterContainerIID)) { + *aInstancePtr = (void*) ((nsIFloaterContainer*) this); + return NS_OK; + } + return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr); +} + +// Computes the top margin to use for this child frames based on its display +// type and the display type of the previous child frame. +// +// Adjacent vertical margins between block-level elements are collapsed. +nscoord nsBlockFrame::GetTopMarginFor(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsStyleMolecule* aKidMol, + PRBool aIsInline) +{ + if (aIsInline) { + // Just use whatever the previous bottom margin was + return aState.prevMaxPosBottomMargin - aState.prevMaxNegBottomMargin; + } else { + nscoord maxNegTopMargin = 0; + nscoord maxPosTopMargin = 0; + if (aKidMol->margin.top < 0) { + maxNegTopMargin = -aKidMol->margin.top; + } else { + maxPosTopMargin = aKidMol->margin.top; + } + + nscoord maxPos = PR_MAX(aState.prevMaxPosBottomMargin, maxPosTopMargin); + nscoord maxNeg = PR_MAX(aState.prevMaxNegBottomMargin, maxNegTopMargin); + return maxPos - maxNeg; + } +} + +void nsBlockFrame::PlaceBelowCurrentLineFloaters(nsIPresContext* aCX, + nsBlockReflowState& aState, + nscoord aY) +{ + NS_PRECONDITION(aState.floaterToDo.Count() > 0, "no floaters"); + + // XXX Factor this code with PlaceFloater()... + PRInt32 numFloaters = aState.floaterToDo.Count(); + + for (PRInt32 i = 0; i < numFloaters; i++) { + nsIFrame* floater = (nsIFrame*)aState.floaterToDo[i]; + nsRect region; + + // Get the band of available space + // XXX This is inefficient to do this inside the loop... + GetAvailableSpaceBand(aState, aY); + + // Get the type of floater + nsIStyleContext* styleContext = floater->GetStyleContext(aCX); + nsStyleMolecule* mol = (nsStyleMolecule*)styleContext->GetData(kStyleMoleculeSID); + NS_RELEASE(styleContext); + + floater->GetRect(region); + region.y = mCurrentState->currentBand->rects[0].y; + + if (NS_STYLE_FLOAT_LEFT == mol->floats) { + region.x = mCurrentState->currentBand->rects[0].x; + } else { + NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == mol->floats, "bad float type"); + region.x = mCurrentState->currentBand->rects[0].XMost() - region.width; + } + + // XXX Don't forget the floater's margins... + mCurrentState->spaceManager->Translate(mCurrentState->borderPadding.left, 0); + mCurrentState->spaceManager->AddRectRegion(region); + + // Set the origin of the floater in world coordinates + nscoord worldX, worldY; + + mCurrentState->spaceManager->GetTranslation(worldX, worldY); + floater->MoveTo(region.x + worldX, region.y + worldY); + mCurrentState->spaceManager->Translate(-mCurrentState->borderPadding.left, 0); + } + aState.floaterToDo.Clear(); +} + +/** + * Flush a line out. Return true if the line fits in our available + * height. If the line does not fit then return false. When the line + * fits we advance the y coordinate, reset the x coordinate and + * prepare the nsBlockReflowState for the next line. + */ +PRBool nsBlockFrame::AdvanceToNextLine(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ + NS_PRECONDITION(aState.lineLength > 0, "bad line"); + NS_PRECONDITION(nsnull != aState.lineStart, "bad line"); + + nscoord y = aState.y + aState.topMargin; + nscoord lineHeight; + + if (aState.isInline) { + // Vertically align the children on this line, returning the height of + // the line upon completion. + lineHeight = nsCSSLayout::VerticallyAlignChildren(aCX, this, aState.font, y, + aState.lineStart, aState.lineLength, + aState.ascents, aState.maxAscent); + + // Any below current line floaters to place? + if (aState.floaterToDo.Count() > 0) { + PlaceBelowCurrentLineFloaters(aCX, aState, y + lineHeight); + // XXX Factor in the height of the floaters as well when considering + // whether the line fits. + // The default policy is that if there isn't room for the floaters then + // both the line and the floaters are pushed to the next-in-flow... + } + } else { + lineHeight = aState.lineStart->GetHeight(); + } + + // The first line always fits + if (aState.currentLineNumber > 0) { + nscoord yb = aState.borderPadding.top + aState.availSize.height; + if (y + lineHeight > yb) { + // After vertical alignment of the children and factoring in the + // proper margin, the line doesn't fit. + return PR_FALSE; + } + } + + if (aState.isInline) { + // Check if the right-edge of the line exceeds our running x-most + nscoord xMost = aState.borderPadding.left + aState.lineWidth; + if (xMost > aState.kidXMost) { + aState.kidXMost = xMost; + } + } + + // Advance the y coordinate to the new position where the next + // line or block element will go. + aState.y = y + lineHeight; + aState.x = 0; + + // Now that the vertical alignment is done we can perform horizontal + // alignment and relative positioning. Skip all of these if we are + // doing an unconstrained (in x) reflow. There's no point in doing + // the work if we *know* we are going to reflowed again. + if (!aState.unconstrainedWidth) { + nsCSSLayout::HorizontallyPlaceChildren(aCX, this, aState.mol, + aState.lineStart, aState.lineLength, + aState.lineWidth, + aState.availSize.width); + + // Finally, now that the in-flow positions of the line's frames are + // known we can apply relative positioning if any of them need it. + if (!aState.justifying) { + nsCSSLayout::RelativePositionChildren(aCX, this, aState.mol, + aState.lineStart, + aState.lineLength); + } + } + + // Record line length + aState.lineLengths.AppendElement((void*)aState.lineLength); + + // Find the last frame in the line + // XXX keep this as running state in the nsBlockReflowState + nsIFrame* lastFrame = aState.lineStart; + PRInt32 lineLen = aState.lineLength - 1; + while (--lineLen >= 0) { + lastFrame = lastFrame->GetNextSibling(); + } + + // Update maxElementSize + if (nsnull != aState.maxElementSize) { + nsSize& lineMax = aState.lineMaxElementSize; + nsSize* maxMax = aState.maxElementSize; + if (lineMax.width > maxMax->width) { + maxMax->width = lineMax.width; + } + if (lineMax.height > maxMax->height) { + maxMax->height = lineMax.height; + } + aState.lineMaxElementSize.width = 0; + aState.lineMaxElementSize.height = 0; + } + + // Advance to the next line + aState.AdvanceToNextLine(lastFrame, lineHeight); + + return PR_TRUE; +} + +/** + * Add an inline child to the current line. Advance various running + * values after placement. + */ +void nsBlockFrame::AddInlineChildToLine(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsIFrame* aKidFrame, + nsReflowMetrics& aKidSize, + nsSize* aKidMaxElementSize, + nsStyleMolecule* aKidMol) +{ + NS_PRECONDITION(nsnull != aState.lineStart, "bad line"); + + PRIntn direction = aState.mol->direction; + if (NS_STYLE_POSITION_RELATIVE == aKidMol->positionFlags) { + aState.needRelativePos = PR_TRUE; + } + + // Place and size the child + // XXX add in left margin from kid + nsRect r; + r.y = aState.y; + r.width = aKidSize.width; + r.height = aKidSize.height; + if (NS_STYLE_DIRECTION_LTR == aState.mol->direction) { + // Left to right positioning. + r.x = aState.borderPadding.left + aState.x + aKidMol->margin.left; + aState.x += aKidSize.width + aKidMol->margin.left + aKidMol->margin.right; + } else { + // Right to left positioning + // XXX what should we do when aState.x goes negative??? + r.x = aState.x - aState.borderPadding.right - aKidMol->margin.right - aKidSize.width; + aState.x -= aKidSize.width + aKidMol->margin.right + aKidMol->margin.left; + } + aKidFrame->SetRect(r); + aState.AddAscent(aKidSize.ascent); + aState.lineWidth += aKidSize.width; + aState.lineLength++; + + // Update maximums for the line + if (aKidSize.ascent > aState.maxAscent) { + aState.maxAscent = aKidSize.ascent; + } + if (aKidSize.descent > aState.maxDescent) { + aState.maxDescent = aKidSize.descent; + } + // Update running margin maximums + if (aState.firstChildIsInsideBullet && (aKidFrame == mFirstChild)) { + // XXX temporary code. Since the molecule for the bullet frame + // is the same as the LI frame, we get bad style information. + // ignore it. + } else { + nscoord margin; +#if 0 + // XXX CSS2 spec says that top/bottom margin don't affect line height + // calculation. We're waiting for clarification on this issue... + if ((margin = aKidMol->margin.top) < 0) { + margin = -margin; + if (margin > aState.maxNegTopMargin) { + aState.maxNegTopMargin = margin; + } + } else { + if (margin > aState.maxPosTopMargin) { + aState.maxPosTopMargin = margin; + } + } +#endif + if ((margin = aKidMol->margin.bottom) < 0) { + margin = -margin; + if (margin > aState.maxNegBottomMargin) { + aState.maxNegBottomMargin = margin; + } + } else { + if (margin > aState.maxPosBottomMargin) { + aState.maxPosBottomMargin = margin; + } + } + } + + // Update line max element size + nsSize& mes = aState.lineMaxElementSize; + if (nsnull != aKidMaxElementSize) { + if (aKidMaxElementSize->width > mes.width) { + mes.width = aKidMaxElementSize->width; + } + if (aKidMaxElementSize->height > mes.height) { + mes.height = aKidMaxElementSize->height; + } + } +} + +// Places and sizes the block-level element, and advances the line. +// The rect is in the local coordinate space of the kid frame. +void nsBlockFrame::AddBlockChild(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsIFrame* aKidFrame, + nsRect& aKidRect, + nsSize* aKidMaxElementSize, + nsStyleMolecule* aKidMol) +{ + NS_PRECONDITION(nsnull != aState.lineStart, "bad line"); + + if (NS_STYLE_POSITION_RELATIVE == aKidMol->positionFlags) { + aState.needRelativePos = PR_TRUE; + } + + // Translate from the kid's coordinate space to our coordinate space + aKidRect.x += aState.borderPadding.left + aKidMol->margin.left; + aKidRect.y += aState.y + aState.topMargin; + + // Place and size the child + aKidFrame->SetRect(aKidRect); + + aState.AddAscent(aKidRect.height); + aState.lineLength++; + + // Is this the widest child frame? + nscoord xMost = aKidRect.XMost() + aKidMol->margin.right; + if (xMost > aState.kidXMost) { + aState.kidXMost = xMost; + } + + // Update the max element size + if (nsnull != aKidMaxElementSize) { + if (aKidMaxElementSize->width > aState.maxElementSize->width) { + aState.maxElementSize->width = aKidMaxElementSize->width; + } + if (aKidMaxElementSize->height > aState.maxElementSize->height) { + aState.maxElementSize->height = aKidMaxElementSize->height; + } + } + + // and the bottom line margin information which we'll use when placing + // the next child + if (aKidMol->margin.bottom < 0) { + aState.maxNegBottomMargin = -aKidMol->margin.bottom; + } else { + aState.maxPosBottomMargin = aKidMol->margin.bottom; + } + + // Update the running y-offset + aState.y += aKidRect.height + aState.topMargin; + + // Apply relative positioning if necessary + nsCSSLayout::RelativePositionChildren(aCX, this, aState.mol, aKidFrame, 1); + + // Advance to the next line + aState.AdvanceToNextLine(aKidFrame, aKidRect.height); +} + +/** + * Compute the available size for reflowing the given child at the + * current x,y position in the state. Note that this may return + * negative or zero width/height's if we are out of room. + */ +void nsBlockFrame::GetAvailSize(nsSize& aResult, + nsBlockReflowState& aState, + nsStyleMolecule* aKidMol, + PRBool aIsInline) +{ + // Determine the maximum available reflow height for the child + nscoord yb = aState.borderPadding.top + aState.availSize.height; + aResult.height = aState.unconstrainedHeight ? NS_UNCONSTRAINEDSIZE : + yb - aState.y - aState.topMargin; + + // Determine the maximum available reflow width for the child + if (aState.unconstrainedWidth) { + aResult.width = NS_UNCONSTRAINEDSIZE; + } else if (aIsInline) { + if (NS_STYLE_DIRECTION_LTR == aState.mol->direction) { + aResult.width = aState.currentBand->rects[0].XMost() - aState.x; + } else { + aResult.width = aState.x - aState.currentBand->rects[0].x; + } + } else { + // It's a block + aResult.width = aState.availSize.width - aKidMol->margin.left - + aKidMol->margin.right; + } +} + +/** + * Push all of the kids that we have not reflowed, starting at + * aState.lineStart. aPrevKid is the kid previous to aState.lineStart + * and is also our last child. Note that line length is NOT a + * reflection of the number of children we are actually pushing + * (because we don't break the sibling list as we add children to the + * line). + */ +void nsBlockFrame::PushKids(nsBlockReflowState& aState) +{ + nsIFrame* prevFrame = aState.prevLineLastFrame; + NS_PRECONDITION(nsnull != prevFrame, "pushing all kids"); + NS_PRECONDITION(prevFrame->GetNextSibling() == aState.lineStart, + "bad prev line"); + +#ifdef NS_DEBUG + PRInt32 numKids = LengthOf(mFirstChild); + NS_ASSERTION(numKids == mChildCount, "bad child count"); +#endif + +#ifdef NOISY + ListTag(stdout); + printf(": push kids (childCount=%d)\n", mChildCount); + DumpFlow(); +#endif + + PushChildren(aState.lineStart, prevFrame, mLastContentIsComplete); + SetLastContentOffset(prevFrame); + + // Set mLastContentIsComplete to the previous lines last content is + // complete now that the previous line's last child is our last + // child. + mLastContentIsComplete = aState.prevLineLastContentIsComplete; + + // Fix up child count + // XXX is there a better way? aState.lineLength doesn't work because + // we might be pushing more than just the pending line. + nsIFrame* kid = mFirstChild; + PRInt32 kids = 0; + while (nsnull != kid) { + kids++; + kid = kid->GetNextSibling(); + } + mChildCount = kids; + + // Make sure we have no lingering line data + aState.lineLength = 0; + aState.lineStart = nsnull; + +#ifdef NOISY + ListTag(stdout); + printf(": push kids done (childCount=%d) [%c]\n", mChildCount, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif +} + +/** + * Gets a band of available space starting at the specified y-offset. Assumes + * the local coordinate space is currently set to the upper-left origin of the + * bounding rect + * + * Updates "currentBand" and "x" member data of the block reflow state + */ +void nsBlockFrame::GetAvailableSpaceBand(nsBlockReflowState& aState, nscoord aY) +{ + // Gets a band of available space. + aState.spaceManager->Translate(aState.borderPadding.left, 0); + aState.spaceManager->GetBandData(aY, aState.availSize, *aState.currentBand); + + // XXX This is hack code that needs to change when the space manager interface + // changes to return both the available and unavailable space + // + // We'll get back anywhere between 1 and 3 rects depending on how many floaters + // there are. Actually the way it currently works we could get back zero rects + // if there are overlapping left and right floaters occupying all the space + if (aState.currentBand->count > 1) { + // If there are three rects then let's assume that there are floaters on the + // left and right and that only the middle rect is available + if (aState.currentBand->count == 3) { + aState.currentBand->rects[0] = aState.currentBand->rects[1]; + } else { + // There are two rects. That means either a left or right floater. Just use + // whichever space is larger. + if (aState.currentBand->rects[1].width > aState.currentBand->rects[0].width) { + aState.currentBand->rects[0] = aState.currentBand->rects[1]; + } + } + } + aState.spaceManager->Translate(-aState.borderPadding.left, 0); + aState.x = aState.currentBand->rects[0].x; +} + +void nsBlockFrame::ClearFloaters(nsBlockReflowState& aState, PRUint32 aClear) +{ + // Translate the coordinate space + aState.spaceManager->Translate(aState.borderPadding.left, 0); + +getBand: + nscoord y = aState.y + aState.topMargin; + PRBool isLeftFloater = PR_FALSE; + PRBool isRightFloater = PR_FALSE; + + // Get a band of available space + aState.spaceManager->GetBandData(y, aState.availSize, *aState.currentBand); + + if (aState.currentBand->count == 1) { + if (aState.currentBand->rects[0].width != aState.availSize.width) { + // Some of the space is taken up by floaters + if (aState.currentBand->rects[0].x > 0) { + isLeftFloater = PR_TRUE; + } + + if (aState.currentBand->rects[0].XMost() < aState.availSize.width) { + isRightFloater = PR_TRUE; + } + } + } else if (aState.currentBand->count == 2) { + if (aState.currentBand->rects[0].width > aState.currentBand->rects[1].width) { + isRightFloater = PR_TRUE; + } else { + isLeftFloater = PR_TRUE; + + // There may also be a right floater + if (aState.currentBand->rects[1].XMost() < aState.availSize.width) { + isRightFloater = PR_TRUE; + } + } + } else { + // Must be both left and right floaters + isLeftFloater = PR_TRUE; + isRightFloater = PR_TRUE; + } + + if (isLeftFloater) { + if ((aClear == NS_STYLE_CLEAR_LEFT) || (aClear == NS_STYLE_CLEAR_BOTH)) { + aState.y += aState.currentBand->rects[0].height; + goto getBand; + } + } + if (isRightFloater) { + if ((aClear == NS_STYLE_CLEAR_RIGHT) || (aClear == NS_STYLE_CLEAR_BOTH)) { + aState.y += aState.currentBand->rects[0].height; + goto getBand; + } + } + + aState.spaceManager->Translate(-aState.borderPadding.left, 0); +} + +// Bit's for PlaceAndReflowChild return value +#define PLACE_FIT 0x1 +#define PLACE_FLOWED 0x2 + +PRIntn +nsBlockFrame::PlaceAndReflowChild(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsIFrame* kidFrame, + nsStyleMolecule* aKidMol) +{ + nsSize kidMaxElementSize; + nsSize* pKidMaxElementSize = + (nsnull != aState.maxElementSize) ? &kidMaxElementSize : nsnull; + + // Get line start setup if we are at the start of a new line + if (nsnull == aState.lineStart) { + NS_ASSERTION(0 == aState.lineLength, "bad line length"); + aState.lineStart = kidFrame; + } + + // Get kid and its style + // XXX How is this any different than what was passed in to us as aKidMol? + nsIContent* kid = kidFrame->GetContent(); + nsIStyleContext* kidSC = kidFrame->GetStyleContext(aCX); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + NS_RELEASE(kid); + + // Figure out if kid is a block element or not + PRBool isInline = PR_TRUE; + PRIntn display = kidMol->display; + if (aState.firstChildIsInsideBullet && (mFirstChild == kidFrame)) { + // XXX Special hack for properly reflowing bullets that have the + // inside value for list-style-position. + display = NS_STYLE_DISPLAY_INLINE; + } + if ((NS_STYLE_DISPLAY_BLOCK == display) || + (NS_STYLE_DISPLAY_LIST_ITEM == display)) { + // Block elements always end up on the next line (unless they are + // already at the start of the line). + isInline = PR_FALSE; + if (aState.lineLength > 0) { + aState.breakAfterChild = PR_TRUE; + } + } + + // Handle forced break first + if (aState.breakAfterChild) { + NS_ASSERTION(aState.lineStart != kidFrame, "bad line"); + + // Get the last child in the current line + nsIFrame* lastFrame = aState.lineStart; + PRInt32 lineLen = aState.lineLength - 1; + while (--lineLen >= 0) { + lastFrame = lastFrame->GetNextSibling(); + } + + if (!AdvanceToNextLine(aCX, aState)) { + // The previous line didn't fit. + return 0; + } + aState.lineStart = kidFrame; + + // Get the style for the last child, and see if it wanted to clear floaters. + // This handles the BR tag, which is the only inline element for which clear + // applies + nsIStyleContext* lastChildSC = lastFrame->GetStyleContext(aCX); + nsStyleMolecule* lastChildMol = (nsStyleMolecule*)lastChildSC->GetData(kStyleMoleculeSID); + if (lastChildMol->clear != NS_STYLE_CLEAR_NONE) { + ClearFloaters(aState, lastChildMol->clear); + } + NS_RELEASE(lastChildSC); + } + + // Now that we've handled force breaks (and maybe called AdvanceToNextLine() + // which checks), remember whether it's an inline frame + aState.isInline = isInline; + + // If we're at the beginning of a line then compute the top margin that we + // should use + if (aState.lineStart == kidFrame) { + // Compute the top margin to use for this line + aState.topMargin = GetTopMarginFor(aCX, aState, kidMol, aState.isInline); + + // If it's an inline element then get a band of available space + // + // XXX If we have a current band and there's unused space in that band + // then avoid this call to get a band... + if (aState.isInline) { + GetAvailableSpaceBand(aState, aState.y + aState.topMargin); + } + } + + // Compute the available space to reflow the child into and then + // reflow it into that space. + nsSize kidAvailSize; + GetAvailSize(kidAvailSize, aState, kidMol, aState.isInline); + if ((aState.currentLineNumber > 0) && (kidAvailSize.height <= 0)) { + // No more room + return 0; + } + + ReflowStatus status; + + if (aState.isInline) { + nsReflowMetrics kidSize; + + // Inline elements are never passed the space manager + status = ReflowChild(kidFrame, aCX, kidSize, kidAvailSize, + pKidMaxElementSize); + + // For first children, we skip all the fit checks because we must + // fit at least one child for a parent to figure what to do with us. + if ((aState.currentLineNumber > 0) || (aState.lineLength > 0)) { + NS_ASSERTION(nsnull != aState.lineStart, "bad line start"); + + if (kidFrame == aState.lineStart) { + // Width always fits when we are at the logical left margin. + // Just check the height. + // + // XXX This height check isn't correct now that we have bands of + // available space... + if (kidSize.height > kidAvailSize.height) { + // It's too tall + return PLACE_FLOWED; + } + } else { + // Examine state and if the breakBeforeChild is set and we + // aren't already on the new line, do the forcing now. + // XXX Why aren't we doing this check BEFORE we resize reflow the child? + if (aState.breakBeforeChild) { + aState.breakBeforeChild = PR_FALSE; + if (kidFrame != aState.lineStart) { + if (!AdvanceToNextLine(aCX, aState)) { + // Flushing out the line failed. + return PLACE_FLOWED; + } + aState.lineStart = kidFrame; + + // Get a band of available space + GetAvailableSpaceBand(aState, aState.y + aState.topMargin); + + // Reflow child now that it has the line to itself + GetAvailSize(kidAvailSize, aState, kidMol, PR_TRUE); + status = ReflowChild(kidFrame, aCX, kidSize, kidAvailSize, + pKidMaxElementSize); + } + } + + // When we are not at the logical left margin then we need + // to check the width first. If we are too wide then advance + // to the next line and try reflowing again. + if (kidSize.width > kidAvailSize.width) { + // Too wide. Try next line + if (!AdvanceToNextLine(aCX, aState)) { + // Flushing out the line failed. + return PLACE_FLOWED; + } + aState.lineStart = kidFrame; + + // Get a band of available space + GetAvailableSpaceBand(aState, aState.y + aState.topMargin); + + // Reflow splittable children + if (kidFrame->IsSplittable()) { + // Update size info now that we are on the next line. Then + // reflow the child into the new available space. + GetAvailSize(kidAvailSize, aState, kidMol, PR_TRUE); + status = ReflowChild(kidFrame, aCX, kidSize, kidAvailSize, + pKidMaxElementSize); + + // If we just reflowed our last child then update the + // mLastContentIsComplete state. + if (nsnull == kidFrame->GetNextSibling()) { + // Use state from the reflow we just did + mLastContentIsComplete = PRBool(status == frComplete); + } + } + + // XXX This height check isn't correct now that we have bands of + // available space... + if (kidSize.height > kidAvailSize.height) { + // It's too tall on the next line + return PLACE_FLOWED; + } + // It's ok if it's too wide on the next line. + } + } + } + + // Add child to the line + AddInlineChildToLine(aCX, aState, kidFrame, kidSize, pKidMaxElementSize, kidMol); + + } else { + nsRect kidRect; + + // Does the block-level element want to clear any floaters that impact + // it? Note that the clear property only applies to block-level elements + // and the BR tag + if (aKidMol->clear != NS_STYLE_CLEAR_NONE) { + ClearFloaters(aState, aKidMol->clear); + GetAvailSize(kidAvailSize, aState, kidMol, PR_FALSE); + if ((aState.currentLineNumber > 0) && (kidAvailSize.height <= 0)) { + // No more room + return 0; + } + } + + // Give the block its own local coordinate space. + // + // XXX This is wrong to have the parent try and account for the kid's + // left margin here, because we have to wait until we know what the + // left edge is and that means resolving any floaters that impact the + // block. If the kid wants to interact with the space manager then it + // will have to deal with left/right margins itself + nscoord tx = aState.borderPadding.left + aKidMol->margin.left; + nscoord ty = aState.y + aState.topMargin; + + // Give the block-level element the opportunity to use the space manager + aState.spaceManager->Translate(tx, ty); + status = ReflowChild(kidFrame, aCX, aState.spaceManager, kidAvailSize, + kidRect, pKidMaxElementSize); + aState.spaceManager->Translate(-tx, -ty); + + // For first children, we skip all the fit checks because we must + // fit at least one child for a parent to figure what to do with us. + if ((aState.currentLineNumber > 0) || (aState.lineLength > 0)) { + // Block elements always fit horizontally (because they are + // always placed at the logical left margin). Check to see if + // the block fits vertically + if (kidRect.YMost() > kidAvailSize.height) { + // Nope + return PLACE_FLOWED; + } + } + + // Add block child + AddBlockChild(aCX, aState, kidFrame, kidRect, pKidMaxElementSize, kidMol); + } + + // If we just reflowed our last child then update the + // mLastContentIsComplete state. + if (nsnull == kidFrame->GetNextSibling()) { + // Use state from the reflow we just did + mLastContentIsComplete = PRBool(status == frComplete); + } + + aState.lastContentIsComplete = PRBool(status == frComplete); + if (aState.isInline && (frNotComplete == status)) { + // Since the inline child didn't complete its reflow we *know* + // that a continuation of it can't possibly fit on the current + // line. Therefore, set a flag in the state that will cause the + // a line break before the next frame is placed. + aState.breakAfterChild = PR_TRUE; + } + NS_RELEASE(kidSC); + + aState.reflowStatus = status; + return PLACE_FLOWED | PLACE_FIT; +} + +/** + * Reflow the existing frames. + * + * @param aCX presentation context to use + * @param aState in out parameter which tracks the state of + * reflow for the block frame. + * @return true if we successfully reflowed all the mapped children and false + * otherwise, e.g. we pushed children to the next in flow + */ +PRBool +nsBlockFrame::ReflowMappedChildren(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": reflow mapped (childCount=%d) [%d,%d,%c]\n", + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif + + PRBool result = PR_TRUE; + nsIFrame* kidFrame; + nsIFrame* prevKidFrame = nsnull; + + for (kidFrame = mFirstChild; nsnull != kidFrame; ) { + nsIContent* kid = kidFrame->GetContent(); + nsIStyleContext* kidSC = aCX->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + NS_RELEASE(kid); + + // Attempt to place and reflow the child + + // XXX if child is not splittable and it fits just place it where + // it is, otherwise advance to the next line and place it there if + // possible + + PRIntn placeStatus = PlaceAndReflowChild(aCX, aState, kidFrame, kidMol); + ReflowStatus status = aState.reflowStatus; + NS_RELEASE(kidSC); + if (0 == (placeStatus & PLACE_FIT)) { + // The child doesn't fit. Push it and any remaining children. + PushKids(aState); + result = PR_FALSE; + goto push_done; + } + + // Is the child complete? + if (frComplete == status) { + // Yes, the child is complete + NS_ASSERTION(nsnull == kidFrame->GetNextInFlow(), "bad child flow list"); + } else { + // No the child isn't complete + nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); + if (nsnull == kidNextInFlow) { + // The child doesn't have a next-in-flow so create a continuing + // frame. This hooks the child into the flow + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aCX, this); + NS_ASSERTION(nsnull != continuingFrame, "frame creation failed"); + + // Add the continuing frame to the sibling list + nsIFrame* nextSib = kidFrame->GetNextSibling(); + continuingFrame->SetNextSibling(nextSib); + kidFrame->SetNextSibling(continuingFrame); + mChildCount++; + } + + // Unlike the inline frame code we can't assume that we used + // up all of our space because the child's reflow status is + // frNotComplete. Instead, the child is probably split and + // we need to reflow the continuations as well. + } + + // Get the next child frame + prevKidFrame = kidFrame; + kidFrame = kidFrame->GetNextSibling(); + } + + push_done:; + // Update the child count member data + NS_POSTCONDITION(LastChild()->GetIndexInParent() == mLastContentOffset, "bad last content offset"); + +#ifdef NS_DEBUG + PRInt32 len = LengthOf(mFirstChild); + NS_POSTCONDITION(len == mChildCount, "bad child count"); + VerifyLastIsComplete(); +#endif + +#ifdef NOISY + ListTag(stdout); + printf(": reflow mapped %sok (childCount=%d) [%d,%d,%c]\n", + (result ? "" : "NOT "), + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif + return result; +} + +PRBool nsBlockFrame::MoreToReflow(nsIPresContext* aCX) +{ + PRBool rv = PR_FALSE; + if (IsPseudoFrame()) { + // Get the next content object that we would like to reflow + PRInt32 kidIndex = NextChildOffset(); + nsIContent* kid = mContent->ChildAt(kidIndex); + if (nsnull != kid) { + // Resolve style for the kid + nsIStyleContext* kidSC = aCX->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + switch (kidMol->display) { + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + // Block pseudo-frames do not contain other block elements + break; + + default: + rv = PR_TRUE; + break; + } + NS_RELEASE(kidSC); + NS_RELEASE(kid); + } + } else { + if (NextChildOffset() < mContent->ChildCount()) { + rv = PR_TRUE; + } + } + return rv; +} + +/** + * Create new frames for content we haven't yet mapped + * + * @param aCX presentation context to use + * @return frComplete if all content has been mapped and frNotComplete + * if we should be continued + */ +nsIFrame::ReflowStatus +nsBlockFrame::ReflowAppendedChildren(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif + nsIFrame* kidPrevInFlow = nsnull; + ReflowStatus result = frNotComplete; + + // If we have no children and we have a prev-in-flow then we need to pick + // up where it left off. If we have children, e.g. we're being resized, then + // our content offset should already be set correctly... + if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) { + nsBlockFrame* prev = (nsBlockFrame*) mPrevInFlow; + NS_ASSERTION(prev->mLastContentOffset >= prev->mFirstContentOffset, "bad prevInFlow"); + mFirstContentOffset = prev->NextChildOffset(); + if (PR_FALSE == prev->mLastContentIsComplete) { + // Our prev-in-flow's last child is not complete + kidPrevInFlow = prev->LastChild(); + } + } + + // Place our children, one at a time until we are out of children + PRInt32 kidIndex = NextChildOffset(); + nsIFrame* prevKidFrame = LastChild(); + nsIFrame* kidFrame = nsnull; + for (;;) { + // Get the next content object + nsIContent* kid = mContent->ChildAt(kidIndex); + if (nsnull == kid) { + result = frComplete; + break; + } + + // Resolve style for the kid + nsIStyleContext* kidSC = aCX->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + + // Is it a floater? + if (kidMol->floats != NS_STYLE_FLOAT_NONE) { + PlaceholderFrame::NewFrame(&kidFrame, kid, kidIndex, this); + kidFrame->SetStyleContext(kidSC); + } else if (nsnull == kidPrevInFlow) { + // Create initial frame for the child + nsIContentDelegate* kidDel; + nsresult fr; + switch (kidMol->display) { + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + // Pseudo block frames do not contain other block elements + // unless the block element would be the first child. + if (IsPseudoFrame()) { + // If we're being used as a pseudo frame, i.e. we map the same + // content as our parent then we want to indicate we're complete; + // otherwise we'll be continued and go on mapping children... + + // It better be true that we are not being asked to flow a + // block element as our first child. That means the body + // decided it needed a pseudo-frame when it shouldn't have. + NS_ASSERTION(nsnull != mFirstChild, "bad body"); + + NS_RELEASE(kidSC); + NS_RELEASE(kid); + result = frComplete; + goto done; + } + // FALL THROUGH (and create frame) + + case NS_STYLE_DISPLAY_INLINE: + kidDel = kid->GetDelegate(aCX); + kidFrame = kidDel->CreateFrame(aCX, kid, kidIndex, this); + NS_RELEASE(kidDel); + break; + + default: + NS_ASSERTION(nsnull == kidPrevInFlow, "bad prev in flow"); + fr = nsFrame::NewFrame(&kidFrame, kid, kidIndex, this); + break; + } + kidFrame->SetStyleContext(kidSC); + } else { + // Since kid has a prev-in-flow, use that to create the next + // frame. + kidFrame = kidPrevInFlow->CreateContinuingFrame(aCX, this); + } + + // Link child frame into the list of children. If the frame ends + // up not fitting and getting pushed, the PushKids code will fixup + // the child count for us. + if (nsnull != prevKidFrame) { + NS_ASSERTION(nsnull == prevKidFrame->GetNextSibling(), "bad append"); + prevKidFrame->SetNextSibling(kidFrame); + } else { + NS_ASSERTION(nsnull == mFirstChild, "bad create"); + mFirstChild = kidFrame; + SetFirstContentOffset(kidFrame); + } + prevKidFrame = kidFrame; + mChildCount++; + + // Reflow child frame as many times as necessary until it is + // complete. + ReflowStatus status; + do { + PRIntn placeStatus = PlaceAndReflowChild(aCX, aState, kidFrame, kidMol); + status = aState.reflowStatus; + if (0 == (placeStatus & PLACE_FIT)) { + // We ran out of room. + mLastContentIsComplete = PRBool(nsnull == kidFrame->GetNextInFlow()); + PushKids(aState); + + NS_RELEASE(kid); + NS_RELEASE(kidSC); + goto push_done; + } + + // Did the child complete? + prevKidFrame = kidFrame; + if (frNotComplete == status) { + // Child didn't complete so create a continuing frame + kidPrevInFlow = kidFrame; + nsIFrame* continuingFrame = kidFrame->CreateContinuingFrame(aCX, this); + + // Add the continuing frame to the sibling list + continuingFrame->SetNextSibling(kidFrame->GetNextSibling()); + kidFrame->SetNextSibling(continuingFrame); + kidFrame = continuingFrame; + mChildCount++; + + // Switch to new kid style + NS_RELEASE(kidSC); + kidSC = kidFrame->GetStyleContext(aCX); + kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + } + NS_ASSERTION(nsnull == kidFrame->GetNextInFlow(), "huh?"); + } while (frNotComplete == status); + NS_RELEASE(kid); + NS_RELEASE(kidSC); + + // The child that we just reflowed is complete + NS_ASSERTION(nsnull == kidFrame->GetNextInFlow(), "bad child flow list"); + kidIndex++; + kidPrevInFlow = nsnull; + } + + done: + // To get here we either completely reflowed all our appended + // children OR we are a pseudo-frame and we ran into a block + // element. In either case our last content MUST be complete. + NS_ASSERTION(PR_TRUE == aState.lastContentIsComplete, "bad state"); + + NS_ASSERTION(LastChild() == prevKidFrame, "bad last child"); + SetLastContentOffset(prevKidFrame); + + push_done: +#ifdef NS_DEBUG + PRInt32 len = LengthOf(mFirstChild); + NS_ASSERTION(len == mChildCount, "bad child count"); + VerifyLastIsComplete(); +#endif + return result; +} + +/** + * Pullup frames from our next in flow and try to place them. Before + * this is called our previously mapped children, if any have been + * reflowed which means that the block reflow state's x and y + * coordinates and other data are ready to go. + * + * Return true if we pulled everything up. + */ +PRBool +nsBlockFrame::PullUpChildren(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": pullup (childCount=%d) [%d,%d,%c]\n", + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif + + PRBool result = PR_TRUE; + nsBlockFrame* nextInFlow = (nsBlockFrame*) mNextInFlow; + nsIFrame* prevKidFrame = LastChild(); + while (nsnull != nextInFlow) { + // Get first available frame from the next-in-flow + nsIFrame* kidFrame = PullUpOneChild(nextInFlow, prevKidFrame); + if (nsnull == kidFrame) { + // We've pulled up all the children from that next-in-flow, so + // move to the next next-in-flow. + nextInFlow = (nsBlockFrame*) nextInFlow->mNextInFlow; + continue; + } + + // Get style information for the pulled up kid + nsIContent* kid = kidFrame->GetContent(); + nsIStyleContext* kidSC = aCX->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + + ReflowStatus status; + do { + PRIntn placeStatus = PlaceAndReflowChild(aCX, aState, kidFrame, kidMol); + status = aState.reflowStatus; + if (0 == (placeStatus & PLACE_FIT)) { + // Push the kids that didn't fit back down to the next-in-flow + mLastContentIsComplete = PRBool(nsnull == kidFrame->GetNextInFlow()); + PushKids(aState); + + result = PR_FALSE; + NS_RELEASE(kid); + NS_RELEASE(kidSC); + goto push_done; + } + + if (frNotComplete == status) { + // Child is not complete + nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); + if (nsnull == kidNextInFlow) { + // Create a continuing frame for the incomplete child + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aCX, this); + + // Add the continuing frame to our sibling list. + continuingFrame->SetNextSibling(kidFrame->GetNextSibling()); + kidFrame->SetNextSibling(continuingFrame); + prevKidFrame = kidFrame; + kidFrame = continuingFrame; + mChildCount++; + + // Switch to new kid style + NS_RELEASE(kidSC); + kidSC = kidFrame->GetStyleContext(aCX); + kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + } else { + // The child has a next-in-flow, but it's not one of ours. + // It *must* be in one of our next-in-flows. Collect it + // then. + NS_ASSERTION(kidNextInFlow->GetGeometricParent() != this, + "busted kid next-in-flow"); + break; + } + } + } while (frNotComplete == status); + NS_RELEASE(kid); + NS_RELEASE(kidSC); + + prevKidFrame = kidFrame; + } + + if (nsnull != prevKidFrame) { + // The only way we can get here is by pulling up every last child + // in our next-in-flows (and reflowing any continunations they + // have). Therefore we KNOW that our last child is complete. + NS_ASSERTION(PR_TRUE == aState.lastContentIsComplete, "bad state"); + NS_ASSERTION(LastChild() == prevKidFrame, "bad last child"); + SetLastContentOffset(prevKidFrame); + } + + push_done:; + + if (result == PR_FALSE) { + // If our next-in-flow is empty OR our next next-in-flow is empty + // then adjust the offsets of all of the empty next-in-flows. + nextInFlow = (nsBlockFrame*) mNextInFlow; + if ((0 == nextInFlow->mChildCount) || + ((nsnull != nextInFlow->mNextInFlow) && + (0 == ((nsBlockFrame*)(nextInFlow->mNextInFlow))->mChildCount))) { + // We didn't pullup everything and we need to fixup one of our + // next-in-flows content offsets. + AdjustOffsetOfEmptyNextInFlows(); + } + } + + +#ifdef NS_DEBUG + PRInt32 len = LengthOf(mFirstChild); + NS_ASSERTION(len == mChildCount, "bad child count"); + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": pullup %sok (childCount=%d) [%d,%d,%c]\n", + (result ? "" : "NOT "), + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif + return result; +} + +void nsBlockFrame::SetupState(nsIPresContext* aCX, + nsBlockReflowState& aState, + const nsSize& aMaxSize, + nsSize* aMaxElementSize, + nsISpaceManager* aSpaceManager) +{ + // Setup reflow state + nsStyleMolecule* mol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + nsStyleFont* font = + (nsStyleFont*)mStyleContext->GetData(kStyleFontSID); + aState.Init(aMaxSize, aMaxElementSize, font, mol, aSpaceManager); + + // Apply border and padding adjustments for regular frames only + if (PR_FALSE == IsPseudoFrame()) { + aState.borderPadding = mol->borderPadding; + aState.y = mol->borderPadding.top; + aState.availSize.width -= + (mol->borderPadding.left + mol->borderPadding.right); + aState.availSize.height -= + (mol->borderPadding.top + mol->borderPadding.bottom); + } else { + aState.borderPadding.SizeTo(0, 0, 0, 0); + } + + // Setup initial list ordinal value + nsIAtom* tag = mContent->GetTag(); + if ((tag == nsHTMLAtoms::ul) || (tag == nsHTMLAtoms::ol) || + (tag == nsHTMLAtoms::menu) || (tag == nsHTMLAtoms::dir)) { + nsHTMLValue value; + if (eContentAttr_HasValue == + ((nsIHTMLContent*)mContent)->GetAttribute(nsHTMLAtoms::start, value)) { + if (eHTMLUnit_Absolute == value.GetUnit()) { + aState.nextListOrdinal = value.GetIntValue(); + } + } + } + NS_RELEASE(tag); + + mCurrentState = &aState; +} + +#include "nsUnitConversion.h"/* XXX */ +nsIFrame::ReflowStatus +nsBlockFrame::ResizeReflow(nsIPresContext* aCX, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsSize* aMaxElementSize) +{ + nsBlockReflowState state; + SetupState(aCX, state, aMaxSize, aMaxElementSize, aSpaceManager); + return DoResizeReflow(aCX, state, aDesiredRect); +} + +nsIFrame::ReflowStatus +nsBlockFrame::DoResizeReflow(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsRect& aDesiredRect) +{ +#ifdef NS_DEBUG + PreReflowCheck(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": resize reflow %g,%g\n", + NS_TWIPS_TO_POINTS_FLOAT(aState.availSize.width), + NS_TWIPS_TO_POINTS_FLOAT(aState.availSize.height)); + DumpFlow(); +#endif + + // Zap old line data + if (nsnull != mLines) { + delete mLines; + mLines = nsnull; + } + mNumLines = 0; + + // Check for an overflow list + MoveOverflowToChildList(); + + // Before we start reflowing, cache a pointer to our state structure + // so that inline frames can find it. + nsIPresShell* shell = aCX->GetShell(); + shell->PutCachedData(this, &aState); + + // First reflow any existing frames + PRBool reflowMappedOK = PR_TRUE; + ReflowStatus status = frComplete; + if (nsnull != mFirstChild) { + reflowMappedOK = ReflowMappedChildren(aCX, aState); + if (!reflowMappedOK) { + status = frNotComplete; + } + } + + if (reflowMappedOK) { + // Any space left? + nscoord yb = aState.borderPadding.top + aState.availSize.height; + if ((nsnull != mFirstChild) && (aState.y >= yb)) { + // No space left. Don't try to pull-up children or reflow + // unmapped. We need to return the correct completion status, + // so see if there is more to reflow. + if (MoreToReflow(aCX)) { + status = frNotComplete; + } + } else if (MoreToReflow(aCX)) { + // Try and pull-up some children from a next-in-flow + if ((nsnull == mNextInFlow) || PullUpChildren(aCX, aState)) { + // If we still have unmapped children then create some new frames + if (MoreToReflow(aCX)) { + status = ReflowAppendedChildren(aCX, aState); + } + } else { + // We were unable to pull-up all the existing frames from the + // next in flow + status = frNotComplete; + } + } + } + + // Deal with last line - make sure it gets vertically and + // horizontally aligned. This also updates the state's y coordinate + // which is good because that's how we size ourselves. + if (0 != aState.lineLength) { + if (!AdvanceToNextLine(aCX, aState)) { + // The last line of output doesn't fit. Push all of the kids to + // the next in flow and change our reflow status to not complete + // so that we are continued. +#ifdef NOISY + ListTag(stdout); + printf(": pushing kids since last line doesn't fit\n"); +#endif + + PushKids(aState); + status = frNotComplete; + } + } + + if (frComplete == status) { + // Don't forget to add in the bottom margin from our last child. + // Only add it in if there is room for it. + nscoord margin = aState.prevMaxPosBottomMargin - + aState.prevMaxNegBottomMargin; + nscoord y = aState.y + margin; + if (y <= aState.borderPadding.top + aState.availSize.height) { + aState.y = y; + } + } + + // Now that reflow has finished, remove the cached pointer + shell->RemoveCachedData(this); + NS_RELEASE(shell); + + // Translate state.lineLengths into an integer array + mNumLines = aState.lineLengths.Count(); + if (mNumLines > 0) { + mLines = new PRInt32[mNumLines]; + for (PRInt32 i = 0; i < mNumLines; i++) { + PRInt32 ll = (PRInt32) aState.lineLengths.ElementAt(i); + mLines[i] = ll; + } + } + + if (!aState.unconstrainedWidth && aState.justifying) { + // Perform justification now that we know how many lines we have. + JustifyLines(aCX, aState); + } + + // Return our desired rect and our status + aDesiredRect.x = 0; + aDesiredRect.y = 0; + aDesiredRect.width = aState.kidXMost + aState.borderPadding.right; + if (!aState.unconstrainedWidth) { + // Make sure we're at least as wide as the max size we were given + nscoord maxWidth = aState.availSize.width + aState.borderPadding.left + + aState.borderPadding.right; + + if (aDesiredRect.width < maxWidth) { + aDesiredRect.width = maxWidth; + } + } + aState.y += aState.borderPadding.bottom; + aDesiredRect.height = aState.y; + +#ifdef NS_DEBUG + PostReflowCheck(status); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": resize reflow %g,%g %scomplete [%d,%d,%c]\n", + NS_TWIPS_TO_POINTS_FLOAT(aState.availSize.width), + NS_TWIPS_TO_POINTS_FLOAT(aState.availSize.height), + ((status == frNotComplete) ? "NOT " : ""), + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F') + ); + DumpFlow(); +#endif + mCurrentState = nsnull; + return status; +} + +void nsBlockFrame::JustifyLines(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ + // XXX we don't justify the last line; what if we are continued, + // should we do it then? + nsIFrame* kid = mFirstChild; + for (PRInt32 i = 0; i < mNumLines; i++) { + nsIFrame* lineStart = kid; + PRInt32 lineLength = mLines[i]; + if (i < mNumLines - 1) { + if (1 == lineLength) { + // For lines with one element on them we can take a shortcut and + // let them do the justification. Note that we still call + // JustifyReflow even if the available space is zero in case the + // child is a hunk of text that ends in whitespace. The whitespace + // will be distributed elsewhere causing a proper flush right look + // for the last word. + nsRect r; + kid->GetRect(r); + nscoord maxWidth = aState.availSize.width; + nscoord availableSpace = maxWidth - r.width; + nscoord maxAvailSpace = nscoord(maxWidth * 0.1f); + if ((availableSpace >= 0) && (availableSpace < maxAvailSpace)) { + kid->JustifyReflow(aCX, availableSpace); + kid->SizeTo(r.width + availableSpace, r.height); + } + kid = kid->GetNextSibling(); + } else { + // XXX Get justification of multiple elements working + while (--lineLength >= 0) { + kid = kid->GetNextSibling(); + } + } + } + + // Finally, now that the in-flow positions of the line's frames are + // known we can apply relative positioning if any of them need it. + nsCSSLayout::RelativePositionChildren(aCX, this, aState.mol, + lineStart, mLines[i]); + } +} + +nsIFrame* nsBlockFrame::CreateContinuingFrame(nsIPresContext* aCX, + nsIFrame* aParent) +{ + nsBlockFrame* cf = new nsBlockFrame(mContent, mIndexInParent, aParent); + PrepareContinuingFrame(aCX, aParent, cf); + return cf; +} + +nsIFrame::ReflowStatus +nsBlockFrame::IncrementalReflow(nsIPresContext* aCX, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsReflowCommand& aReflowCommand) +{ + ReflowStatus status = frComplete; + + if (aReflowCommand.GetTarget() == this) { + // XXX for now, just do a complete reflow mapped (it'll kinda + // work, but it's slow) + + nsBlockReflowState state; + SetupState(aCX, state, aMaxSize, nsnull, aSpaceManager); + PRBool reflowMappedOK = ReflowMappedChildren(aCX, state); + if (!reflowMappedOK) { + status = frNotComplete; + } + } else { + // XXX not yet implemented + NS_ABORT(); + // XXX work to compute initial state goes *HERE* + aDesiredRect.x = 0; + aDesiredRect.y = 0; + aDesiredRect.width = 0; + aDesiredRect.height = 0; + } + + mCurrentState = nsnull; + return status; +} + +PRBool nsBlockFrame::IsLeftMostChild(nsIFrame* aFrame) +{ + do { + nsIFrame* parent = aFrame->GetGeometricParent(); + + // See if there are any non-zero sized child frames that precede aFrame + // in the child list + nsIFrame* child = parent->FirstChild(); + + while ((nsnull != child) && (aFrame != child)) { + // Is the child zero-sized? + if ((child->GetWidth() > 0) || (child->GetHeight() > 0)) { + // We found a non-zero sized child frame that precedes aFrame + return PR_FALSE; + } + + child = child->GetNextSibling(); + } + + // aFrame is the left-most non-zero sized frame in its geometric parent. + // Walk up one level and check that its parent is left-most as well + aFrame = parent; + } while (aFrame != this); + + return PR_TRUE; +} + +PRBool nsBlockFrame::AddFloater(nsIPresContext* aCX, + nsIFrame* aFloater, + PlaceholderFrame* aPlaceholder) +{ + // Get the frame associated with the space manager, and get its nsIAnchoredItems + // interface + nsIFrame* frame = mCurrentState->spaceManager->GetFrame(); + nsIAnchoredItems* anchoredItems = nsnull; + + frame->QueryInterface(kIAnchoredItemsIID, (void**)&anchoredItems); + NS_ASSERTION(nsnull != anchoredItems, "no anchored items interface"); + + if (nsnull != anchoredItems) { + anchoredItems->AddAnchoredItem(aFloater, nsIAnchoredItems::anHTMLFloater, this); + PlaceFloater(aCX, aFloater, aPlaceholder); + return PR_TRUE; + } + + return PR_FALSE; +} + +// XXX The size of the floater needs to be taken into consideration if we're +// computing a maximum element size +void nsBlockFrame::PlaceFloater(nsIPresContext* aCX, + nsIFrame* aFloater, + PlaceholderFrame* aPlaceholder) +{ + // If the floater is the left-most non-zero size child frame then insert + // it before the current line; otherwise add it to the below-current-line + // todo list and we'll handle it when we flush out the line + if (IsLeftMostChild(aPlaceholder)) { + // Get the type of floater + nsIStyleContext* styleContext = aFloater->GetStyleContext(aCX); + nsStyleMolecule* mol = (nsStyleMolecule*)styleContext->GetData(kStyleMoleculeSID); + NS_RELEASE(styleContext); + + if (!mCurrentState->isInline) { + // Get the current band for this line + GetAvailableSpaceBand(*mCurrentState, mCurrentState->y + mCurrentState->topMargin); + } + + // Commit some space in the space manager + nsRect region; + + aFloater->GetRect(region); + region.y = mCurrentState->currentBand->rects[0].y; + + if (NS_STYLE_FLOAT_LEFT == mol->floats) { + region.x = mCurrentState->currentBand->rects[0].x; + } else { + NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == mol->floats, "bad float type"); + region.x = mCurrentState->currentBand->rects[0].XMost() - region.width; + } + + // XXX Don't forget the floater's margins... + mCurrentState->spaceManager->Translate(mCurrentState->borderPadding.left, 0); + mCurrentState->spaceManager->AddRectRegion(region); + + // Set the origin of the floater in world coordinates + nscoord worldX, worldY; + + mCurrentState->spaceManager->GetTranslation(worldX, worldY); + aFloater->MoveTo(region.x + worldX, region.y + worldY); + mCurrentState->spaceManager->Translate(-mCurrentState->borderPadding.left, 0); + + // Update the band of available space to reflect space taken up by the floater + GetAvailableSpaceBand(*mCurrentState, mCurrentState->y + mCurrentState->topMargin); + } else { + // Add the floater to our to-do list + mCurrentState->floaterToDo.AppendElement(aFloater); + } +} + +void nsBlockFrame::ContentAppended(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer) +{ + // Zip down to the end-of-flow + nsBlockFrame* flow = this; + for (;;) { + nsBlockFrame* next = (nsBlockFrame*) flow->GetNextInFlow(); + if (nsnull == next) { + break; + } + flow = next; + } + + PRInt32 kidIndex = flow->NextChildOffset(); + PRInt32 startIndex = kidIndex; + nsIFrame* prevKidFrame = flow->LastChild(); + nsIFrame* kidFrame = nsnull; + for (;;) { + // Get the next content object + nsIContent* kid = mContent->ChildAt(kidIndex); + if (nsnull == kid) { + break; + } + + // Resolve style for the kid + nsIStyleContext* kidSC = aPresContext->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + + // Is it a floater? + if (kidMol->floats != NS_STYLE_FLOAT_NONE) { + PlaceholderFrame::NewFrame(&kidFrame, kid, kidIndex, this); + } else { + // Create initial frame for the child + nsIContentDelegate* kidDel; + nsresult fr; + switch (kidMol->display) { + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + // Pseudo block frames do not contain other block elements + // unless the block element would be the first child. + if (IsPseudoFrame()) { + // Update last content offset now that we are done drawing + // children from our parent. + SetLastContentOffset(prevKidFrame); + + // It better be true that we are not being asked to flow a + // block element as our first child. That means the body + // decided it needed a pseudo-frame when it shouldn't have. + NS_ASSERTION(nsnull != mFirstChild, "bad body"); + + NS_RELEASE(kidSC); + NS_RELEASE(kid); + + return; + } + // FALL THROUGH (and create frame) + + case NS_STYLE_DISPLAY_INLINE: + kidDel = kid->GetDelegate(aPresContext); + kidFrame = kidDel->CreateFrame(aPresContext, kid, kidIndex, this); + NS_RELEASE(kidDel); + break; + + default: + fr = nsFrame::NewFrame(&kidFrame, kid, kidIndex, this); + break; + } + } + kidFrame->SetStyleContext(kidSC); + NS_RELEASE(kidSC); + NS_RELEASE(kid); + + // Link child frame into the list of children + if (nsnull != prevKidFrame) { + NS_ASSERTION(nsnull == prevKidFrame->GetNextSibling(), "bad append"); + prevKidFrame->SetNextSibling(kidFrame); + } else { + NS_ASSERTION(nsnull == mFirstChild, "bad create"); + mFirstChild = kidFrame; + SetFirstContentOffset(kidFrame); + } + prevKidFrame = kidFrame; + kidIndex++; + mChildCount++; + } + SetLastContentOffset(prevKidFrame); + + // If this is a pseudo-frame then our parent will generate the + // reflow command. Otherwise, if the container is us then we should + // generate the reflow command because we were directly called. + if (!IsPseudoFrame() && (aContainer == mContent)) { + nsReflowCommand* rc = + new nsReflowCommand(aPresContext, flow, nsReflowCommand::FrameAppended, + startIndex); + aShell->AppendReflowCommand(rc); + } +} + +PRIntn nsBlockFrame::GetSkipSides() const +{ + PRIntn skip = 0; + if (nsnull != mPrevInFlow) { + skip |= 1 << NS_SIDE_TOP; + } + if (nsnull != mNextInFlow) { + skip |= 1 << NS_SIDE_BOTTOM; + } + return skip; +} + +nsHTMLFrameType nsBlockFrame::GetFrameType() const +{ + return eHTMLFrame_Block; +} + +void nsBlockFrame::ListTag(FILE* out) const +{ + if ((nsnull != mGeometricParent) && IsPseudoFrame()) { + fprintf(out, "*block(%d)@%p", mIndexInParent, this); + } else { + nsHTMLContainerFrame::ListTag(out); + } +} + +#ifdef NS_DEBUG +void nsBlockFrame::DumpFlow() const +{ +#ifdef NOISY_FLOW + nsBlockFrame* flow = (nsBlockFrame*) mNextInFlow; + while (flow != 0) { + printf(" %p: [%d,%d,%c]\n", + flow, flow->mFirstContentOffset, flow->mLastContentOffset, + (flow->mLastContentIsComplete ? 'T' : 'F')); + flow = (nsBlockFrame*) flow->mNextInFlow; + } +#endif +} +#endif diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.h b/mozilla/layout/html/base/src/nsBlockReflowState.h new file mode 100644 index 00000000000..de26654f45d --- /dev/null +++ b/mozilla/layout/html/base/src/nsBlockReflowState.h @@ -0,0 +1,2030 @@ +/* -*- 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 "nsBlockFrame.h" +#include "nsSize.h" +#include "nsIAnchoredItems.h" +#include "nsIContent.h" +#include "nsIContentDelegate.h" +#include "nsISpaceManager.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsIPresContext.h" +#include "nsMargin.h" +#include "nsHTMLIIDs.h" +#include "nsCSSLayout.h" +#include "nsCRT.h" +#include "nsIPresShell.h" +#include "nsReflowCommand.h" +#include "nsPlaceholderFrame.h" +#include "nsHTMLAtoms.h" +#include "nsHTMLValue.h" +#include "nsIHTMLContent.h" + +#ifdef NS_DEBUG +#undef NOISY +#undef NOISY_FLOW +#else +#undef NOISY +#undef NOISY_FLOW +#endif + +static NS_DEFINE_IID(kIRunaroundIID, NS_IRUNAROUND_IID); +static NS_DEFINE_IID(kIFloaterContainerIID, NS_IFLOATERCONTAINER_IID); +static NS_DEFINE_IID(kIAnchoredItemsIID, NS_IANCHOREDITEMS_IID); +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); +static NS_DEFINE_IID(kStyleFontSID, NS_STYLEFONT_SID); + +struct BlockBandData : public nsBandData { + nsRect data[5]; + + BlockBandData() {size = 5; rects = data;} +}; + +// XXX Bugs +// 1. right to left reflow can generate negative x coordinates. + +// XXX Speedup idea (all containers) + +// If I reflow a child and it gives back not-complete status then +// there is no sense in trying to pullup children. For blocks, it's a +// little more complicated unless the child is a block - if the child +// is a block, then we must be out of room hence we should stop. If +// the child is not a block then our line should be flushed (see #2 +// below) if our line is already empty then we must be out of room. + +// For inline frames and column frames, if we reflow a child and get +// back not-complete status then we should bail immediately because we +// are out of room. + +// XXX Speedup ideas: +// 1. change pullup code to use line information from next in flow +// 2. we can advance to next line immediately after reflowing something +// and noticing that it's not complete. +// 3. pass down last child information in aState so that pullup, etc., +// don't need to recompute it + +// XXX TODO: +// 0. Move justification into line flushing code + +// 1. To get ebina margins I need "auto" information from the style +// system margin's. A bottom/top margin of auto will then be computed like +// ebina computes it [however the heck that is]. + +// 2. kicking out floaters and talking with floater container to adjust +// left and right margins + +nsBlockReflowState::nsBlockReflowState() +{ +} + +void nsBlockReflowState::Init(const nsSize& aMaxSize, + nsSize* aMaxElementSize, + nsStyleFont* aFont, + nsStyleMolecule* aMol, + nsISpaceManager* aSpaceManager) +{ + firstLine = PR_TRUE; + allowLeadingWhitespace = PR_FALSE; + breakAfterChild = PR_FALSE; + breakBeforeChild = PR_FALSE; + firstChildIsInsideBullet = PR_FALSE; + nextListOrdinal = -1; + column = 0; + + spaceManager = aSpaceManager; + currentBand = new BlockBandData; + font = aFont; + mol = aMol; + availSize.width = aMaxSize.width; + availSize.height = aMaxSize.height; + maxElementSize = aMaxElementSize; + if (nsnull != aMaxElementSize) { + aMaxElementSize->width = 0; + aMaxElementSize->height = 0; + } + + kidXMost = 0; + x = 0; + y = 0; + + isInline = PR_FALSE; + currentLineNumber = 0; + lineStart = nsnull; + lineLength = 0; + ascents = ascentBuf; + maxAscent = 0; + maxDescent = 0; + lineWidth = 0; + maxPosBottomMargin = 0; + maxNegBottomMargin = 0; + lineMaxElementSize.width = 0; + lineMaxElementSize.height = 0; + lastContentIsComplete = PR_TRUE; + + maxAscents = sizeof(ascentBuf) / sizeof(ascentBuf[0]); + needRelativePos = PR_FALSE; + + prevLineLastFrame = nsnull; + prevLineHeight = 0; + topMargin = 0; + prevMaxPosBottomMargin = 0; + prevMaxNegBottomMargin = 0; + prevLineLastContentIsComplete = PR_TRUE; + + unconstrainedWidth = PRBool(aMaxSize.width == NS_UNCONSTRAINEDSIZE); + unconstrainedHeight = PRBool(aMaxSize.height == NS_UNCONSTRAINEDSIZE); + + justifying = (NS_STYLE_TEXT_ALIGN_JUSTIFY == mol->textAlign) && + (NS_STYLE_WHITESPACE_PRE != mol->whiteSpace); + reflowStatus = nsIFrame::frNotComplete; +} + +nsBlockReflowState::~nsBlockReflowState() +{ + if (ascents != ascentBuf) { + delete ascents; + } + delete currentBand; +} + +void nsBlockReflowState::AddAscent(nscoord aAscent) +{ + NS_PRECONDITION(lineLength <= maxAscents, "bad line length"); + if (lineLength == maxAscents) { + maxAscents *= 2; + nscoord* newAscents = new nscoord[maxAscents]; + if (nsnull != newAscents) { + nsCRT::memcpy(newAscents, ascents, sizeof(nscoord) * lineLength); + if (ascents != ascentBuf) { + delete ascents; + } + ascents = newAscents; + } else { + // Yikes! Out of memory! + return; + } + } + ascents[lineLength] = aAscent; +} + +void nsBlockReflowState::AdvanceToNextLine(nsIFrame* aPrevLineLastFrame, + nscoord aPrevLineHeight) +{ + firstLine = PR_FALSE; + allowLeadingWhitespace = PR_FALSE; + column = 0; + breakAfterChild = PR_FALSE; + breakBeforeChild = PR_FALSE; + lineStart = nsnull; + lineLength = 0; + currentLineNumber++; + maxAscent = 0; + maxDescent = 0; + lineWidth = 0; + needRelativePos = PR_FALSE; + + prevLineLastFrame = aPrevLineLastFrame; + prevLineHeight = aPrevLineHeight; + prevMaxPosBottomMargin = maxPosBottomMargin; + prevMaxNegBottomMargin = maxNegBottomMargin; + + // Remember previous line's lastContentIsComplete + prevLineLastContentIsComplete = lastContentIsComplete; + lastContentIsComplete = PR_TRUE; + + topMargin = 0; + maxPosBottomMargin = 0; + maxNegBottomMargin = 0; +} + +#ifdef NS_DEBUG +void nsBlockReflowState::DumpLine() +{ + nsIFrame* f = lineStart; + PRInt32 ll = lineLength; + while (--ll >= 0) { + printf(" "); + ((nsFrame*)f)->ListTag(stdout);/* XXX */ + printf("\n"); + f = f->GetNextSibling(); + } +} + +void nsBlockReflowState::DumpList() +{ + nsIFrame* f = lineStart; + while (nsnull != f) { + printf(" "); + ((nsFrame*)f)->ListTag(stdout);/* XXX */ + printf("\n"); + f = f->GetNextSibling(); + } +} +#endif + +//---------------------------------------------------------------------- + +nsresult nsBlockFrame::NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIFrame* it = new nsBlockFrame(aContent, aIndexInParent, aParent); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aInstancePtrResult = it; + return NS_OK; +} + +nsBlockFrame::nsBlockFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) + : nsHTMLContainerFrame(aContent, aIndexInParent, aParent) +{ +} + +nsBlockFrame::~nsBlockFrame() +{ + if (nsnull != mLines) { + delete mLines; + } +} + +nsresult +nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) +{ + NS_PRECONDITION(0 != aInstancePtr, "null ptr"); + if (NULL == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kIHTMLFrameTypeIID)) { + *aInstancePtr = (void*) ((nsIHTMLFrameType*) this); + return NS_OK; + } else if (aIID.Equals(kIRunaroundIID)) { + *aInstancePtr = (void*) ((nsIRunaround*) this); + return NS_OK; + } else if (aIID.Equals(kIFloaterContainerIID)) { + *aInstancePtr = (void*) ((nsIFloaterContainer*) this); + return NS_OK; + } + return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr); +} + +// Computes the top margin to use for this child frames based on its display +// type and the display type of the previous child frame. +// +// Adjacent vertical margins between block-level elements are collapsed. +nscoord nsBlockFrame::GetTopMarginFor(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsStyleMolecule* aKidMol, + PRBool aIsInline) +{ + if (aIsInline) { + // Just use whatever the previous bottom margin was + return aState.prevMaxPosBottomMargin - aState.prevMaxNegBottomMargin; + } else { + nscoord maxNegTopMargin = 0; + nscoord maxPosTopMargin = 0; + if (aKidMol->margin.top < 0) { + maxNegTopMargin = -aKidMol->margin.top; + } else { + maxPosTopMargin = aKidMol->margin.top; + } + + nscoord maxPos = PR_MAX(aState.prevMaxPosBottomMargin, maxPosTopMargin); + nscoord maxNeg = PR_MAX(aState.prevMaxNegBottomMargin, maxNegTopMargin); + return maxPos - maxNeg; + } +} + +void nsBlockFrame::PlaceBelowCurrentLineFloaters(nsIPresContext* aCX, + nsBlockReflowState& aState, + nscoord aY) +{ + NS_PRECONDITION(aState.floaterToDo.Count() > 0, "no floaters"); + + // XXX Factor this code with PlaceFloater()... + PRInt32 numFloaters = aState.floaterToDo.Count(); + + for (PRInt32 i = 0; i < numFloaters; i++) { + nsIFrame* floater = (nsIFrame*)aState.floaterToDo[i]; + nsRect region; + + // Get the band of available space + // XXX This is inefficient to do this inside the loop... + GetAvailableSpaceBand(aState, aY); + + // Get the type of floater + nsIStyleContext* styleContext = floater->GetStyleContext(aCX); + nsStyleMolecule* mol = (nsStyleMolecule*)styleContext->GetData(kStyleMoleculeSID); + NS_RELEASE(styleContext); + + floater->GetRect(region); + region.y = mCurrentState->currentBand->rects[0].y; + + if (NS_STYLE_FLOAT_LEFT == mol->floats) { + region.x = mCurrentState->currentBand->rects[0].x; + } else { + NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == mol->floats, "bad float type"); + region.x = mCurrentState->currentBand->rects[0].XMost() - region.width; + } + + // XXX Don't forget the floater's margins... + mCurrentState->spaceManager->Translate(mCurrentState->borderPadding.left, 0); + mCurrentState->spaceManager->AddRectRegion(region); + + // Set the origin of the floater in world coordinates + nscoord worldX, worldY; + + mCurrentState->spaceManager->GetTranslation(worldX, worldY); + floater->MoveTo(region.x + worldX, region.y + worldY); + mCurrentState->spaceManager->Translate(-mCurrentState->borderPadding.left, 0); + } + aState.floaterToDo.Clear(); +} + +/** + * Flush a line out. Return true if the line fits in our available + * height. If the line does not fit then return false. When the line + * fits we advance the y coordinate, reset the x coordinate and + * prepare the nsBlockReflowState for the next line. + */ +PRBool nsBlockFrame::AdvanceToNextLine(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ + NS_PRECONDITION(aState.lineLength > 0, "bad line"); + NS_PRECONDITION(nsnull != aState.lineStart, "bad line"); + + nscoord y = aState.y + aState.topMargin; + nscoord lineHeight; + + if (aState.isInline) { + // Vertically align the children on this line, returning the height of + // the line upon completion. + lineHeight = nsCSSLayout::VerticallyAlignChildren(aCX, this, aState.font, y, + aState.lineStart, aState.lineLength, + aState.ascents, aState.maxAscent); + + // Any below current line floaters to place? + if (aState.floaterToDo.Count() > 0) { + PlaceBelowCurrentLineFloaters(aCX, aState, y + lineHeight); + // XXX Factor in the height of the floaters as well when considering + // whether the line fits. + // The default policy is that if there isn't room for the floaters then + // both the line and the floaters are pushed to the next-in-flow... + } + } else { + lineHeight = aState.lineStart->GetHeight(); + } + + // The first line always fits + if (aState.currentLineNumber > 0) { + nscoord yb = aState.borderPadding.top + aState.availSize.height; + if (y + lineHeight > yb) { + // After vertical alignment of the children and factoring in the + // proper margin, the line doesn't fit. + return PR_FALSE; + } + } + + if (aState.isInline) { + // Check if the right-edge of the line exceeds our running x-most + nscoord xMost = aState.borderPadding.left + aState.lineWidth; + if (xMost > aState.kidXMost) { + aState.kidXMost = xMost; + } + } + + // Advance the y coordinate to the new position where the next + // line or block element will go. + aState.y = y + lineHeight; + aState.x = 0; + + // Now that the vertical alignment is done we can perform horizontal + // alignment and relative positioning. Skip all of these if we are + // doing an unconstrained (in x) reflow. There's no point in doing + // the work if we *know* we are going to reflowed again. + if (!aState.unconstrainedWidth) { + nsCSSLayout::HorizontallyPlaceChildren(aCX, this, aState.mol, + aState.lineStart, aState.lineLength, + aState.lineWidth, + aState.availSize.width); + + // Finally, now that the in-flow positions of the line's frames are + // known we can apply relative positioning if any of them need it. + if (!aState.justifying) { + nsCSSLayout::RelativePositionChildren(aCX, this, aState.mol, + aState.lineStart, + aState.lineLength); + } + } + + // Record line length + aState.lineLengths.AppendElement((void*)aState.lineLength); + + // Find the last frame in the line + // XXX keep this as running state in the nsBlockReflowState + nsIFrame* lastFrame = aState.lineStart; + PRInt32 lineLen = aState.lineLength - 1; + while (--lineLen >= 0) { + lastFrame = lastFrame->GetNextSibling(); + } + + // Update maxElementSize + if (nsnull != aState.maxElementSize) { + nsSize& lineMax = aState.lineMaxElementSize; + nsSize* maxMax = aState.maxElementSize; + if (lineMax.width > maxMax->width) { + maxMax->width = lineMax.width; + } + if (lineMax.height > maxMax->height) { + maxMax->height = lineMax.height; + } + aState.lineMaxElementSize.width = 0; + aState.lineMaxElementSize.height = 0; + } + + // Advance to the next line + aState.AdvanceToNextLine(lastFrame, lineHeight); + + return PR_TRUE; +} + +/** + * Add an inline child to the current line. Advance various running + * values after placement. + */ +void nsBlockFrame::AddInlineChildToLine(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsIFrame* aKidFrame, + nsReflowMetrics& aKidSize, + nsSize* aKidMaxElementSize, + nsStyleMolecule* aKidMol) +{ + NS_PRECONDITION(nsnull != aState.lineStart, "bad line"); + + PRIntn direction = aState.mol->direction; + if (NS_STYLE_POSITION_RELATIVE == aKidMol->positionFlags) { + aState.needRelativePos = PR_TRUE; + } + + // Place and size the child + // XXX add in left margin from kid + nsRect r; + r.y = aState.y; + r.width = aKidSize.width; + r.height = aKidSize.height; + if (NS_STYLE_DIRECTION_LTR == aState.mol->direction) { + // Left to right positioning. + r.x = aState.borderPadding.left + aState.x + aKidMol->margin.left; + aState.x += aKidSize.width + aKidMol->margin.left + aKidMol->margin.right; + } else { + // Right to left positioning + // XXX what should we do when aState.x goes negative??? + r.x = aState.x - aState.borderPadding.right - aKidMol->margin.right - aKidSize.width; + aState.x -= aKidSize.width + aKidMol->margin.right + aKidMol->margin.left; + } + aKidFrame->SetRect(r); + aState.AddAscent(aKidSize.ascent); + aState.lineWidth += aKidSize.width; + aState.lineLength++; + + // Update maximums for the line + if (aKidSize.ascent > aState.maxAscent) { + aState.maxAscent = aKidSize.ascent; + } + if (aKidSize.descent > aState.maxDescent) { + aState.maxDescent = aKidSize.descent; + } + // Update running margin maximums + if (aState.firstChildIsInsideBullet && (aKidFrame == mFirstChild)) { + // XXX temporary code. Since the molecule for the bullet frame + // is the same as the LI frame, we get bad style information. + // ignore it. + } else { + nscoord margin; +#if 0 + // XXX CSS2 spec says that top/bottom margin don't affect line height + // calculation. We're waiting for clarification on this issue... + if ((margin = aKidMol->margin.top) < 0) { + margin = -margin; + if (margin > aState.maxNegTopMargin) { + aState.maxNegTopMargin = margin; + } + } else { + if (margin > aState.maxPosTopMargin) { + aState.maxPosTopMargin = margin; + } + } +#endif + if ((margin = aKidMol->margin.bottom) < 0) { + margin = -margin; + if (margin > aState.maxNegBottomMargin) { + aState.maxNegBottomMargin = margin; + } + } else { + if (margin > aState.maxPosBottomMargin) { + aState.maxPosBottomMargin = margin; + } + } + } + + // Update line max element size + nsSize& mes = aState.lineMaxElementSize; + if (nsnull != aKidMaxElementSize) { + if (aKidMaxElementSize->width > mes.width) { + mes.width = aKidMaxElementSize->width; + } + if (aKidMaxElementSize->height > mes.height) { + mes.height = aKidMaxElementSize->height; + } + } +} + +// Places and sizes the block-level element, and advances the line. +// The rect is in the local coordinate space of the kid frame. +void nsBlockFrame::AddBlockChild(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsIFrame* aKidFrame, + nsRect& aKidRect, + nsSize* aKidMaxElementSize, + nsStyleMolecule* aKidMol) +{ + NS_PRECONDITION(nsnull != aState.lineStart, "bad line"); + + if (NS_STYLE_POSITION_RELATIVE == aKidMol->positionFlags) { + aState.needRelativePos = PR_TRUE; + } + + // Translate from the kid's coordinate space to our coordinate space + aKidRect.x += aState.borderPadding.left + aKidMol->margin.left; + aKidRect.y += aState.y + aState.topMargin; + + // Place and size the child + aKidFrame->SetRect(aKidRect); + + aState.AddAscent(aKidRect.height); + aState.lineLength++; + + // Is this the widest child frame? + nscoord xMost = aKidRect.XMost() + aKidMol->margin.right; + if (xMost > aState.kidXMost) { + aState.kidXMost = xMost; + } + + // Update the max element size + if (nsnull != aKidMaxElementSize) { + if (aKidMaxElementSize->width > aState.maxElementSize->width) { + aState.maxElementSize->width = aKidMaxElementSize->width; + } + if (aKidMaxElementSize->height > aState.maxElementSize->height) { + aState.maxElementSize->height = aKidMaxElementSize->height; + } + } + + // and the bottom line margin information which we'll use when placing + // the next child + if (aKidMol->margin.bottom < 0) { + aState.maxNegBottomMargin = -aKidMol->margin.bottom; + } else { + aState.maxPosBottomMargin = aKidMol->margin.bottom; + } + + // Update the running y-offset + aState.y += aKidRect.height + aState.topMargin; + + // Apply relative positioning if necessary + nsCSSLayout::RelativePositionChildren(aCX, this, aState.mol, aKidFrame, 1); + + // Advance to the next line + aState.AdvanceToNextLine(aKidFrame, aKidRect.height); +} + +/** + * Compute the available size for reflowing the given child at the + * current x,y position in the state. Note that this may return + * negative or zero width/height's if we are out of room. + */ +void nsBlockFrame::GetAvailSize(nsSize& aResult, + nsBlockReflowState& aState, + nsStyleMolecule* aKidMol, + PRBool aIsInline) +{ + // Determine the maximum available reflow height for the child + nscoord yb = aState.borderPadding.top + aState.availSize.height; + aResult.height = aState.unconstrainedHeight ? NS_UNCONSTRAINEDSIZE : + yb - aState.y - aState.topMargin; + + // Determine the maximum available reflow width for the child + if (aState.unconstrainedWidth) { + aResult.width = NS_UNCONSTRAINEDSIZE; + } else if (aIsInline) { + if (NS_STYLE_DIRECTION_LTR == aState.mol->direction) { + aResult.width = aState.currentBand->rects[0].XMost() - aState.x; + } else { + aResult.width = aState.x - aState.currentBand->rects[0].x; + } + } else { + // It's a block + aResult.width = aState.availSize.width - aKidMol->margin.left - + aKidMol->margin.right; + } +} + +/** + * Push all of the kids that we have not reflowed, starting at + * aState.lineStart. aPrevKid is the kid previous to aState.lineStart + * and is also our last child. Note that line length is NOT a + * reflection of the number of children we are actually pushing + * (because we don't break the sibling list as we add children to the + * line). + */ +void nsBlockFrame::PushKids(nsBlockReflowState& aState) +{ + nsIFrame* prevFrame = aState.prevLineLastFrame; + NS_PRECONDITION(nsnull != prevFrame, "pushing all kids"); + NS_PRECONDITION(prevFrame->GetNextSibling() == aState.lineStart, + "bad prev line"); + +#ifdef NS_DEBUG + PRInt32 numKids = LengthOf(mFirstChild); + NS_ASSERTION(numKids == mChildCount, "bad child count"); +#endif + +#ifdef NOISY + ListTag(stdout); + printf(": push kids (childCount=%d)\n", mChildCount); + DumpFlow(); +#endif + + PushChildren(aState.lineStart, prevFrame, mLastContentIsComplete); + SetLastContentOffset(prevFrame); + + // Set mLastContentIsComplete to the previous lines last content is + // complete now that the previous line's last child is our last + // child. + mLastContentIsComplete = aState.prevLineLastContentIsComplete; + + // Fix up child count + // XXX is there a better way? aState.lineLength doesn't work because + // we might be pushing more than just the pending line. + nsIFrame* kid = mFirstChild; + PRInt32 kids = 0; + while (nsnull != kid) { + kids++; + kid = kid->GetNextSibling(); + } + mChildCount = kids; + + // Make sure we have no lingering line data + aState.lineLength = 0; + aState.lineStart = nsnull; + +#ifdef NOISY + ListTag(stdout); + printf(": push kids done (childCount=%d) [%c]\n", mChildCount, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif +} + +/** + * Gets a band of available space starting at the specified y-offset. Assumes + * the local coordinate space is currently set to the upper-left origin of the + * bounding rect + * + * Updates "currentBand" and "x" member data of the block reflow state + */ +void nsBlockFrame::GetAvailableSpaceBand(nsBlockReflowState& aState, nscoord aY) +{ + // Gets a band of available space. + aState.spaceManager->Translate(aState.borderPadding.left, 0); + aState.spaceManager->GetBandData(aY, aState.availSize, *aState.currentBand); + + // XXX This is hack code that needs to change when the space manager interface + // changes to return both the available and unavailable space + // + // We'll get back anywhere between 1 and 3 rects depending on how many floaters + // there are. Actually the way it currently works we could get back zero rects + // if there are overlapping left and right floaters occupying all the space + if (aState.currentBand->count > 1) { + // If there are three rects then let's assume that there are floaters on the + // left and right and that only the middle rect is available + if (aState.currentBand->count == 3) { + aState.currentBand->rects[0] = aState.currentBand->rects[1]; + } else { + // There are two rects. That means either a left or right floater. Just use + // whichever space is larger. + if (aState.currentBand->rects[1].width > aState.currentBand->rects[0].width) { + aState.currentBand->rects[0] = aState.currentBand->rects[1]; + } + } + } + aState.spaceManager->Translate(-aState.borderPadding.left, 0); + aState.x = aState.currentBand->rects[0].x; +} + +void nsBlockFrame::ClearFloaters(nsBlockReflowState& aState, PRUint32 aClear) +{ + // Translate the coordinate space + aState.spaceManager->Translate(aState.borderPadding.left, 0); + +getBand: + nscoord y = aState.y + aState.topMargin; + PRBool isLeftFloater = PR_FALSE; + PRBool isRightFloater = PR_FALSE; + + // Get a band of available space + aState.spaceManager->GetBandData(y, aState.availSize, *aState.currentBand); + + if (aState.currentBand->count == 1) { + if (aState.currentBand->rects[0].width != aState.availSize.width) { + // Some of the space is taken up by floaters + if (aState.currentBand->rects[0].x > 0) { + isLeftFloater = PR_TRUE; + } + + if (aState.currentBand->rects[0].XMost() < aState.availSize.width) { + isRightFloater = PR_TRUE; + } + } + } else if (aState.currentBand->count == 2) { + if (aState.currentBand->rects[0].width > aState.currentBand->rects[1].width) { + isRightFloater = PR_TRUE; + } else { + isLeftFloater = PR_TRUE; + + // There may also be a right floater + if (aState.currentBand->rects[1].XMost() < aState.availSize.width) { + isRightFloater = PR_TRUE; + } + } + } else { + // Must be both left and right floaters + isLeftFloater = PR_TRUE; + isRightFloater = PR_TRUE; + } + + if (isLeftFloater) { + if ((aClear == NS_STYLE_CLEAR_LEFT) || (aClear == NS_STYLE_CLEAR_BOTH)) { + aState.y += aState.currentBand->rects[0].height; + goto getBand; + } + } + if (isRightFloater) { + if ((aClear == NS_STYLE_CLEAR_RIGHT) || (aClear == NS_STYLE_CLEAR_BOTH)) { + aState.y += aState.currentBand->rects[0].height; + goto getBand; + } + } + + aState.spaceManager->Translate(-aState.borderPadding.left, 0); +} + +// Bit's for PlaceAndReflowChild return value +#define PLACE_FIT 0x1 +#define PLACE_FLOWED 0x2 + +PRIntn +nsBlockFrame::PlaceAndReflowChild(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsIFrame* kidFrame, + nsStyleMolecule* aKidMol) +{ + nsSize kidMaxElementSize; + nsSize* pKidMaxElementSize = + (nsnull != aState.maxElementSize) ? &kidMaxElementSize : nsnull; + + // Get line start setup if we are at the start of a new line + if (nsnull == aState.lineStart) { + NS_ASSERTION(0 == aState.lineLength, "bad line length"); + aState.lineStart = kidFrame; + } + + // Get kid and its style + // XXX How is this any different than what was passed in to us as aKidMol? + nsIContent* kid = kidFrame->GetContent(); + nsIStyleContext* kidSC = kidFrame->GetStyleContext(aCX); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + NS_RELEASE(kid); + + // Figure out if kid is a block element or not + PRBool isInline = PR_TRUE; + PRIntn display = kidMol->display; + if (aState.firstChildIsInsideBullet && (mFirstChild == kidFrame)) { + // XXX Special hack for properly reflowing bullets that have the + // inside value for list-style-position. + display = NS_STYLE_DISPLAY_INLINE; + } + if ((NS_STYLE_DISPLAY_BLOCK == display) || + (NS_STYLE_DISPLAY_LIST_ITEM == display)) { + // Block elements always end up on the next line (unless they are + // already at the start of the line). + isInline = PR_FALSE; + if (aState.lineLength > 0) { + aState.breakAfterChild = PR_TRUE; + } + } + + // Handle forced break first + if (aState.breakAfterChild) { + NS_ASSERTION(aState.lineStart != kidFrame, "bad line"); + + // Get the last child in the current line + nsIFrame* lastFrame = aState.lineStart; + PRInt32 lineLen = aState.lineLength - 1; + while (--lineLen >= 0) { + lastFrame = lastFrame->GetNextSibling(); + } + + if (!AdvanceToNextLine(aCX, aState)) { + // The previous line didn't fit. + return 0; + } + aState.lineStart = kidFrame; + + // Get the style for the last child, and see if it wanted to clear floaters. + // This handles the BR tag, which is the only inline element for which clear + // applies + nsIStyleContext* lastChildSC = lastFrame->GetStyleContext(aCX); + nsStyleMolecule* lastChildMol = (nsStyleMolecule*)lastChildSC->GetData(kStyleMoleculeSID); + if (lastChildMol->clear != NS_STYLE_CLEAR_NONE) { + ClearFloaters(aState, lastChildMol->clear); + } + NS_RELEASE(lastChildSC); + } + + // Now that we've handled force breaks (and maybe called AdvanceToNextLine() + // which checks), remember whether it's an inline frame + aState.isInline = isInline; + + // If we're at the beginning of a line then compute the top margin that we + // should use + if (aState.lineStart == kidFrame) { + // Compute the top margin to use for this line + aState.topMargin = GetTopMarginFor(aCX, aState, kidMol, aState.isInline); + + // If it's an inline element then get a band of available space + // + // XXX If we have a current band and there's unused space in that band + // then avoid this call to get a band... + if (aState.isInline) { + GetAvailableSpaceBand(aState, aState.y + aState.topMargin); + } + } + + // Compute the available space to reflow the child into and then + // reflow it into that space. + nsSize kidAvailSize; + GetAvailSize(kidAvailSize, aState, kidMol, aState.isInline); + if ((aState.currentLineNumber > 0) && (kidAvailSize.height <= 0)) { + // No more room + return 0; + } + + ReflowStatus status; + + if (aState.isInline) { + nsReflowMetrics kidSize; + + // Inline elements are never passed the space manager + status = ReflowChild(kidFrame, aCX, kidSize, kidAvailSize, + pKidMaxElementSize); + + // For first children, we skip all the fit checks because we must + // fit at least one child for a parent to figure what to do with us. + if ((aState.currentLineNumber > 0) || (aState.lineLength > 0)) { + NS_ASSERTION(nsnull != aState.lineStart, "bad line start"); + + if (kidFrame == aState.lineStart) { + // Width always fits when we are at the logical left margin. + // Just check the height. + // + // XXX This height check isn't correct now that we have bands of + // available space... + if (kidSize.height > kidAvailSize.height) { + // It's too tall + return PLACE_FLOWED; + } + } else { + // Examine state and if the breakBeforeChild is set and we + // aren't already on the new line, do the forcing now. + // XXX Why aren't we doing this check BEFORE we resize reflow the child? + if (aState.breakBeforeChild) { + aState.breakBeforeChild = PR_FALSE; + if (kidFrame != aState.lineStart) { + if (!AdvanceToNextLine(aCX, aState)) { + // Flushing out the line failed. + return PLACE_FLOWED; + } + aState.lineStart = kidFrame; + + // Get a band of available space + GetAvailableSpaceBand(aState, aState.y + aState.topMargin); + + // Reflow child now that it has the line to itself + GetAvailSize(kidAvailSize, aState, kidMol, PR_TRUE); + status = ReflowChild(kidFrame, aCX, kidSize, kidAvailSize, + pKidMaxElementSize); + } + } + + // When we are not at the logical left margin then we need + // to check the width first. If we are too wide then advance + // to the next line and try reflowing again. + if (kidSize.width > kidAvailSize.width) { + // Too wide. Try next line + if (!AdvanceToNextLine(aCX, aState)) { + // Flushing out the line failed. + return PLACE_FLOWED; + } + aState.lineStart = kidFrame; + + // Get a band of available space + GetAvailableSpaceBand(aState, aState.y + aState.topMargin); + + // Reflow splittable children + if (kidFrame->IsSplittable()) { + // Update size info now that we are on the next line. Then + // reflow the child into the new available space. + GetAvailSize(kidAvailSize, aState, kidMol, PR_TRUE); + status = ReflowChild(kidFrame, aCX, kidSize, kidAvailSize, + pKidMaxElementSize); + + // If we just reflowed our last child then update the + // mLastContentIsComplete state. + if (nsnull == kidFrame->GetNextSibling()) { + // Use state from the reflow we just did + mLastContentIsComplete = PRBool(status == frComplete); + } + } + + // XXX This height check isn't correct now that we have bands of + // available space... + if (kidSize.height > kidAvailSize.height) { + // It's too tall on the next line + return PLACE_FLOWED; + } + // It's ok if it's too wide on the next line. + } + } + } + + // Add child to the line + AddInlineChildToLine(aCX, aState, kidFrame, kidSize, pKidMaxElementSize, kidMol); + + } else { + nsRect kidRect; + + // Does the block-level element want to clear any floaters that impact + // it? Note that the clear property only applies to block-level elements + // and the BR tag + if (aKidMol->clear != NS_STYLE_CLEAR_NONE) { + ClearFloaters(aState, aKidMol->clear); + GetAvailSize(kidAvailSize, aState, kidMol, PR_FALSE); + if ((aState.currentLineNumber > 0) && (kidAvailSize.height <= 0)) { + // No more room + return 0; + } + } + + // Give the block its own local coordinate space. + // + // XXX This is wrong to have the parent try and account for the kid's + // left margin here, because we have to wait until we know what the + // left edge is and that means resolving any floaters that impact the + // block. If the kid wants to interact with the space manager then it + // will have to deal with left/right margins itself + nscoord tx = aState.borderPadding.left + aKidMol->margin.left; + nscoord ty = aState.y + aState.topMargin; + + // Give the block-level element the opportunity to use the space manager + aState.spaceManager->Translate(tx, ty); + status = ReflowChild(kidFrame, aCX, aState.spaceManager, kidAvailSize, + kidRect, pKidMaxElementSize); + aState.spaceManager->Translate(-tx, -ty); + + // For first children, we skip all the fit checks because we must + // fit at least one child for a parent to figure what to do with us. + if ((aState.currentLineNumber > 0) || (aState.lineLength > 0)) { + // Block elements always fit horizontally (because they are + // always placed at the logical left margin). Check to see if + // the block fits vertically + if (kidRect.YMost() > kidAvailSize.height) { + // Nope + return PLACE_FLOWED; + } + } + + // Add block child + AddBlockChild(aCX, aState, kidFrame, kidRect, pKidMaxElementSize, kidMol); + } + + // If we just reflowed our last child then update the + // mLastContentIsComplete state. + if (nsnull == kidFrame->GetNextSibling()) { + // Use state from the reflow we just did + mLastContentIsComplete = PRBool(status == frComplete); + } + + aState.lastContentIsComplete = PRBool(status == frComplete); + if (aState.isInline && (frNotComplete == status)) { + // Since the inline child didn't complete its reflow we *know* + // that a continuation of it can't possibly fit on the current + // line. Therefore, set a flag in the state that will cause the + // a line break before the next frame is placed. + aState.breakAfterChild = PR_TRUE; + } + NS_RELEASE(kidSC); + + aState.reflowStatus = status; + return PLACE_FLOWED | PLACE_FIT; +} + +/** + * Reflow the existing frames. + * + * @param aCX presentation context to use + * @param aState in out parameter which tracks the state of + * reflow for the block frame. + * @return true if we successfully reflowed all the mapped children and false + * otherwise, e.g. we pushed children to the next in flow + */ +PRBool +nsBlockFrame::ReflowMappedChildren(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": reflow mapped (childCount=%d) [%d,%d,%c]\n", + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif + + PRBool result = PR_TRUE; + nsIFrame* kidFrame; + nsIFrame* prevKidFrame = nsnull; + + for (kidFrame = mFirstChild; nsnull != kidFrame; ) { + nsIContent* kid = kidFrame->GetContent(); + nsIStyleContext* kidSC = aCX->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + NS_RELEASE(kid); + + // Attempt to place and reflow the child + + // XXX if child is not splittable and it fits just place it where + // it is, otherwise advance to the next line and place it there if + // possible + + PRIntn placeStatus = PlaceAndReflowChild(aCX, aState, kidFrame, kidMol); + ReflowStatus status = aState.reflowStatus; + NS_RELEASE(kidSC); + if (0 == (placeStatus & PLACE_FIT)) { + // The child doesn't fit. Push it and any remaining children. + PushKids(aState); + result = PR_FALSE; + goto push_done; + } + + // Is the child complete? + if (frComplete == status) { + // Yes, the child is complete + NS_ASSERTION(nsnull == kidFrame->GetNextInFlow(), "bad child flow list"); + } else { + // No the child isn't complete + nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); + if (nsnull == kidNextInFlow) { + // The child doesn't have a next-in-flow so create a continuing + // frame. This hooks the child into the flow + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aCX, this); + NS_ASSERTION(nsnull != continuingFrame, "frame creation failed"); + + // Add the continuing frame to the sibling list + nsIFrame* nextSib = kidFrame->GetNextSibling(); + continuingFrame->SetNextSibling(nextSib); + kidFrame->SetNextSibling(continuingFrame); + mChildCount++; + } + + // Unlike the inline frame code we can't assume that we used + // up all of our space because the child's reflow status is + // frNotComplete. Instead, the child is probably split and + // we need to reflow the continuations as well. + } + + // Get the next child frame + prevKidFrame = kidFrame; + kidFrame = kidFrame->GetNextSibling(); + } + + push_done:; + // Update the child count member data + NS_POSTCONDITION(LastChild()->GetIndexInParent() == mLastContentOffset, "bad last content offset"); + +#ifdef NS_DEBUG + PRInt32 len = LengthOf(mFirstChild); + NS_POSTCONDITION(len == mChildCount, "bad child count"); + VerifyLastIsComplete(); +#endif + +#ifdef NOISY + ListTag(stdout); + printf(": reflow mapped %sok (childCount=%d) [%d,%d,%c]\n", + (result ? "" : "NOT "), + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif + return result; +} + +PRBool nsBlockFrame::MoreToReflow(nsIPresContext* aCX) +{ + PRBool rv = PR_FALSE; + if (IsPseudoFrame()) { + // Get the next content object that we would like to reflow + PRInt32 kidIndex = NextChildOffset(); + nsIContent* kid = mContent->ChildAt(kidIndex); + if (nsnull != kid) { + // Resolve style for the kid + nsIStyleContext* kidSC = aCX->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + switch (kidMol->display) { + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + // Block pseudo-frames do not contain other block elements + break; + + default: + rv = PR_TRUE; + break; + } + NS_RELEASE(kidSC); + NS_RELEASE(kid); + } + } else { + if (NextChildOffset() < mContent->ChildCount()) { + rv = PR_TRUE; + } + } + return rv; +} + +/** + * Create new frames for content we haven't yet mapped + * + * @param aCX presentation context to use + * @return frComplete if all content has been mapped and frNotComplete + * if we should be continued + */ +nsIFrame::ReflowStatus +nsBlockFrame::ReflowAppendedChildren(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif + nsIFrame* kidPrevInFlow = nsnull; + ReflowStatus result = frNotComplete; + + // If we have no children and we have a prev-in-flow then we need to pick + // up where it left off. If we have children, e.g. we're being resized, then + // our content offset should already be set correctly... + if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) { + nsBlockFrame* prev = (nsBlockFrame*) mPrevInFlow; + NS_ASSERTION(prev->mLastContentOffset >= prev->mFirstContentOffset, "bad prevInFlow"); + mFirstContentOffset = prev->NextChildOffset(); + if (PR_FALSE == prev->mLastContentIsComplete) { + // Our prev-in-flow's last child is not complete + kidPrevInFlow = prev->LastChild(); + } + } + + // Place our children, one at a time until we are out of children + PRInt32 kidIndex = NextChildOffset(); + nsIFrame* prevKidFrame = LastChild(); + nsIFrame* kidFrame = nsnull; + for (;;) { + // Get the next content object + nsIContent* kid = mContent->ChildAt(kidIndex); + if (nsnull == kid) { + result = frComplete; + break; + } + + // Resolve style for the kid + nsIStyleContext* kidSC = aCX->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + + // Is it a floater? + if (kidMol->floats != NS_STYLE_FLOAT_NONE) { + PlaceholderFrame::NewFrame(&kidFrame, kid, kidIndex, this); + kidFrame->SetStyleContext(kidSC); + } else if (nsnull == kidPrevInFlow) { + // Create initial frame for the child + nsIContentDelegate* kidDel; + nsresult fr; + switch (kidMol->display) { + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + // Pseudo block frames do not contain other block elements + // unless the block element would be the first child. + if (IsPseudoFrame()) { + // If we're being used as a pseudo frame, i.e. we map the same + // content as our parent then we want to indicate we're complete; + // otherwise we'll be continued and go on mapping children... + + // It better be true that we are not being asked to flow a + // block element as our first child. That means the body + // decided it needed a pseudo-frame when it shouldn't have. + NS_ASSERTION(nsnull != mFirstChild, "bad body"); + + NS_RELEASE(kidSC); + NS_RELEASE(kid); + result = frComplete; + goto done; + } + // FALL THROUGH (and create frame) + + case NS_STYLE_DISPLAY_INLINE: + kidDel = kid->GetDelegate(aCX); + kidFrame = kidDel->CreateFrame(aCX, kid, kidIndex, this); + NS_RELEASE(kidDel); + break; + + default: + NS_ASSERTION(nsnull == kidPrevInFlow, "bad prev in flow"); + fr = nsFrame::NewFrame(&kidFrame, kid, kidIndex, this); + break; + } + kidFrame->SetStyleContext(kidSC); + } else { + // Since kid has a prev-in-flow, use that to create the next + // frame. + kidFrame = kidPrevInFlow->CreateContinuingFrame(aCX, this); + } + + // Link child frame into the list of children. If the frame ends + // up not fitting and getting pushed, the PushKids code will fixup + // the child count for us. + if (nsnull != prevKidFrame) { + NS_ASSERTION(nsnull == prevKidFrame->GetNextSibling(), "bad append"); + prevKidFrame->SetNextSibling(kidFrame); + } else { + NS_ASSERTION(nsnull == mFirstChild, "bad create"); + mFirstChild = kidFrame; + SetFirstContentOffset(kidFrame); + } + prevKidFrame = kidFrame; + mChildCount++; + + // Reflow child frame as many times as necessary until it is + // complete. + ReflowStatus status; + do { + PRIntn placeStatus = PlaceAndReflowChild(aCX, aState, kidFrame, kidMol); + status = aState.reflowStatus; + if (0 == (placeStatus & PLACE_FIT)) { + // We ran out of room. + mLastContentIsComplete = PRBool(nsnull == kidFrame->GetNextInFlow()); + PushKids(aState); + + NS_RELEASE(kid); + NS_RELEASE(kidSC); + goto push_done; + } + + // Did the child complete? + prevKidFrame = kidFrame; + if (frNotComplete == status) { + // Child didn't complete so create a continuing frame + kidPrevInFlow = kidFrame; + nsIFrame* continuingFrame = kidFrame->CreateContinuingFrame(aCX, this); + + // Add the continuing frame to the sibling list + continuingFrame->SetNextSibling(kidFrame->GetNextSibling()); + kidFrame->SetNextSibling(continuingFrame); + kidFrame = continuingFrame; + mChildCount++; + + // Switch to new kid style + NS_RELEASE(kidSC); + kidSC = kidFrame->GetStyleContext(aCX); + kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + } + NS_ASSERTION(nsnull == kidFrame->GetNextInFlow(), "huh?"); + } while (frNotComplete == status); + NS_RELEASE(kid); + NS_RELEASE(kidSC); + + // The child that we just reflowed is complete + NS_ASSERTION(nsnull == kidFrame->GetNextInFlow(), "bad child flow list"); + kidIndex++; + kidPrevInFlow = nsnull; + } + + done: + // To get here we either completely reflowed all our appended + // children OR we are a pseudo-frame and we ran into a block + // element. In either case our last content MUST be complete. + NS_ASSERTION(PR_TRUE == aState.lastContentIsComplete, "bad state"); + + NS_ASSERTION(LastChild() == prevKidFrame, "bad last child"); + SetLastContentOffset(prevKidFrame); + + push_done: +#ifdef NS_DEBUG + PRInt32 len = LengthOf(mFirstChild); + NS_ASSERTION(len == mChildCount, "bad child count"); + VerifyLastIsComplete(); +#endif + return result; +} + +/** + * Pullup frames from our next in flow and try to place them. Before + * this is called our previously mapped children, if any have been + * reflowed which means that the block reflow state's x and y + * coordinates and other data are ready to go. + * + * Return true if we pulled everything up. + */ +PRBool +nsBlockFrame::PullUpChildren(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": pullup (childCount=%d) [%d,%d,%c]\n", + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif + + PRBool result = PR_TRUE; + nsBlockFrame* nextInFlow = (nsBlockFrame*) mNextInFlow; + nsIFrame* prevKidFrame = LastChild(); + while (nsnull != nextInFlow) { + // Get first available frame from the next-in-flow + nsIFrame* kidFrame = PullUpOneChild(nextInFlow, prevKidFrame); + if (nsnull == kidFrame) { + // We've pulled up all the children from that next-in-flow, so + // move to the next next-in-flow. + nextInFlow = (nsBlockFrame*) nextInFlow->mNextInFlow; + continue; + } + + // Get style information for the pulled up kid + nsIContent* kid = kidFrame->GetContent(); + nsIStyleContext* kidSC = aCX->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + + ReflowStatus status; + do { + PRIntn placeStatus = PlaceAndReflowChild(aCX, aState, kidFrame, kidMol); + status = aState.reflowStatus; + if (0 == (placeStatus & PLACE_FIT)) { + // Push the kids that didn't fit back down to the next-in-flow + mLastContentIsComplete = PRBool(nsnull == kidFrame->GetNextInFlow()); + PushKids(aState); + + result = PR_FALSE; + NS_RELEASE(kid); + NS_RELEASE(kidSC); + goto push_done; + } + + if (frNotComplete == status) { + // Child is not complete + nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); + if (nsnull == kidNextInFlow) { + // Create a continuing frame for the incomplete child + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aCX, this); + + // Add the continuing frame to our sibling list. + continuingFrame->SetNextSibling(kidFrame->GetNextSibling()); + kidFrame->SetNextSibling(continuingFrame); + prevKidFrame = kidFrame; + kidFrame = continuingFrame; + mChildCount++; + + // Switch to new kid style + NS_RELEASE(kidSC); + kidSC = kidFrame->GetStyleContext(aCX); + kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + } else { + // The child has a next-in-flow, but it's not one of ours. + // It *must* be in one of our next-in-flows. Collect it + // then. + NS_ASSERTION(kidNextInFlow->GetGeometricParent() != this, + "busted kid next-in-flow"); + break; + } + } + } while (frNotComplete == status); + NS_RELEASE(kid); + NS_RELEASE(kidSC); + + prevKidFrame = kidFrame; + } + + if (nsnull != prevKidFrame) { + // The only way we can get here is by pulling up every last child + // in our next-in-flows (and reflowing any continunations they + // have). Therefore we KNOW that our last child is complete. + NS_ASSERTION(PR_TRUE == aState.lastContentIsComplete, "bad state"); + NS_ASSERTION(LastChild() == prevKidFrame, "bad last child"); + SetLastContentOffset(prevKidFrame); + } + + push_done:; + + if (result == PR_FALSE) { + // If our next-in-flow is empty OR our next next-in-flow is empty + // then adjust the offsets of all of the empty next-in-flows. + nextInFlow = (nsBlockFrame*) mNextInFlow; + if ((0 == nextInFlow->mChildCount) || + ((nsnull != nextInFlow->mNextInFlow) && + (0 == ((nsBlockFrame*)(nextInFlow->mNextInFlow))->mChildCount))) { + // We didn't pullup everything and we need to fixup one of our + // next-in-flows content offsets. + AdjustOffsetOfEmptyNextInFlows(); + } + } + + +#ifdef NS_DEBUG + PRInt32 len = LengthOf(mFirstChild); + NS_ASSERTION(len == mChildCount, "bad child count"); + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": pullup %sok (childCount=%d) [%d,%d,%c]\n", + (result ? "" : "NOT "), + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); + DumpFlow(); +#endif + return result; +} + +void nsBlockFrame::SetupState(nsIPresContext* aCX, + nsBlockReflowState& aState, + const nsSize& aMaxSize, + nsSize* aMaxElementSize, + nsISpaceManager* aSpaceManager) +{ + // Setup reflow state + nsStyleMolecule* mol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + nsStyleFont* font = + (nsStyleFont*)mStyleContext->GetData(kStyleFontSID); + aState.Init(aMaxSize, aMaxElementSize, font, mol, aSpaceManager); + + // Apply border and padding adjustments for regular frames only + if (PR_FALSE == IsPseudoFrame()) { + aState.borderPadding = mol->borderPadding; + aState.y = mol->borderPadding.top; + aState.availSize.width -= + (mol->borderPadding.left + mol->borderPadding.right); + aState.availSize.height -= + (mol->borderPadding.top + mol->borderPadding.bottom); + } else { + aState.borderPadding.SizeTo(0, 0, 0, 0); + } + + // Setup initial list ordinal value + nsIAtom* tag = mContent->GetTag(); + if ((tag == nsHTMLAtoms::ul) || (tag == nsHTMLAtoms::ol) || + (tag == nsHTMLAtoms::menu) || (tag == nsHTMLAtoms::dir)) { + nsHTMLValue value; + if (eContentAttr_HasValue == + ((nsIHTMLContent*)mContent)->GetAttribute(nsHTMLAtoms::start, value)) { + if (eHTMLUnit_Absolute == value.GetUnit()) { + aState.nextListOrdinal = value.GetIntValue(); + } + } + } + NS_RELEASE(tag); + + mCurrentState = &aState; +} + +#include "nsUnitConversion.h"/* XXX */ +nsIFrame::ReflowStatus +nsBlockFrame::ResizeReflow(nsIPresContext* aCX, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsSize* aMaxElementSize) +{ + nsBlockReflowState state; + SetupState(aCX, state, aMaxSize, aMaxElementSize, aSpaceManager); + return DoResizeReflow(aCX, state, aDesiredRect); +} + +nsIFrame::ReflowStatus +nsBlockFrame::DoResizeReflow(nsIPresContext* aCX, + nsBlockReflowState& aState, + nsRect& aDesiredRect) +{ +#ifdef NS_DEBUG + PreReflowCheck(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": resize reflow %g,%g\n", + NS_TWIPS_TO_POINTS_FLOAT(aState.availSize.width), + NS_TWIPS_TO_POINTS_FLOAT(aState.availSize.height)); + DumpFlow(); +#endif + + // Zap old line data + if (nsnull != mLines) { + delete mLines; + mLines = nsnull; + } + mNumLines = 0; + + // Check for an overflow list + MoveOverflowToChildList(); + + // Before we start reflowing, cache a pointer to our state structure + // so that inline frames can find it. + nsIPresShell* shell = aCX->GetShell(); + shell->PutCachedData(this, &aState); + + // First reflow any existing frames + PRBool reflowMappedOK = PR_TRUE; + ReflowStatus status = frComplete; + if (nsnull != mFirstChild) { + reflowMappedOK = ReflowMappedChildren(aCX, aState); + if (!reflowMappedOK) { + status = frNotComplete; + } + } + + if (reflowMappedOK) { + // Any space left? + nscoord yb = aState.borderPadding.top + aState.availSize.height; + if ((nsnull != mFirstChild) && (aState.y >= yb)) { + // No space left. Don't try to pull-up children or reflow + // unmapped. We need to return the correct completion status, + // so see if there is more to reflow. + if (MoreToReflow(aCX)) { + status = frNotComplete; + } + } else if (MoreToReflow(aCX)) { + // Try and pull-up some children from a next-in-flow + if ((nsnull == mNextInFlow) || PullUpChildren(aCX, aState)) { + // If we still have unmapped children then create some new frames + if (MoreToReflow(aCX)) { + status = ReflowAppendedChildren(aCX, aState); + } + } else { + // We were unable to pull-up all the existing frames from the + // next in flow + status = frNotComplete; + } + } + } + + // Deal with last line - make sure it gets vertically and + // horizontally aligned. This also updates the state's y coordinate + // which is good because that's how we size ourselves. + if (0 != aState.lineLength) { + if (!AdvanceToNextLine(aCX, aState)) { + // The last line of output doesn't fit. Push all of the kids to + // the next in flow and change our reflow status to not complete + // so that we are continued. +#ifdef NOISY + ListTag(stdout); + printf(": pushing kids since last line doesn't fit\n"); +#endif + + PushKids(aState); + status = frNotComplete; + } + } + + if (frComplete == status) { + // Don't forget to add in the bottom margin from our last child. + // Only add it in if there is room for it. + nscoord margin = aState.prevMaxPosBottomMargin - + aState.prevMaxNegBottomMargin; + nscoord y = aState.y + margin; + if (y <= aState.borderPadding.top + aState.availSize.height) { + aState.y = y; + } + } + + // Now that reflow has finished, remove the cached pointer + shell->RemoveCachedData(this); + NS_RELEASE(shell); + + // Translate state.lineLengths into an integer array + mNumLines = aState.lineLengths.Count(); + if (mNumLines > 0) { + mLines = new PRInt32[mNumLines]; + for (PRInt32 i = 0; i < mNumLines; i++) { + PRInt32 ll = (PRInt32) aState.lineLengths.ElementAt(i); + mLines[i] = ll; + } + } + + if (!aState.unconstrainedWidth && aState.justifying) { + // Perform justification now that we know how many lines we have. + JustifyLines(aCX, aState); + } + + // Return our desired rect and our status + aDesiredRect.x = 0; + aDesiredRect.y = 0; + aDesiredRect.width = aState.kidXMost + aState.borderPadding.right; + if (!aState.unconstrainedWidth) { + // Make sure we're at least as wide as the max size we were given + nscoord maxWidth = aState.availSize.width + aState.borderPadding.left + + aState.borderPadding.right; + + if (aDesiredRect.width < maxWidth) { + aDesiredRect.width = maxWidth; + } + } + aState.y += aState.borderPadding.bottom; + aDesiredRect.height = aState.y; + +#ifdef NS_DEBUG + PostReflowCheck(status); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": resize reflow %g,%g %scomplete [%d,%d,%c]\n", + NS_TWIPS_TO_POINTS_FLOAT(aState.availSize.width), + NS_TWIPS_TO_POINTS_FLOAT(aState.availSize.height), + ((status == frNotComplete) ? "NOT " : ""), + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F') + ); + DumpFlow(); +#endif + mCurrentState = nsnull; + return status; +} + +void nsBlockFrame::JustifyLines(nsIPresContext* aCX, + nsBlockReflowState& aState) +{ + // XXX we don't justify the last line; what if we are continued, + // should we do it then? + nsIFrame* kid = mFirstChild; + for (PRInt32 i = 0; i < mNumLines; i++) { + nsIFrame* lineStart = kid; + PRInt32 lineLength = mLines[i]; + if (i < mNumLines - 1) { + if (1 == lineLength) { + // For lines with one element on them we can take a shortcut and + // let them do the justification. Note that we still call + // JustifyReflow even if the available space is zero in case the + // child is a hunk of text that ends in whitespace. The whitespace + // will be distributed elsewhere causing a proper flush right look + // for the last word. + nsRect r; + kid->GetRect(r); + nscoord maxWidth = aState.availSize.width; + nscoord availableSpace = maxWidth - r.width; + nscoord maxAvailSpace = nscoord(maxWidth * 0.1f); + if ((availableSpace >= 0) && (availableSpace < maxAvailSpace)) { + kid->JustifyReflow(aCX, availableSpace); + kid->SizeTo(r.width + availableSpace, r.height); + } + kid = kid->GetNextSibling(); + } else { + // XXX Get justification of multiple elements working + while (--lineLength >= 0) { + kid = kid->GetNextSibling(); + } + } + } + + // Finally, now that the in-flow positions of the line's frames are + // known we can apply relative positioning if any of them need it. + nsCSSLayout::RelativePositionChildren(aCX, this, aState.mol, + lineStart, mLines[i]); + } +} + +nsIFrame* nsBlockFrame::CreateContinuingFrame(nsIPresContext* aCX, + nsIFrame* aParent) +{ + nsBlockFrame* cf = new nsBlockFrame(mContent, mIndexInParent, aParent); + PrepareContinuingFrame(aCX, aParent, cf); + return cf; +} + +nsIFrame::ReflowStatus +nsBlockFrame::IncrementalReflow(nsIPresContext* aCX, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsReflowCommand& aReflowCommand) +{ + ReflowStatus status = frComplete; + + if (aReflowCommand.GetTarget() == this) { + // XXX for now, just do a complete reflow mapped (it'll kinda + // work, but it's slow) + + nsBlockReflowState state; + SetupState(aCX, state, aMaxSize, nsnull, aSpaceManager); + PRBool reflowMappedOK = ReflowMappedChildren(aCX, state); + if (!reflowMappedOK) { + status = frNotComplete; + } + } else { + // XXX not yet implemented + NS_ABORT(); + // XXX work to compute initial state goes *HERE* + aDesiredRect.x = 0; + aDesiredRect.y = 0; + aDesiredRect.width = 0; + aDesiredRect.height = 0; + } + + mCurrentState = nsnull; + return status; +} + +PRBool nsBlockFrame::IsLeftMostChild(nsIFrame* aFrame) +{ + do { + nsIFrame* parent = aFrame->GetGeometricParent(); + + // See if there are any non-zero sized child frames that precede aFrame + // in the child list + nsIFrame* child = parent->FirstChild(); + + while ((nsnull != child) && (aFrame != child)) { + // Is the child zero-sized? + if ((child->GetWidth() > 0) || (child->GetHeight() > 0)) { + // We found a non-zero sized child frame that precedes aFrame + return PR_FALSE; + } + + child = child->GetNextSibling(); + } + + // aFrame is the left-most non-zero sized frame in its geometric parent. + // Walk up one level and check that its parent is left-most as well + aFrame = parent; + } while (aFrame != this); + + return PR_TRUE; +} + +PRBool nsBlockFrame::AddFloater(nsIPresContext* aCX, + nsIFrame* aFloater, + PlaceholderFrame* aPlaceholder) +{ + // Get the frame associated with the space manager, and get its nsIAnchoredItems + // interface + nsIFrame* frame = mCurrentState->spaceManager->GetFrame(); + nsIAnchoredItems* anchoredItems = nsnull; + + frame->QueryInterface(kIAnchoredItemsIID, (void**)&anchoredItems); + NS_ASSERTION(nsnull != anchoredItems, "no anchored items interface"); + + if (nsnull != anchoredItems) { + anchoredItems->AddAnchoredItem(aFloater, nsIAnchoredItems::anHTMLFloater, this); + PlaceFloater(aCX, aFloater, aPlaceholder); + return PR_TRUE; + } + + return PR_FALSE; +} + +// XXX The size of the floater needs to be taken into consideration if we're +// computing a maximum element size +void nsBlockFrame::PlaceFloater(nsIPresContext* aCX, + nsIFrame* aFloater, + PlaceholderFrame* aPlaceholder) +{ + // If the floater is the left-most non-zero size child frame then insert + // it before the current line; otherwise add it to the below-current-line + // todo list and we'll handle it when we flush out the line + if (IsLeftMostChild(aPlaceholder)) { + // Get the type of floater + nsIStyleContext* styleContext = aFloater->GetStyleContext(aCX); + nsStyleMolecule* mol = (nsStyleMolecule*)styleContext->GetData(kStyleMoleculeSID); + NS_RELEASE(styleContext); + + if (!mCurrentState->isInline) { + // Get the current band for this line + GetAvailableSpaceBand(*mCurrentState, mCurrentState->y + mCurrentState->topMargin); + } + + // Commit some space in the space manager + nsRect region; + + aFloater->GetRect(region); + region.y = mCurrentState->currentBand->rects[0].y; + + if (NS_STYLE_FLOAT_LEFT == mol->floats) { + region.x = mCurrentState->currentBand->rects[0].x; + } else { + NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == mol->floats, "bad float type"); + region.x = mCurrentState->currentBand->rects[0].XMost() - region.width; + } + + // XXX Don't forget the floater's margins... + mCurrentState->spaceManager->Translate(mCurrentState->borderPadding.left, 0); + mCurrentState->spaceManager->AddRectRegion(region); + + // Set the origin of the floater in world coordinates + nscoord worldX, worldY; + + mCurrentState->spaceManager->GetTranslation(worldX, worldY); + aFloater->MoveTo(region.x + worldX, region.y + worldY); + mCurrentState->spaceManager->Translate(-mCurrentState->borderPadding.left, 0); + + // Update the band of available space to reflect space taken up by the floater + GetAvailableSpaceBand(*mCurrentState, mCurrentState->y + mCurrentState->topMargin); + } else { + // Add the floater to our to-do list + mCurrentState->floaterToDo.AppendElement(aFloater); + } +} + +void nsBlockFrame::ContentAppended(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer) +{ + // Zip down to the end-of-flow + nsBlockFrame* flow = this; + for (;;) { + nsBlockFrame* next = (nsBlockFrame*) flow->GetNextInFlow(); + if (nsnull == next) { + break; + } + flow = next; + } + + PRInt32 kidIndex = flow->NextChildOffset(); + PRInt32 startIndex = kidIndex; + nsIFrame* prevKidFrame = flow->LastChild(); + nsIFrame* kidFrame = nsnull; + for (;;) { + // Get the next content object + nsIContent* kid = mContent->ChildAt(kidIndex); + if (nsnull == kid) { + break; + } + + // Resolve style for the kid + nsIStyleContext* kidSC = aPresContext->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + + // Is it a floater? + if (kidMol->floats != NS_STYLE_FLOAT_NONE) { + PlaceholderFrame::NewFrame(&kidFrame, kid, kidIndex, this); + } else { + // Create initial frame for the child + nsIContentDelegate* kidDel; + nsresult fr; + switch (kidMol->display) { + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + // Pseudo block frames do not contain other block elements + // unless the block element would be the first child. + if (IsPseudoFrame()) { + // Update last content offset now that we are done drawing + // children from our parent. + SetLastContentOffset(prevKidFrame); + + // It better be true that we are not being asked to flow a + // block element as our first child. That means the body + // decided it needed a pseudo-frame when it shouldn't have. + NS_ASSERTION(nsnull != mFirstChild, "bad body"); + + NS_RELEASE(kidSC); + NS_RELEASE(kid); + + return; + } + // FALL THROUGH (and create frame) + + case NS_STYLE_DISPLAY_INLINE: + kidDel = kid->GetDelegate(aPresContext); + kidFrame = kidDel->CreateFrame(aPresContext, kid, kidIndex, this); + NS_RELEASE(kidDel); + break; + + default: + fr = nsFrame::NewFrame(&kidFrame, kid, kidIndex, this); + break; + } + } + kidFrame->SetStyleContext(kidSC); + NS_RELEASE(kidSC); + NS_RELEASE(kid); + + // Link child frame into the list of children + if (nsnull != prevKidFrame) { + NS_ASSERTION(nsnull == prevKidFrame->GetNextSibling(), "bad append"); + prevKidFrame->SetNextSibling(kidFrame); + } else { + NS_ASSERTION(nsnull == mFirstChild, "bad create"); + mFirstChild = kidFrame; + SetFirstContentOffset(kidFrame); + } + prevKidFrame = kidFrame; + kidIndex++; + mChildCount++; + } + SetLastContentOffset(prevKidFrame); + + // If this is a pseudo-frame then our parent will generate the + // reflow command. Otherwise, if the container is us then we should + // generate the reflow command because we were directly called. + if (!IsPseudoFrame() && (aContainer == mContent)) { + nsReflowCommand* rc = + new nsReflowCommand(aPresContext, flow, nsReflowCommand::FrameAppended, + startIndex); + aShell->AppendReflowCommand(rc); + } +} + +PRIntn nsBlockFrame::GetSkipSides() const +{ + PRIntn skip = 0; + if (nsnull != mPrevInFlow) { + skip |= 1 << NS_SIDE_TOP; + } + if (nsnull != mNextInFlow) { + skip |= 1 << NS_SIDE_BOTTOM; + } + return skip; +} + +nsHTMLFrameType nsBlockFrame::GetFrameType() const +{ + return eHTMLFrame_Block; +} + +void nsBlockFrame::ListTag(FILE* out) const +{ + if ((nsnull != mGeometricParent) && IsPseudoFrame()) { + fprintf(out, "*block(%d)@%p", mIndexInParent, this); + } else { + nsHTMLContainerFrame::ListTag(out); + } +} + +#ifdef NS_DEBUG +void nsBlockFrame::DumpFlow() const +{ +#ifdef NOISY_FLOW + nsBlockFrame* flow = (nsBlockFrame*) mNextInFlow; + while (flow != 0) { + printf(" %p: [%d,%d,%c]\n", + flow, flow->mFirstContentOffset, flow->mLastContentOffset, + (flow->mLastContentIsComplete ? 'T' : 'F')); + flow = (nsBlockFrame*) flow->mNextInFlow; + } +#endif +} +#endif diff --git a/mozilla/layout/html/base/src/nsBodyFrame.cpp b/mozilla/layout/html/base/src/nsBodyFrame.cpp new file mode 100644 index 00000000000..d98a0080506 --- /dev/null +++ b/mozilla/layout/html/base/src/nsBodyFrame.cpp @@ -0,0 +1,388 @@ +/* -*- 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 "nsBodyFrame.h" +#include "nsIContent.h" +#include "nsIContentDelegate.h" +#include "nsBlockFrame.h" +#include "nsReflowCommand.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsIPresContext.h" +#include "nsIPresShell.h" +#include "nsIViewManager.h" +#include "nsIDeviceContext.h" +#include "nsColumnFrame.h" +#include "nsSpaceManager.h" + +static NS_DEFINE_IID(kIRunaroundIID, NS_IRUNAROUND_IID); +static NS_DEFINE_IID(kIAnchoredItemsIID, NS_IANCHOREDITEMS_IID); +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); + +nsresult nsBodyFrame::NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIFrame* it = new nsBodyFrame(aContent, aIndexInParent, aParent); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aInstancePtrResult = it; + return NS_OK; +} + +nsBodyFrame::nsBodyFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsHTMLContainerFrame(aContent, aIndexInParent, aParentFrame) +{ + mSpaceManager = new SpaceManager(this); + NS_ADDREF(mSpaceManager); +} + +nsBodyFrame::~nsBodyFrame() +{ + NS_RELEASE(mSpaceManager); +} + +nsresult +nsBodyFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) +{ + NS_PRECONDITION(0 != aInstancePtr, "null ptr"); + if (NULL == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kIAnchoredItemsIID)) { + *aInstancePtr = (void*) ((nsIAnchoredItems*) this); + return NS_OK; + } + return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr); +} + +void nsBodyFrame::CreateColumnFrame(nsIPresContext* aPresContext) +{ + // Do we have a prev-in-flow? + if (nsnull == mPrevInFlow) { + // No, create a column pseudo frame + mFirstChild = new ColumnFrame(mContent, mIndexInParent, this); + mChildCount = 1; + + // Resolve style and set the style context + nsIStyleContext* styleContext = + aPresContext->ResolveStyleContextFor(mContent, this); + mFirstChild->SetStyleContext(styleContext); + NS_RELEASE(styleContext); + } else { + nsBodyFrame* prevBody = (nsBodyFrame*)mPrevInFlow; + + nsIFrame* prevColumn = prevBody->mFirstChild; + NS_ASSERTION(prevBody->ChildIsPseudoFrame(prevColumn), "bad previous column"); + + // Create a continuing column + mFirstChild = prevColumn->CreateContinuingFrame(aPresContext, this); + mChildCount = 1; + } +} + +nsSize nsBodyFrame::GetColumnAvailSpace(nsIPresContext* aPresContext, + nsStyleMolecule* aMol, + const nsSize& aMaxSize) +{ + nsSize result(aMaxSize); + + // If we're not being used as a pseudo frame then make adjustments + // for border/padding and a vertical scrollbar + if (!IsPseudoFrame()) { + // If our width is constrained then subtract for the border/padding + if (aMaxSize.width != NS_UNCONSTRAINEDSIZE) { + result.width -= aMol->borderPadding.left + aMol->borderPadding.right; + if (! aPresContext->IsPaginated()) { + nsIDeviceContext* dc = aPresContext->GetDeviceContext(); + result.width -= NS_TO_INT_ROUND(dc->GetScrollBarWidth()); + NS_RELEASE(dc); + } + } + // If our height is constrained then subtract for the border/padding + if (aMaxSize.height != NS_UNCONSTRAINEDSIZE) { + result.height -= aMol->borderPadding.top + aMol->borderPadding.bottom; + } + } + + return result; +} + +nsIFrame::ReflowStatus +nsBodyFrame::ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ + nsIFrame::ReflowStatus status = frComplete; + + // Do we have any children? + if (nsnull == mFirstChild) { + // No, create a column frame + CreateColumnFrame(aPresContext); + } + + // Reflow the column + if (nsnull != mFirstChild) { + // Clear any regions that are marked as unavailable + mSpaceManager->ClearRegions(); + + // Get our border/padding info + nsStyleMolecule* myMol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + + // Compute the column's max size + nsSize columnMaxSize = GetColumnAvailSpace(aPresContext, myMol, aMaxSize); + + // XXX Style code should be dealing with this... + PRBool isPseudoFrame = IsPseudoFrame(); + nscoord leftInset = 0, topInset = 0; + if (!isPseudoFrame) { + leftInset = myMol->borderPadding.left; + topInset = myMol->borderPadding.top; + } + + // Get the column's desired rect + nsRect desiredRect; + + mSpaceManager->Translate(leftInset, topInset); + status = ReflowChild(mFirstChild, aPresContext, mSpaceManager, columnMaxSize, + desiredRect, aMaxElementSize); + mSpaceManager->Translate(-leftInset, -topInset); + + // Place and size the column + desiredRect.x += leftInset; + desiredRect.y += topInset; + mFirstChild->SetRect(desiredRect); + + // Set our last content offset and whether the last content is complete + // based on the state of the pseudo frame + SetLastContentOffset(mFirstChild); + + // Return our desired size. Take into account the y-most floater + aDesiredSize.width = desiredRect.XMost(); + aDesiredSize.height = PR_MAX(desiredRect.YMost(), mSpaceManager->YMost()); + + if (!isPseudoFrame) { + aDesiredSize.width += myMol->borderPadding.left + myMol->borderPadding.right; + aDesiredSize.height += myMol->borderPadding.top + myMol->borderPadding.bottom; + } + aDesiredSize.ascent = aDesiredSize.height; + aDesiredSize.descent = 0; + } + + return status; +} + +void nsBodyFrame::VerifyTree() const +{ +#ifdef NS_DEBUG + // Check our child count + PRInt32 len = LengthOf(mFirstChild); + NS_ASSERTION(len == mChildCount, "bad child count"); + nsIFrame* lastChild = LastChild(); + if (len != 0) { + NS_ASSERTION(nsnull != lastChild, "bad last child"); + } + NS_ASSERTION(nsnull == mOverflowList, "bad overflow list"); + + // Make sure our content offsets are sane + NS_ASSERTION(mFirstContentOffset <= mLastContentOffset, "bad offsets"); + + // Verify child content offsets + PRInt32 offset = mFirstContentOffset; + nsIFrame* child = mFirstChild; + while (nsnull != child) { + // Make sure that the child's tree is valid + child->VerifyTree(); + child = child->GetNextSibling(); + } + + // Make sure that our flow blocks offsets are all correct + if (nsnull == mPrevInFlow) { + PRInt32 nextOffset = NextChildOffset(); + nsBodyFrame* nextInFlow = (nsBodyFrame*) mNextInFlow; + while (nsnull != nextInFlow) { + NS_ASSERTION(0 != nextInFlow->mChildCount, "empty next-in-flow"); + NS_ASSERTION(nextInFlow->GetFirstContentOffset() == nextOffset, + "bad next-in-flow first offset"); + nextOffset = nextInFlow->NextChildOffset(); + nextInFlow = (nsBodyFrame*) nextInFlow->mNextInFlow; + } + } +#endif +} + +nsIFrame::ReflowStatus +nsBodyFrame::IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand) +{ + ReflowStatus status; + + // Get our border/padding info + nsStyleMolecule* myMol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + + // XXX Style code should be dealing with this... + PRBool isPseudoFrame = IsPseudoFrame(); + nscoord leftInset = 0, topInset = 0; + if (!isPseudoFrame) { + leftInset = myMol->borderPadding.left; + topInset = myMol->borderPadding.top; + } + + // XXX Clear the list of regions. This fixes a problem with the way reflow + // appended is currently working (we're reflowing some framems twice) + mSpaceManager->ClearRegions(); + mSpaceManager->Translate(leftInset, topInset); + + // Is the reflow command targeted for us? + if (aReflowCommand.GetTarget() == this) { + // Currently we only support appended content + if (aReflowCommand.GetType() != nsReflowCommand::FrameAppended) { + NS_NOTYETIMPLEMENTED("unexpected reflow command"); + } + + // Compute the column's max size + nsSize columnMaxSize = GetColumnAvailSpace(aPresContext, myMol, aMaxSize); + + // Pass the command along to our column pseudo frame + nsIRunaround* reflowRunaround; + nsRect aDesiredRect; + + NS_ASSERTION(nsnull != mFirstChild, "no first child"); + mFirstChild->QueryInterface(kIRunaroundIID, (void**)&reflowRunaround); + status = reflowRunaround->IncrementalReflow(aPresContext, mSpaceManager, + columnMaxSize, aDesiredRect, aReflowCommand); + + // Place and size the column + aDesiredRect.x += leftInset; + aDesiredRect.y += topInset; + mFirstChild->SetRect(aDesiredRect); + + // Set our last content offset and whether the last content is complete + // based on the state of the pseudo frame + SetLastContentOffset(mFirstChild); + + // Return our desired size + aDesiredSize.width = aDesiredRect.XMost(); + aDesiredSize.height = aDesiredRect.YMost(); + if (!isPseudoFrame) { + aDesiredSize.width += myMol->borderPadding.left + myMol->borderPadding.right; + aDesiredSize.height += myMol->borderPadding.top + myMol->borderPadding.bottom; + } + aDesiredSize.ascent = aDesiredSize.height; + aDesiredSize.descent = 0; + } else { + NS_NOTYETIMPLEMENTED("unexpected reflow command"); + nsRect desiredRect; + nsIFrame* child; + + status = aReflowCommand.Next(mSpaceManager, desiredRect, aMaxSize, child); + + // XXX Deal with next in flow, adjusting of siblings, adjusting the + // content length... + + // Return our desired size + aDesiredSize.width = 0; + aDesiredSize.height = 0; + aDesiredSize.ascent = aDesiredSize.height; + aDesiredSize.descent = 0; + } + + mSpaceManager->Translate(-leftInset, -topInset); + return status; +} + +void nsBodyFrame::ContentAppended(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer) +{ + NS_ASSERTION(mContent == aContainer, "bad content-appended target"); + + // Zip down to the end-of-flow + nsBodyFrame* flow = this; + for (;;) { + nsBodyFrame* next = (nsBodyFrame*) flow->GetNextInFlow(); + if (nsnull == next) { + break; + } + flow = next; + } + + // Since body frame's have only a single pseudo-frame in them, + // pass on the content-appended call to the pseudo-frame + PRInt32 oldLastContentOffset = mLastContentOffset; + flow->mFirstChild->ContentAppended(aShell, aPresContext, aContainer); + + // Now generate a frame reflow command aimed at flow + nsReflowCommand* rc = + new nsReflowCommand(aPresContext, flow, nsReflowCommand::FrameAppended, + oldLastContentOffset); + aShell->AppendReflowCommand(rc); +} + +void nsBodyFrame::AddAnchoredItem(nsIFrame* aAnchoredItem, + AnchoringPosition aPosition, + nsIFrame* aContainer) +{ + aAnchoredItem->SetGeometricParent(this); + // Add the item to the end of the child list + LastChild()->SetNextSibling(aAnchoredItem); + aAnchoredItem->SetNextSibling(nsnull); + mChildCount++; +} + +void nsBodyFrame::RemoveAnchoredItem(nsIFrame* aAnchoredItem) +{ + NS_PRECONDITION(this == aAnchoredItem->GetGeometricParent(), "bad anchored item"); + NS_ASSERTION(aAnchoredItem != mFirstChild, "unexpected anchored item"); + // Remove the anchored item from the child list + // XXX Implement me + mChildCount--; +} + +nsIFrame* nsBodyFrame::CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent) +{ + nsBodyFrame* cf = new nsBodyFrame(mContent, mIndexInParent, aParent); + PrepareContinuingFrame(aPresContext, aParent, cf); + return cf; +} + +// XXX use same logic as block frame? +PRIntn nsBodyFrame::GetSkipSides() const +{ + PRIntn skip = 0; + if (nsnull != mPrevInFlow) { + skip |= 1 << NS_SIDE_TOP; + } + if (nsnull != mNextInFlow) { + skip |= 1 << NS_SIDE_BOTTOM; + } + return skip; +} diff --git a/mozilla/layout/html/base/src/nsBodyFrame.h b/mozilla/layout/html/base/src/nsBodyFrame.h new file mode 100644 index 00000000000..563e779b21b --- /dev/null +++ b/mozilla/layout/html/base/src/nsBodyFrame.h @@ -0,0 +1,79 @@ +/* -*- 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. + */ +#ifndef nsBodyFrame_h___ +#define nsBodyFrame_h___ + +#include "nsHTMLContainerFrame.h" +#include "nsIAnchoredItems.h" + +struct nsBodyReflowState; +class SpaceManager; + +class nsBodyFrame : public nsHTMLContainerFrame, public nsIAnchoredItems { +public: + static nsresult NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); + + virtual ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + + virtual ReflowStatus IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand); + + virtual void ContentAppended(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer); + + virtual nsIFrame* CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent); + + virtual void AddAnchoredItem(nsIFrame* aAnchoredItem, + AnchoringPosition aPosition, + nsIFrame* aContainer); + + virtual void RemoveAnchoredItem(nsIFrame* aAnchoredItem); + + virtual void VerifyTree() const; + +protected: + nsBodyFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + ~nsBodyFrame(); + + virtual PRIntn GetSkipSides() const; + +private: + SpaceManager* mSpaceManager; + + void CreateColumnFrame(nsIPresContext* aPresContext); + nsSize GetColumnAvailSpace(nsIPresContext* aPresContext, + nsStyleMolecule* aStyleMolecule, + const nsSize& aMaxSize); +}; + +#endif /* nsBodyFrame_h___ */ diff --git a/mozilla/layout/html/base/src/nsBodyPart.cpp b/mozilla/layout/html/base/src/nsBodyPart.cpp new file mode 100644 index 00000000000..3fb848829a8 --- /dev/null +++ b/mozilla/layout/html/base/src/nsBodyPart.cpp @@ -0,0 +1,84 @@ +/* -*- 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 "nsHTMLParts.h" +#include "nsHTMLContainer.h" +#include "nsBodyFrame.h" +#include "nsIPresContext.h" +#include "nsHTMLIIDs.h" + +class BodyPart : public nsHTMLContainer { +public: + BodyPart(nsIAtom* aTag); + + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + +protected: + virtual ~BodyPart(); +}; + +BodyPart::BodyPart(nsIAtom* aTag) + : nsHTMLContainer(aTag) +{ +} + +BodyPart::~BodyPart() +{ +} + +nsrefcnt BodyPart::AddRef(void) +{ + return ++mRefCnt; +} + +nsrefcnt BodyPart::Release(void) +{ + if (--mRefCnt == 0) { + delete this; + return 0; + } + return mRefCnt; +} + +nsIFrame* BodyPart::CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + nsIFrame* rv; + nsresult status = nsBodyFrame::NewFrame(&rv, this, aIndexInParent, + aParentFrame); + return rv; +} + +nsresult +NS_NewBodyPart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIHTMLContent* body = new BodyPart(aTag); + if (nsnull == body) { + return NS_ERROR_OUT_OF_MEMORY; + } + return body->QueryInterface(kIHTMLContentIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/layout/html/base/src/nsColumnFrame.cpp b/mozilla/layout/html/base/src/nsColumnFrame.cpp new file mode 100644 index 00000000000..5e93a9a86b5 --- /dev/null +++ b/mozilla/layout/html/base/src/nsColumnFrame.cpp @@ -0,0 +1,1273 @@ +/* -*- 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 "nsColumnFrame.h" +#include "nsIContent.h" +#include "nsIContentDelegate.h" +#include "nsBlockFrame.h" +#include "nsReflowCommand.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsIPresContext.h" +#include "nsIPresShell.h" +#include "nsIViewManager.h" +#include "nsIDeviceContext.h" +#include "nsISpaceManager.h" + +#ifdef NS_DEBUG +#undef NOISY +#undef NOISY_FLOW +#else +#undef NOISY +#undef NOISY_FLOW +#endif + +static NS_DEFINE_IID(kIRunaroundIID, NS_IRUNAROUND_IID); +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); + +struct ColumnReflowState { + // The space manager to use + nsISpaceManager* spaceManager; + + // The body's style molecule + nsStyleMolecule* mol; + + // The body's available size (computed from the body's parent) + nsSize availSize; + + // The running max child x-most (used to size our frame when done). + // This includes the child's right margin. + nscoord kidXMost; + + // Running y-offset + nscoord y; + + // Margin tracking information + nscoord prevMaxPosBottomMargin; + nscoord prevMaxNegBottomMargin; + + // Flags for whether the max size is unconstrained + PRBool unconstrainedWidth; + PRBool unconstrainedHeight; + + ColumnReflowState(nsIPresContext* aPresContext, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsStyleMolecule* aMol) + { + spaceManager = aSpaceManager; + mol = aMol; + availSize.width = aMaxSize.width; + availSize.height = aMaxSize.height; + kidXMost = 0; + prevMaxPosBottomMargin = 0; + prevMaxNegBottomMargin = 0; + unconstrainedWidth = PRBool(aMaxSize.width == NS_UNCONSTRAINEDSIZE); + unconstrainedHeight = PRBool(aMaxSize.height == NS_UNCONSTRAINEDSIZE); + + // Since we're always used as a pseudo frame we have no border/padding + y = 0; + } + + ~ColumnReflowState() { + } +}; + +ColumnFrame::ColumnFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsHTMLContainerFrame(aContent, aIndexInParent, aParentFrame) +{ + NS_PRECONDITION(IsPseudoFrame(), "can only be used as a pseudo frame"); +} + +ColumnFrame::~ColumnFrame() +{ +} + +nsresult ColumnFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) +{ + NS_PRECONDITION(0 != aInstancePtr, "null ptr"); + if (nsnull == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kIRunaroundIID)) { + *aInstancePtr = (void**)((nsIRunaround*)this); + return NS_OK; + } + return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr); +} + +// Collapse child's top margin with previous bottom margin +nscoord ColumnFrame::GetTopMarginFor(nsIPresContext* aCX, + ColumnReflowState& aState, + nsStyleMolecule* aKidMol) +{ + nscoord margin; + nscoord maxNegTopMargin = 0; + nscoord maxPosTopMargin = 0; + if ((margin = aKidMol->margin.top) < 0) { + maxNegTopMargin = -margin; + } else { + maxPosTopMargin = margin; + } + + nscoord maxPos = PR_MAX(aState.prevMaxPosBottomMargin, maxPosTopMargin); + nscoord maxNeg = PR_MAX(aState.prevMaxNegBottomMargin, maxNegTopMargin); + margin = maxPos - maxNeg; + + return margin; +} + +// Position and size aKidFrame and update our reflow state. The origin of +// aKidRect is relative to the upper-left origin of our frame, and includes +// any left/top margin. +void ColumnFrame::PlaceChild(nsIPresContext* aPresContext, + ColumnReflowState& aState, + nsIFrame* aKidFrame, + const nsRect& aKidRect, + nsStyleMolecule* aKidMol, + nsSize* aMaxElementSize, + nsSize& aKidMaxElementSize) +{ + // Place and size the child + aKidFrame->SetRect(aKidRect); + + // Adjust the running y-offset + aState.y += aKidRect.height; + aState.spaceManager->Translate(0, aKidRect.height); + + // Update the x-most + nscoord xMost = aKidRect.XMost() + aKidMol->margin.right; + if (xMost > aState.kidXMost) { + aState.kidXMost = xMost; + } + + // If our height is constrained then update the available height + if (PR_FALSE == aState.unconstrainedHeight) { + aState.availSize.height -= aKidRect.height; + } + + // Update the maximum element size + if (nsnull != aMaxElementSize) { + if (aKidMaxElementSize.width > aMaxElementSize->width) { + aMaxElementSize->width = aKidMaxElementSize.width; + } + if (aKidMaxElementSize.height > aMaxElementSize->height) { + aMaxElementSize->height = aKidMaxElementSize.height; + } + } +} + +/** + * Reflow the frames we've already created + * + * @param aPresContext presentation context to use + * @param aState current inline state + * @return true if we successfully reflowed all the mapped children and false + * otherwise, e.g. we pushed children to the next in flow + */ +PRBool ColumnFrame::ReflowMappedChildren(nsIPresContext* aPresContext, + ColumnReflowState& aState, + nsSize* aMaxElementSize) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": reflow mapped (childCount=%d) [%d,%d,%c]\n", + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); +#ifdef NOISY_FLOW + { + ColumnFrame* flow = (ColumnFrame*) mNextInFlow; + while (flow != 0) { + printf(" %p: [%d,%d,%c]\n", + flow, flow->mFirstContentOffset, flow->mLastContentOffset, + (flow->mLastContentIsComplete ? 'T' : 'F')); + flow = (ColumnFrame*) flow->mNextInFlow; + } + } +#endif +#endif + NS_PRECONDITION(nsnull != mFirstChild, "no children"); + + PRInt32 childCount = 0; + nsIFrame* prevKidFrame = nsnull; + + // Remember our original mLastContentIsComplete so that if we end up + // having to push children, we have the correct value to hand to + // PushChildren. + PRBool lastContentIsComplete = mLastContentIsComplete; + + nsSize kidMaxElementSize; + nsSize* pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull; + PRBool result = PR_TRUE; + + for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; ) { + nsSize kidAvailSize(aState.availSize); + nsRect kidRect; + nsIFrame::ReflowStatus status; + + // Get top margin for this kid + nsIContent* kid = kidFrame->GetContent(); + nsIStyleContext* kidSC = kidFrame->GetStyleContext(aPresContext); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol); + nscoord bottomMargin = kidMol->margin.bottom; + NS_RELEASE(kid); + NS_RELEASE(kidSC); + + // Figure out the amount of available size for the child (subtract + // off the top margin we are going to apply to it) + if (PR_FALSE == aState.unconstrainedHeight) { + kidAvailSize.height -= topMargin; + } + // Subtract off for left and right margin + if (PR_FALSE == aState.unconstrainedWidth) { + kidAvailSize.width -= kidMol->margin.left + kidMol->margin.right; + } + + // Only skip the reflow if this is not our first child and we are + // out of space. + if ((kidFrame == mFirstChild) || (kidAvailSize.height > 0)) { + // Reflow the child into the available space + aState.spaceManager->Translate(kidMol->margin.left, topMargin); + status = ReflowChild(kidFrame, aPresContext, aState.spaceManager, + kidAvailSize, kidRect, pKidMaxElementSize); + aState.spaceManager->Translate(-kidMol->margin.left, -topMargin); + } + + // Did the child fit? + if ((kidFrame != mFirstChild) && + ((kidAvailSize.height <= 0) || + (kidRect.YMost() > kidAvailSize.height))) + { + // The child's height is too big to fit at all in our remaining space, + // and it's not our first child. + // + // Note that if the width is too big that's okay and we allow the + // child to extend horizontally outside of the reflow area + + // Since we are giving the next-in-flow our last child, we + // give it our original mLastContentIsComplete, too (in case we + // are pushing into an empty next-in-flow) + PushChildren(kidFrame, prevKidFrame, lastContentIsComplete); + + // Our mLastContentIsComplete was already set by the last kid we + // reflowed reflow's status + result = PR_FALSE; + break; + } + + // Place the child after taking into account it's margin + aState.y += topMargin; + aState.spaceManager->Translate(0, topMargin); + kidRect.x += kidMol->margin.left; + kidRect.y += aState.y; + PlaceChild(aPresContext, aState, kidFrame, kidRect, kidMol, aMaxElementSize, + kidMaxElementSize); + if (bottomMargin < 0) { + aState.prevMaxNegBottomMargin = -bottomMargin; + } else { + aState.prevMaxPosBottomMargin = bottomMargin; + } + childCount++; + + // Update mLastContentIsComplete now that this kid fits + mLastContentIsComplete = PRBool(status == frComplete); + + // Special handling for incomplete children + if (frNotComplete == status) { + // XXX It's good to assume that we might still have room + // even if the child didn't complete (floaters will want this) + nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); + if (nsnull == kidNextInFlow) { + // No the child isn't complete, and it doesn't have a next in flow so + // create a continuing frame. This hooks the child into the flow. + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aPresContext, this); + + // Insert the frame. We'll reflow it next pass through the loop + nsIFrame* nextSib = kidFrame->GetNextSibling(); + continuingFrame->SetNextSibling(nextSib); + kidFrame->SetNextSibling(continuingFrame); + if (nsnull == nextSib) { + // Assume that the continuation frame we just created is + // complete, for now. It will get reflowed by our + // next-in-flow (we are going to push it now) + lastContentIsComplete = PR_TRUE; + } + } + } + + // Get the next child + prevKidFrame = kidFrame; + kidFrame = kidFrame->GetNextSibling(); + + // XXX talk with troy about checking for available space here + } + + // Update the child count + mChildCount = childCount; + NS_POSTCONDITION(LengthOf(mFirstChild) == mChildCount, "bad child count"); + + // Set the last content offset based on the last child we mapped. + NS_ASSERTION(LastChild() == prevKidFrame, "unexpected last child"); + SetLastContentOffset(prevKidFrame); + +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": reflow mapped %sok (childCount=%d) [%d,%d,%c]\n", + (result ? "" : "NOT "), + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); +#ifdef NOISY_FLOW + { + ColumnFrame* flow = (ColumnFrame*) mNextInFlow; + while (flow != 0) { + printf(" %p: [%d,%d,%c]\n", + flow, flow->mFirstContentOffset, flow->mLastContentOffset, + (flow->mLastContentIsComplete ? 'T' : 'F')); + flow = (ColumnFrame*) flow->mNextInFlow; + } + } +#endif +#endif + return result; +} + +/** + * Try and pull-up frames from our next-in-flow + * + * @param aPresContext presentation context to use + * @param aState current inline state + * @return true if we successfully pulled-up all the children and false + * otherwise, e.g. child didn't fit + */ +PRBool ColumnFrame::PullUpChildren(nsIPresContext* aPresContext, + ColumnReflowState& aState, + nsSize* aMaxElementSize) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": pullup (childCount=%d) [%d,%d,%c]\n", + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); +#ifdef NOISY_FLOW + { + ColumnFrame* flow = (ColumnFrame*) mNextInFlow; + while (flow != 0) { + printf(" %p: [%d,%d,%c]\n", + flow, flow->mFirstContentOffset, flow->mLastContentOffset, + (flow->mLastContentIsComplete ? 'T' : 'F')); + flow = (ColumnFrame*) flow->mNextInFlow; + } + } +#endif +#endif + NS_PRECONDITION(nsnull != mNextInFlow, "null next-in-flow"); + ColumnFrame* nextInFlow = (ColumnFrame*)mNextInFlow; + nsSize kidMaxElementSize; + nsSize* pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull; + + // The frame previous to the current frame we are reflowing. This + // starts out initially as our last frame. + nsIFrame* prevKidFrame = LastChild(); + + // This will hold the prevKidFrame's mLastContentIsComplete + // status. If we have to push the frame that follows prevKidFrame + // then this will become our mLastContentIsComplete state. Since + // prevKidFrame is initially our last frame, it's completion status + // is our mLastContentIsComplete value. + PRBool prevLastContentIsComplete = mLastContentIsComplete; + PRBool result = PR_TRUE; + + while (nsnull != nextInFlow) { + nsRect kidRect; + nsSize kidAvailSize(aState.availSize); + + // Get first available frame from the next-in-flow + nsIFrame* kidFrame = PullUpOneChild(nextInFlow, prevKidFrame); + if (nsnull == kidFrame) { + // We've pulled up all the children from that next-in-flow, so + // move to the next next-in-flow. + nextInFlow = (ColumnFrame*) nextInFlow->mNextInFlow; + continue; + } + + // Get top margin for this kid + nsIContent* kid = kidFrame->GetContent(); + nsIStyleContext* kidSC = kidFrame->GetStyleContext(aPresContext); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol); + nscoord bottomMargin = kidMol->margin.bottom; + + // Figure out the amount of available size for the child (subtract + // off the top margin we are going to apply to it) + if (PR_FALSE == aState.unconstrainedHeight) { + kidAvailSize.height -= topMargin; + } + // Subtract off for left and right margin + if (PR_FALSE == aState.unconstrainedWidth) { + kidAvailSize.width -= kidMol->margin.left + kidMol->margin.right; + } + + ReflowStatus status; + do { + // Only skip the reflow if this is not our first child and we are + // out of space. + if ((kidFrame == mFirstChild) || (kidAvailSize.height > 0)) { + aState.spaceManager->Translate(kidMol->margin.left, topMargin); + status = ReflowChild(kidFrame, aPresContext, aState.spaceManager, + kidAvailSize, kidRect, pKidMaxElementSize); + aState.spaceManager->Translate(-kidMol->margin.left, -topMargin); + } + + // Did the child fit? + if ((kidFrame != mFirstChild) && + ((kidAvailSize.height <= 0) || + (kidRect.YMost() > kidAvailSize.height))) + { + // The child's height is too big to fit at all in our remaining space, + // and it wouldn't have been our first child. + // + // Note that if the width is too big that's okay and we allow the + // child to extend horizontally outside of the reflow area + PRBool lastComplete = PRBool(nsnull == kidFrame->GetNextInFlow()); + PushChildren(kidFrame, prevKidFrame, lastComplete); + mLastContentIsComplete = prevLastContentIsComplete; + mChildCount--; + result = PR_FALSE; + NS_RELEASE(kid); + NS_RELEASE(kidSC); + goto push_done; + } + + // Place the child + aState.y += topMargin; + aState.spaceManager->Translate(0, topMargin); + kidRect.x += kidMol->margin.left; + kidRect.y += aState.y; + PlaceChild(aPresContext, aState, kidFrame, kidRect, kidMol, aMaxElementSize, + kidMaxElementSize); + if (bottomMargin < 0) { + aState.prevMaxNegBottomMargin = -bottomMargin; + } else { + aState.prevMaxPosBottomMargin = bottomMargin; + } + mLastContentIsComplete = PRBool(status == frComplete); + +#ifdef NOISY + ListTag(stdout); + printf(": pulled up "); + ((nsFrame*)kidFrame)->ListTag(stdout); + printf("\n"); +#endif + + // Is the child we just pulled up complete? + if (frNotComplete == status) { + // No the child isn't complete. + nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); + if (nsnull == kidNextInFlow) { + // The child doesn't have a next-in-flow so create a + // continuing frame. The creation appends it to the flow and + // prepares it for reflow. + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aPresContext, this); + + // Add the continuing frame to our sibling list. + continuingFrame->SetNextSibling(kidFrame->GetNextSibling()); + kidFrame->SetNextSibling(continuingFrame); + prevKidFrame = kidFrame; + prevLastContentIsComplete = mLastContentIsComplete; + kidFrame = continuingFrame; + mChildCount++; + } else { + // The child has a next-in-flow, but it's not one of ours. + // It *must* be in one of our next-in-flows. Collect it + // then. + NS_ASSERTION(kidNextInFlow->GetGeometricParent() != this, + "busted kid next-in-flow"); + break; + } + } + } while (frNotComplete == status); + NS_RELEASE(kid); + NS_RELEASE(kidSC); + + prevKidFrame = kidFrame; + prevLastContentIsComplete = mLastContentIsComplete; + } + + push_done:; + // Update our last content index + if (nsnull != prevKidFrame) { + NS_ASSERTION(LastChild() == prevKidFrame, "bad last child"); + SetLastContentOffset(prevKidFrame); + } + + // We need to make sure the first content offset is correct for any empty + // next-in-flow frames (frames where we pulled up all the child frames) + nextInFlow = (ColumnFrame*)mNextInFlow; + if ((nsnull != nextInFlow) && (nsnull == nextInFlow->mFirstChild)) { + // We have at least one empty frame. Did we succesfully pull up all the + // child frames? + if (PR_FALSE == result) { + // No, so we need to adjust the first content offset of all the empty + // frames + AdjustOffsetOfEmptyNextInFlows(); +#ifdef NS_DEBUG + } else { + // Yes, we successfully pulled up all the child frames which means all + // the next-in-flows must be empty. Do a sanity check + while (nsnull != nextInFlow) { + NS_ASSERTION(nsnull == nextInFlow->mFirstChild, "non-empty next-in-flow"); + nextInFlow = (ColumnFrame*)nextInFlow->GetNextInFlow(); + } +#endif + } + } + +#ifdef NS_DEBUG + PRInt32 len = LengthOf(mFirstChild); + NS_ASSERTION(len == mChildCount, "bad child count"); + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": pullup %sok (childCount=%d) [%d,%d,%c]\n", + (result ? "" : "NOT "), + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); +#ifdef NOISY_FLOW + { + ColumnFrame* flow = (ColumnFrame*) mNextInFlow; + while (flow != 0) { + printf(" %p: [%d,%d,%c]\n", + flow, flow->mFirstContentOffset, flow->mLastContentOffset, + (flow->mLastContentIsComplete ? 'T' : 'F')); + flow = (ColumnFrame*) flow->mNextInFlow; + } + } +#endif +#endif + return result; +} + +/** + * Create new frames for content we haven't yet mapped + * + * @param aPresContext presentation context to use + * @param aState current inline state + * @return frComplete if all content has been mapped and frNotComplete + * if we should be continued + */ +nsIFrame::ReflowStatus +ColumnFrame::ReflowUnmappedChildren(nsIPresContext* aPresContext, + ColumnReflowState& aState, + nsSize* aMaxElementSize) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif + nsIFrame* kidPrevInFlow = nsnull; + ReflowStatus result = frNotComplete; + + // If we have no children and we have a prev-in-flow then we need to pick + // up where it left off. If we have children, e.g. we're being resized, then + // our content offset should already be set correctly... + if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) { + ColumnFrame* prev = (ColumnFrame*)mPrevInFlow; + NS_ASSERTION(prev->mLastContentOffset >= prev->mFirstContentOffset, "bad prevInFlow"); + + mFirstContentOffset = prev->NextChildOffset(); + if (!prev->mLastContentIsComplete) { + // Our prev-in-flow's last child is not complete + kidPrevInFlow = prev->LastChild(); + } + } + + PRBool originalLastContentIsComplete = mLastContentIsComplete; + + // Place our children, one at a time, until we are out of children + nsSize kidMaxElementSize; + nsSize* pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull; + PRInt32 kidIndex = NextChildOffset(); + nsIFrame* prevKidFrame = LastChild(); // XXX remember this... + + for (;;) { + // Get the next content object + nsIContent* kid = mContent->ChildAt(kidIndex); + if (nsnull == kid) { + result = frComplete; + break; + } + + // Make sure we still have room left + if (aState.availSize.height <= 0) { + // Note: return status was set to frNotComplete above... + NS_RELEASE(kid); + break; + } + + // Resolve style + nsIStyleContext* kidStyleContext = + aPresContext->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = + (nsStyleMolecule*)kidStyleContext->GetData(kStyleMoleculeSID); + nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol); + nscoord bottomMargin = kidMol->margin.bottom; + + nsBlockFrame* pseudoFrame = nsnull; + nsIFrame* kidFrame; + nsRect kidRect; + ReflowStatus status; + + // Create a child frame + if (nsnull == kidPrevInFlow) { + // Figure out how to treat the content + nsIContentDelegate* kidDel = nsnull; + switch (kidMol->display) { + case NS_STYLE_DISPLAY_NONE: + // Create a placeholder frame that takes up no space + NS_ASSERTION(nsnull == kidPrevInFlow, "bad prev in flow"); + nsFrame::NewFrame(&kidFrame, kid, kidIndex, this); + break; + + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + // Get the content delegate to use. We'll need this to create a frame + kidDel = kid->GetDelegate(aPresContext); + kidFrame = kidDel->CreateFrame(aPresContext, kid, kidIndex, this); + NS_RELEASE(kidDel); + break; + + case NS_STYLE_DISPLAY_INLINE: + // Inline elements are wrapped in a block pseudo frame; that way the + // body doesn't have to deal with 2D layout + nsBlockFrame::NewFrame(&kidFrame, mContent, mIndexInParent, this); + + // Set the content offset for the pseudo frame, so it knows + // which content to begin with + pseudoFrame = (nsBlockFrame*) kidFrame; + pseudoFrame->SetFirstContentOffset(kidIndex); + break; + } + kidFrame->SetStyleContext(kidStyleContext); + } else { + kidFrame = kidPrevInFlow->CreateContinuingFrame(aPresContext, this); + if (ChildIsPseudoFrame(kidFrame)) { + pseudoFrame = (nsBlockFrame*) kidFrame; + } + } + + // Link the child frame into the list of children and update the + // child count + if (nsnull != prevKidFrame) { + NS_ASSERTION(nsnull == prevKidFrame->GetNextSibling(), "bad append"); + prevKidFrame->SetNextSibling(kidFrame); + } else { + NS_ASSERTION(nsnull == mFirstChild, "bad create"); + mFirstChild = kidFrame; + SetFirstContentOffset(kidFrame); + } + mChildCount++; + + do { + nsSize kidAvailSize(aState.availSize); + + // Figure out the amount of available size for the child (subtract + // off the margin we are going to apply to it) + if (PR_FALSE == aState.unconstrainedHeight) { + kidAvailSize.height -= topMargin; + } + // Subtract off for left and right margin + if (PR_FALSE == aState.unconstrainedWidth) { + kidAvailSize.width -= kidMol->margin.left + kidMol->margin.right; + } + + // Try to reflow the child into the available space. It might not + // fit or might need continuing + if (kidAvailSize.height > 0) { + aState.spaceManager->Translate(kidMol->margin.left, topMargin); + status = ReflowChild(kidFrame, aPresContext, aState.spaceManager, + kidAvailSize, kidRect, pKidMaxElementSize); + aState.spaceManager->Translate(-kidMol->margin.left, -topMargin); + } + + // Did the child fit? + if ((nsnull != mFirstChild) && + ((kidAvailSize.height <= 0) || + (kidRect.YMost() > kidAvailSize.height))) { + // The child's height is too big to fit in our remaining + // space, and it's not our first child. + NS_ASSERTION(nsnull == mOverflowList, "bad overflow list"); + NS_ASSERTION(nsnull == mNextInFlow, "whoops"); + + // Chop off the part of our child list that's being overflowed + NS_ASSERTION(prevKidFrame->GetNextSibling() == kidFrame, "bad list"); + prevKidFrame->SetNextSibling(nsnull); + + // Create overflow list + mOverflowList = kidFrame; + + // Fixup child count by subtracting off the number of children + // that just ended up on the reflow list. + PRInt32 overflowKids = 0; + nsIFrame* f = kidFrame; + while (nsnull != f) { + overflowKids++; + f = f->GetNextSibling(); + } + mChildCount -= overflowKids; + NS_RELEASE(kidStyleContext); + NS_RELEASE(kid); + goto done; + } + + // Advance y by the topMargin between children. Zero out the + // topMargin in case this frame is continued because + // continuations do not have a top margin. Update the prev + // bottom margin state in the body reflow state so that we can + // apply the bottom margin when we hit the next child (or + // finish). + aState.y += topMargin; + aState.spaceManager->Translate(0, topMargin); + kidRect.x += kidMol->margin.left; + kidRect.y += aState.y; + PlaceChild(aPresContext, aState, kidFrame, kidRect, kidMol, aMaxElementSize, + kidMaxElementSize); + if (bottomMargin < 0) { + aState.prevMaxNegBottomMargin = -bottomMargin; + } else { + aState.prevMaxPosBottomMargin = bottomMargin; + } + topMargin = 0; + + mLastContentIsComplete = PRBool(status == frComplete); + if (frNotComplete == status) { + // Child didn't complete so create a continuing frame + kidPrevInFlow = kidFrame; + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aPresContext, this); + + // Add the continuing frame to the sibling list + continuingFrame->SetNextSibling(kidFrame->GetNextSibling()); + kidFrame->SetNextSibling(continuingFrame); + prevKidFrame = kidFrame; + kidFrame = continuingFrame; + mChildCount++; + + if (nsnull != pseudoFrame) { + pseudoFrame = (nsBlockFrame*) kidFrame; + } + + // XXX We probably shouldn't assume that there is no room for + // the continuation + } + } while (frNotComplete == status); + NS_RELEASE(kidStyleContext); + NS_RELEASE(kid); + + prevKidFrame = kidFrame; + kidPrevInFlow = nsnull; + + // Update the kidIndex + if (nsnull != pseudoFrame) { + // Adjust kidIndex to reflect the number of children mapped by + // the pseudo frame + kidIndex = pseudoFrame->NextChildOffset(); + } else { + kidIndex++; + } + } + +done: + // Update the content mapping + NS_ASSERTION(LastChild() == prevKidFrame, "bad last child"); + if (0 != mChildCount) { + SetLastContentOffset(prevKidFrame); + } +#ifdef NS_DEBUG + PRInt32 len = LengthOf(mFirstChild); + NS_ASSERTION(len == mChildCount, "bad child count"); + VerifyLastIsComplete(); +#endif + return result; +} + +nsIFrame::ReflowStatus +ColumnFrame::ResizeReflow(nsIPresContext* aPresContext, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsSize* aMaxElementSize) +{ +#ifdef NS_DEBUG + PreReflowCheck(); + + nscoord txIn, tyIn; + aSpaceManager->GetTranslation(txIn, tyIn); +#endif + //XXX NS_PRECONDITION((aMaxSize.width > 0) && (aMaxSize.height > 0), "unexpected max size"); + + PRBool reflowMappedOK = PR_TRUE; + ReflowStatus status = frComplete; + + // Initialize out parameter + if (nsnull != aMaxElementSize) { + aMaxElementSize->width = 0; + aMaxElementSize->height = 0; + } + + // Initialize body reflow state + nsStyleMolecule* myMol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + ColumnReflowState state(aPresContext, aSpaceManager, aMaxSize, myMol); + + // Check for an overflow list + MoveOverflowToChildList(); + + // Reflow the existing frames + if (nsnull != mFirstChild) { + reflowMappedOK = + ReflowMappedChildren(aPresContext, state, aMaxElementSize); + if (PR_FALSE == reflowMappedOK) { + status = frNotComplete; + } + } + + // Did we successfully relow our mapped children? + if (PR_TRUE == reflowMappedOK) { + // Any space left? + if ((nsnull != mFirstChild) && (state.availSize.height <= 0)) { + // No space left. Don't try to pull-up children or reflow unmapped + if (NextChildOffset() < mContent->ChildCount()) { + status = frNotComplete; + } + } else if (NextChildOffset() < mContent->ChildCount()) { + // Try and pull-up some children from a next-in-flow + if ((nsnull == mNextInFlow) || + PullUpChildren(aPresContext, state, aMaxElementSize)) { + // If we still have unmapped children then create some new frames + if (NextChildOffset() < mContent->ChildCount()) { + status = + ReflowUnmappedChildren(aPresContext, state, aMaxElementSize); + } + } else { + // We were unable to pull-up all the existing frames from the + // next in flow + status = frNotComplete; + } + } + } + + // Restore the coordinate space + aSpaceManager->Translate(0, -state.y); + + if (frComplete == status) { + // Don't forget to add in the bottom margin from our last child. + // Only add it in if there's room for it. + nscoord margin = state.prevMaxPosBottomMargin - + state.prevMaxNegBottomMargin; + if (state.availSize.height >= margin) { + state.y += margin; + } + } + + // Return our desired rect + aDesiredRect.x = 0; + aDesiredRect.y = 0; + aDesiredRect.width = state.kidXMost; + aDesiredRect.height = state.y; + + // Our desired width is always at least as big as our parent's width + // even though we reflowed our children to a narrower width. + if (!state.unconstrainedWidth && (aDesiredRect.width < aMaxSize.width)) { + aDesiredRect.width = aMaxSize.width; + } + +#ifdef NS_DEBUG + PostReflowCheck(status); + + // Verify we properly restored the coordinate space + nscoord txOut, tyOut; + + aSpaceManager->GetTranslation(txOut, tyOut); + NS_POSTCONDITION((txIn == txOut) && (tyIn == tyOut), "bad translation"); +#endif + return status; +} + +nsIFrame::ReflowStatus +ColumnFrame::IncrementalReflow(nsIPresContext* aPresContext, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsReflowCommand& aReflowCommand) +{ +#ifdef NS_DEBUG + nscoord txIn, tyIn; + aSpaceManager->GetTranslation(txIn, tyIn); +#endif + ReflowStatus status; + + // Who's the reflow command targeted for? + if (aReflowCommand.GetTarget() == mGeometricParent) { + // It's targeted for our parent frame which passed the reflow + // command along to us. + // + // Currently we only support appended content, but this could also + // be an inserted reflow command. + if (aReflowCommand.GetType() != nsReflowCommand::FrameAppended) { + NS_NOTYETIMPLEMENTED("unexpected reflow command"); + } + + // Initialize body reflow state + nsStyleMolecule* myMol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + ColumnReflowState state(aPresContext, aSpaceManager, aMaxSize, myMol); + + // Get to the frame that we should begin reflowing (where the + // append occured). + PRInt32 startOffset = aReflowCommand.GetIndex(); + nsIFrame* kidFrame = mFirstChild; + nsIFrame* prevKidFrame = nsnull; + PRInt32 kidIndex = mFirstContentOffset; + for (;;) { + if (ChildIsPseudoFrame(kidFrame)) { + nsBlockFrame* pseudo = (nsBlockFrame*) kidFrame; + PRInt32 fco = pseudo->GetFirstContentOffset(); + PRInt32 lco = pseudo->GetLastContentOffset(); + /* XXX <=? mLastContentIsComplete? */ + if ((fco <= startOffset) && (startOffset <= lco)) { + break; + } + } else { + if (kidFrame->GetIndexInParent() == startOffset) { + break; + } + } + prevKidFrame = kidFrame; + kidFrame = kidFrame->GetNextSibling(); + } + + // Factor in the previous kid's bottom margin information + // XXX inline version of RecoverState + if (nsnull != prevKidFrame) { + // When we have a previous kid frame, get it's y most coordinate + // and then setup the state so that the starting y is correct + // and the previous kid's bottom margin information is correct. + nsRect startKidRect; + prevKidFrame->GetRect(startKidRect); + + // Get style info + nsIContent* kid = prevKidFrame->GetContent(); + nsIStyleContext* kidSC = prevKidFrame->GetStyleContext(aPresContext); + nsStyleMolecule* kidMol = + (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + nscoord bottomMargin = kidMol->margin.bottom; + NS_RELEASE(kid); + NS_RELEASE(kidSC); + + state.y = startKidRect.YMost(); + if (bottomMargin < 0) { + state.prevMaxNegBottomMargin = -bottomMargin; + } else { + state.prevMaxPosBottomMargin = bottomMargin; + } + } else { + // Get style info + nsIContent* kid = kidFrame->GetContent(); + nsIStyleContext* kidSC = kidFrame->GetStyleContext(aPresContext); + nsStyleMolecule* kidMol = + (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + nscoord topMargin = kidMol->margin.top; + NS_RELEASE(kid); + NS_RELEASE(kidSC); + + // Initialize y to start after the top margin + state.y = topMargin; + } + + aSpaceManager->Translate(0, state.y); + + // XXX This nees to be computed the hard way. This value will be + // wrong because it includes our previous border+padding + // values. Since those values may have changed we need to + // recalculate our maxChildWidth based on our children and then we + // can add back in order border+padding + + // XXX subtract out old border+padding? + state.kidXMost = mRect.width; + + // Now ResizeReflow the appended frames + while (nsnull != kidFrame) { + nsIContent* kid = kidFrame->GetContent(); + nsIStyleContext* kidSC = kidFrame->GetStyleContext(aPresContext); + nsStyleMolecule* kidMol = + (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + NS_RELEASE(kid); + + nsRect kidRect; + nsSize kidAvailSize(state.availSize); + if (PR_FALSE == state.unconstrainedWidth) { + kidAvailSize.width -= kidMol->margin.left + kidMol->margin.right; + } + + // Reflow the child + state.spaceManager->Translate(kidMol->margin.left, 0); + status = ReflowChild(kidFrame, aPresContext, state.spaceManager, + kidAvailSize, kidRect, nsnull); + state.spaceManager->Translate(-kidMol->margin.left, 0); + + // Did it fit? + if ((kidFrame != mFirstChild) && + ((kidAvailSize.height <= 0) || + (kidRect.YMost() > kidAvailSize.height))) + { + // No, it didn't fit. This means we need to push this child + // to our next-in-flow and get it to reflow the appended + // children. + // XXX write me + NS_ABORT(); + } + + // Place the child + nsSize kidMaxElementSize; // XXX unused + kidRect.x += kidMol->margin.left; + kidRect.y += state.y; + PlaceChild(aPresContext, state, kidFrame, kidRect, kidMol, nsnull, + kidMaxElementSize); + nscoord bottomMargin = kidMol->margin.bottom; + if (bottomMargin < 0) { + state.prevMaxNegBottomMargin = -bottomMargin; + } else { + state.prevMaxPosBottomMargin = bottomMargin; + } + NS_RELEASE(kidSC); + + // XXX Was it complete? + if (frNotComplete == status) { + // XXX Need to push remaining frames and trigger a reflow there + NS_ABORT(); + } + + prevKidFrame = kidFrame; + kidFrame = kidFrame->GetNextSibling(); + } + SetLastContentOffset(prevKidFrame); + + // Restore the coordinate space + aSpaceManager->Translate(0, -state.y); + + // Return our desired size + // XXX What about adding in the bottom margin from our last child like we + // did in ResizeReflow()? + aDesiredRect.x = 0; + aDesiredRect.y = 0; + aDesiredRect.width = state.kidXMost;/* XXX */ + aDesiredRect.height = state.y; + + } else if (aReflowCommand.GetTarget() == this) { + // The reflow command is targeted for us. This could be a deleted or + // changed reflow command + NS_NOTYETIMPLEMENTED("unexpected reflow command"); + } else { + NS_NOTYETIMPLEMENTED("unexpected reflow command"); + } + +#ifdef NS_DEBUG + // Verify we properly restored the coordinate space + nscoord txOut, tyOut; + + aSpaceManager->GetTranslation(txOut, tyOut); + NS_POSTCONDITION((txIn == txOut) && (tyIn == tyOut), "bad translation"); +#endif + return status; +} + +// XXX factor nicely with reflow-unmapped +void ColumnFrame::ContentAppended(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer) +{ + // We must only be called by the body frame since we are a + // pseudo-frame; the body frame makes sure that it's dealing with + // it's last-in-flow therefore we must also be a last-in-flow + NS_ASSERTION(nsnull == mNextInFlow, "improper content-appended"); + NS_ASSERTION(mLastContentIsComplete == PR_TRUE, "huh?"); + + // Get index of where the content has been appended + PRInt32 kidIndex = NextChildOffset(); + PRInt32 startIndex = kidIndex; + nsIFrame* prevKidFrame = LastChild(); + nsIContent* content = mContent; + + nsBlockFrame* pseudoFrame = nsnull; + if ((nsnull != prevKidFrame) && ChildIsPseudoFrame(prevKidFrame)) { + pseudoFrame = (nsBlockFrame*) prevKidFrame; + } + + // Create frames for each new child + for (;;) { + // Get the next content object + nsIContent* kid = content->ChildAt(kidIndex); + if (nsnull == kid) { + break; + } + + // Get style context for the kid + nsIStyleContext* kidStyleContext = + aPresContext->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = + (nsStyleMolecule*)kidStyleContext->GetData(kStyleMoleculeSID); + + // See what display mode it has + nsIFrame* kidFrame; + nsIContentDelegate* del; + switch (kidMol->display) { + case NS_STYLE_DISPLAY_NONE: + // Create place holder frame + nsFrame::NewFrame(&kidFrame, kid, kidIndex, this); + kidFrame->SetStyleContext(kidStyleContext); + + // Append it to the child list + if (nsnull == prevKidFrame) { + mFirstChild = kidFrame; + mFirstContentOffset = kidIndex; + } else { + prevKidFrame->SetNextSibling(kidFrame); + } + mChildCount++; + prevKidFrame = kidFrame; + pseudoFrame = nsnull; + kidIndex++; + mLastContentOffset = kidIndex; + break; + + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + // Block and list-item's don't go into our pseudo-frames + // therefore we just make a frame. + del = kid->GetDelegate(aPresContext); + kidFrame = del->CreateFrame(aPresContext, kid, kidIndex, this); + NS_RELEASE(del); + kidFrame->SetStyleContext(kidStyleContext); + + // Append it to the child list + if (nsnull == prevKidFrame) { + mFirstChild = kidFrame; + mFirstContentOffset = kidIndex; + } else { + prevKidFrame->SetNextSibling(kidFrame); + } + mChildCount++; + prevKidFrame = kidFrame; + pseudoFrame = nsnull; + kidIndex++; + mLastContentOffset = kidIndex; + break; + + case NS_STYLE_DISPLAY_INLINE: + if (nsnull == pseudoFrame) { + // Inline elements are wrapped in a block pseudo frame; that + // way the body doesn't have to deal with 2D layout + nsBlockFrame::NewFrame(&kidFrame, mContent, mIndexInParent, this); + + // Resolve style for the pseudo-frame (kid's style won't do) + NS_RELEASE(kidStyleContext); + kidStyleContext = aPresContext->ResolveStyleContextFor(mContent, this); + kidFrame->SetStyleContext(kidStyleContext); + + // Append the pseudo frame to the child list + pseudoFrame = (nsBlockFrame*) kidFrame; + if (nsnull == prevKidFrame) { + mFirstChild = kidFrame; + mFirstContentOffset = kidIndex; + } else { + prevKidFrame->SetNextSibling(pseudoFrame); + } + mChildCount++; + + // Set the content offset for the pseudo frame, so it knows + // which content to begin with + pseudoFrame->SetFirstContentOffset(kidIndex); + pseudoFrame->SetLastContentOffset(kidIndex); + prevKidFrame = pseudoFrame; + } + + // The child frame needs to belong to the pseudo-frame (or one + // of it's pseudos). Let it do the content appended frame + // creation. + pseudoFrame->ContentAppended(aShell, aPresContext, aContainer); + + // Update *our* last content offset since this child is our last + // child and it just consumed one or more of the appended + // children. +#ifdef NS_DEBUG + if (pseudoFrame == mFirstChild) { + PRInt32 pfco = pseudoFrame->GetFirstContentOffset(); + NS_ASSERTION(mFirstContentOffset == pfco, "bad pseudo first offset"); + } +#endif + mLastContentOffset = pseudoFrame->GetLastContentOffset(); + + // Pick up where it stopped + kidIndex = NextChildOffset(); + break; + } + NS_RELEASE(kid); + NS_RELEASE(kidStyleContext); + } + SetLastContentOffset(prevKidFrame); + // Note: Column frames *never* directly generate reflow commands + // because they are always pseudo-frames for bodies. +} + +nsIFrame* ColumnFrame::CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent) +{ + ColumnFrame* cf = new ColumnFrame(mContent, mIndexInParent, aParent); + PrepareContinuingFrame(aPresContext, aParent, cf); + return cf; +} + +PRIntn ColumnFrame::GetSkipSides() const +{ + // Because we're only ever used as a pseudo frame we shouldn't have any borders + // or padding. But just to be safe... + return 0x0F; +} + +void ColumnFrame::ListTag(FILE* out) const +{ + fprintf(out, "*COLUMN@%p", this); +} + diff --git a/mozilla/layout/html/base/src/nsColumnFrame.h b/mozilla/layout/html/base/src/nsColumnFrame.h new file mode 100644 index 00000000000..0391a5d6c72 --- /dev/null +++ b/mozilla/layout/html/base/src/nsColumnFrame.h @@ -0,0 +1,86 @@ +/* -*- 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. + */ +#ifndef nsColumnFrame_h___ +#define nsColumnFrame_h___ + +#include "nsHTMLContainerFrame.h" +#include "nsIRunaround.h" + +struct ColumnReflowState; + +class ColumnFrame : public nsHTMLContainerFrame, public nsIRunaround { +public: + ColumnFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); + + virtual ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsSize* aMaxElementSize); + + virtual ReflowStatus IncrementalReflow(nsIPresContext* aPresContext, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsReflowCommand& aReflowCommand); + + virtual void ContentAppended(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer); + + virtual nsIFrame* CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent); + + // Debugging + virtual void ListTag(FILE* out = stdout) const; + +protected: + ~ColumnFrame(); + + virtual PRIntn GetSkipSides() const; + + nscoord GetTopMarginFor(nsIPresContext* aCX, + ColumnReflowState& aState, + nsStyleMolecule* aKidMol); + + void PlaceChild(nsIPresContext* aPresContext, + ColumnReflowState& aState, + nsIFrame* aKidFrame, + const nsRect& aKidRect, + nsStyleMolecule* aKidMol, + nsSize* aMaxElementSize, + nsSize& aKidMaxElementSize); + + PRBool ReflowMappedChildren(nsIPresContext* aPresContext, + ColumnReflowState& aState, + nsSize* aMaxElementSize); + + PRBool PullUpChildren(nsIPresContext* aPresContext, + ColumnReflowState& aState, + nsSize* aMaxElementSize); + + ReflowStatus ReflowUnmappedChildren(nsIPresContext* aPresContext, + ColumnReflowState& aState, + nsSize* aMaxElementSize); +}; + +#endif /* nsColumnFrame_h___ */ diff --git a/mozilla/layout/html/base/src/nsDOMAttributes.cpp b/mozilla/layout/html/base/src/nsDOMAttributes.cpp new file mode 100644 index 00000000000..31c011cc62a --- /dev/null +++ b/mozilla/layout/html/base/src/nsDOMAttributes.cpp @@ -0,0 +1,254 @@ +/* -*- 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 "nsDOMAttributes.h" +#include "nsIContent.h" +#include "nsIHTMLContent.h" +#include "nsString.h" +#include "nsIAtom.h" +#include "nsISupportsArray.h" + +nsDOMAttribute::nsDOMAttribute(nsString &aName, nsString &aValue) +{ + mName = new nsString(aName); + mValue = new nsString(aValue); + mRefCnt = 1; + mScriptObject = nsnull; +} + +nsDOMAttribute::~nsDOMAttribute() +{ + NS_PRECONDITION(nsnull != mName && nsnull != mValue, "attribute must be valid"); + delete mName; + delete mValue; +} + +nsresult nsDOMAttribute::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if (NULL == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + static NS_DEFINE_IID(kIDOMAttributeIID, NS_IDOMATTRIBUTE_IID); + static NS_DEFINE_IID(kIScriptObjectOwnerIID, NS_ISCRIPTOBJECTOWNER_IID); + if (aIID.Equals(kIDOMAttributeIID)) { + *aInstancePtr = (void*)(nsIDOMAttribute*)this; + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIScriptObjectOwnerIID)) { + *aInstancePtr = (void*)(nsIScriptObjectOwner*)this; + AddRef(); + return NS_OK; + } + if (aIID.Equals(kISupportsIID)) { + *aInstancePtr = (void*)(nsISupports*)(nsIDOMAttribute*)this; + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +NS_IMPL_ADDREF(nsDOMAttribute) + +NS_IMPL_RELEASE(nsDOMAttribute) + + +nsresult nsDOMAttribute::GetScriptObject(JSContext *aContext, void** aScriptObject) +{ + nsresult res = NS_OK; + if (nsnull == mScriptObject) { + res = NS_NewScriptAttribute(aContext, this, nsnull, (JSObject**)&mScriptObject); + } + *aScriptObject = mScriptObject; + return res; +} + +nsresult nsDOMAttribute::ResetScriptObject() +{ + mScriptObject = nsnull; + return NS_OK; +} + +// +// nsIDOMAttribute interface +// +nsresult nsDOMAttribute::GetName(nsString &aName) +{ + aName = *mName; + return NS_OK; +} + +nsresult nsDOMAttribute::GetValue(nsString &aValue /*nsIDOMNode **aValue*/) +{ + aValue = *mValue; + return NS_OK; +} + +nsresult nsDOMAttribute::SetValue(nsString &aValue /*nsIDOMNode *aValue*/) +{ + delete mValue; + mValue = new nsString(aValue); + return NS_OK; +} + +nsresult nsDOMAttribute::GetSpecified() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDOMAttribute::SetSpecified(PRBool specified) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDOMAttribute::ToString(nsString &aString) +{ + aString = *mName; + aString += " = "; + aString += *mValue; + return NS_OK; +} + + + +// +// nsDOMAttributeList interface +// +nsDOMAttributeList::nsDOMAttributeList(nsIHTMLContent &aContent) : + mContent(aContent) +{ + mRefCnt = 1; + mContent.AddRef(); + mScriptObject = nsnull; +} + +nsDOMAttributeList::~nsDOMAttributeList() +{ + mContent.Release(); +} + +nsresult nsDOMAttributeList::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if (NULL == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + static NS_DEFINE_IID(kIDOMAttributeListIID, NS_IDOMATTRIBUTELIST_IID); + static NS_DEFINE_IID(kIScriptObjectOwnerIID, NS_ISCRIPTOBJECTOWNER_IID); + if (aIID.Equals(kIDOMAttributeListIID)) { + *aInstancePtr = (void*)(nsIDOMAttributeList*)this; + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIScriptObjectOwnerIID)) { + *aInstancePtr = (void*)(nsIScriptObjectOwner*)this; + AddRef(); + return NS_OK; + } + if (aIID.Equals(kISupportsIID)) { + *aInstancePtr = (void*)(nsISupports*)(nsIDOMAttributeList*)this; + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +NS_IMPL_ADDREF(nsDOMAttributeList) + +NS_IMPL_RELEASE(nsDOMAttributeList) + +nsresult nsDOMAttributeList::GetScriptObject(JSContext *aContext, void** aScriptObject) +{ + nsresult res = NS_OK; + if (nsnull == mScriptObject) { + res = NS_NewScriptAttributeList(aContext, this, nsnull, (JSObject**)&mScriptObject); + } + *aScriptObject = mScriptObject; + return res; +} + +nsresult nsDOMAttributeList::ResetScriptObject() +{ + mScriptObject = nsnull; + return NS_OK; +} + +nsresult nsDOMAttributeList::GetAttribute(nsString &aAttrName, nsIDOMAttribute** aAttribute) +{ + nsAutoString value; + mContent.GetAttribute(aAttrName, value); + *aAttribute = new nsDOMAttribute(aAttrName, value); + return NS_OK; +} + +nsresult nsDOMAttributeList::SetAttribute(nsIDOMAttribute *aAttribute) +{ + nsAutoString name, value; + aAttribute->GetName(name); + aAttribute->GetValue(value); + mContent.SetAttribute(name, value); + return NS_OK; +} + +nsresult nsDOMAttributeList::Remove(nsString &attrName, nsIDOMAttribute** aAttribute) +{ + nsAutoString name, upper; + (*aAttribute)->GetName(name); + name.ToUpperCase(upper); + nsIAtom* attr = NS_NewAtom(upper); + mContent.UnsetAttribute(attr); + return NS_OK; +} + +nsresult nsDOMAttributeList::Item(PRUint32 aIndex, nsIDOMAttribute** aAttribute) +{ + nsresult res = NS_ERROR_FAILURE; + nsAutoString name, value; + nsISupportsArray *attributes = nsnull; + if (NS_OK == NS_NewISupportsArray(&attributes)) { + PRInt32 count = mContent.GetAllAttributeNames(attributes); + if (count > 0) { + if ((PRInt32)aIndex < count) { + nsISupports *att = attributes->ElementAt(aIndex); + static NS_DEFINE_IID(kIAtom, NS_IATOM_IID); + nsIAtom *atName = nsnull; + if (nsnull != att && NS_OK == att->QueryInterface(kIAtom, (void**)&atName)) { + atName->ToString(name); + if (eContentAttr_NotThere != mContent.GetAttribute(name, value)) { + *aAttribute = new nsDOMAttribute(name, value); + res = NS_OK; + } + NS_RELEASE(atName); + } + } + } + NS_RELEASE(attributes); + } + + return res; +} + +nsresult nsDOMAttributeList::GetLength(PRUint32 *aLength) +{ + *aLength = mContent.GetAttributeCount(); + return NS_OK; +} + + + diff --git a/mozilla/layout/html/base/src/nsDOMAttributes.h b/mozilla/layout/html/base/src/nsDOMAttributes.h new file mode 100644 index 00000000000..0f2ed5f8cd3 --- /dev/null +++ b/mozilla/layout/html/base/src/nsDOMAttributes.h @@ -0,0 +1,77 @@ +/* -*- 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. + */ + +#ifndef nsDOMAttributes_h__ +#define nsDOMAttributes_h__ + +#include "nsIDOMAttribute.h" +#include "nsIScriptObjectOwner.h" + +class nsIContent; +class nsIHTMLContent; + +class nsDOMAttribute : public nsIDOMAttribute, public nsIScriptObjectOwner { +public: + nsDOMAttribute(nsString &aName, nsString &aValue); + virtual ~nsDOMAttribute(); + + NS_DECL_ISUPPORTS + + virtual nsresult GetScriptObject(JSContext *aContext, void** aScriptObject); + virtual nsresult ResetScriptObject(); + + // nsIDOMAttribute interface + virtual nsresult GetName(nsString &aName); + virtual nsresult GetValue(nsString &aValue /*nsIDOMNode **aValue*/); + virtual nsresult SetValue(nsString &aValue /*nsIDOMNode *aValue*/); + virtual nsresult GetSpecified(); + virtual nsresult SetSpecified(PRBool specified); + virtual nsresult ToString(nsString &aString); + +private: + nsString *mName; + nsString *mValue; + void *mScriptObject; +}; + + +class nsDOMAttributeList : public nsIDOMAttributeList, public nsIScriptObjectOwner { +public: + nsDOMAttributeList(nsIHTMLContent &aContent); + virtual ~nsDOMAttributeList(); + + NS_DECL_ISUPPORTS + + virtual nsresult GetScriptObject(JSContext *aContext, void** aScriptObject); + virtual nsresult ResetScriptObject(); + + // nsIDOMAttributeList interface + virtual nsresult GetAttribute(nsString &aAttrName, nsIDOMAttribute** aAttribute); + virtual nsresult SetAttribute(nsIDOMAttribute *aAttribute); + virtual nsresult Remove(nsString &attrName, nsIDOMAttribute** aAttribute); + virtual nsresult Item(PRUint32 aIndex, nsIDOMAttribute** aAttribute); + virtual nsresult GetLength(PRUint32 *aLength); + +private: + nsIHTMLContent &mContent; + void *mScriptObject; +}; + + +#endif + diff --git a/mozilla/layout/html/base/src/nsDOMIterator.cpp b/mozilla/layout/html/base/src/nsDOMIterator.cpp new file mode 100644 index 00000000000..e1859075358 --- /dev/null +++ b/mozilla/layout/html/base/src/nsDOMIterator.cpp @@ -0,0 +1,176 @@ +/* -*- 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 "nsDOMIterator.h" +#include "nsIDOMNode.h" + +static NS_DEFINE_IID(kIContentIID, NS_ICONTENT_IID); +static NS_DEFINE_IID(kIDOMNodeIID, NS_IDOMNODE_IID); + +nsDOMIterator::nsDOMIterator(nsIContent &aContent) : mContent(aContent) +{ + mRefCnt = 1; + + // keep the content alive so the array of children + // does not go away without "this" to know + mContent.AddRef(); + + mPosition = -1; + mScriptObject = nsnull; +} + +nsDOMIterator::~nsDOMIterator() +{ + mContent.Release(); +} + +nsresult nsDOMIterator::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if (NULL == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + static NS_DEFINE_IID(kIDOMNodeIteratorIID, NS_IDOMNODEITERATOR_IID); + static NS_DEFINE_IID(kIScriptObjectOwnerIID, NS_ISCRIPTOBJECTOWNER_IID); + if (aIID.Equals(kIDOMNodeIteratorIID)) { + *aInstancePtr = (void*)(nsIDOMNodeIterator*)this; + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIScriptObjectOwnerIID)) { + *aInstancePtr = (void*)(nsIScriptObjectOwner*)this; + AddRef(); + return NS_OK; + } + if (aIID.Equals(kISupportsIID)) { + *aInstancePtr = (void*)(nsISupports*)(nsIDOMNodeIterator*)this; + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +NS_IMPL_ADDREF(nsDOMIterator) + +NS_IMPL_RELEASE(nsDOMIterator) + + +nsresult nsDOMIterator::GetScriptObject(JSContext *aContext, void** aScriptObject) +{ + nsresult res = NS_OK; + if (nsnull == mScriptObject) { + res = NS_NewScriptNodeIterator(aContext, this, nsnull, (JSObject**)&mScriptObject); + } + *aScriptObject = mScriptObject; + return res; +} + +nsresult nsDOMIterator::ResetScriptObject() +{ + mScriptObject = nsnull; + return NS_OK; +} + +// nsIDOMIterator interface +nsresult nsDOMIterator::SetFilter(PRInt32 aFilter, PRBool aFilterOn) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsDOMIterator::GetLength(PRUint32 *aLength) +{ + *aLength = mContent.ChildCount(); + return NS_OK; +} + +nsresult nsDOMIterator::GetCurrentNode(nsIDOMNode **aNode) +{ + nsIContent *content = nsnull; + nsresult res = NS_ERROR_FAILURE; + content = mContent.ChildAt(mPosition); + if (nsnull != content) { + res = content->QueryInterface(kIDOMNodeIID, (void**)aNode); + NS_RELEASE(content); + } + + return res; +} + +nsresult nsDOMIterator::GetNextNode(nsIDOMNode **aNode) +{ + nsIContent *content = nsnull; + nsresult res = NS_ERROR_FAILURE; + content = mContent.ChildAt(++mPosition); + if (nsnull != content) { + res = content->QueryInterface(kIDOMNodeIID, (void**)aNode); + NS_RELEASE(content); + } + else mPosition = mContent.ChildCount(); + + return res; +} + +nsresult nsDOMIterator::GetPreviousNode(nsIDOMNode **aNode) +{ + nsIContent *content = nsnull; + nsresult res = NS_ERROR_FAILURE; + content = mContent.ChildAt(--mPosition); + if (nsnull != content) { + res = content->QueryInterface(kIDOMNodeIID, (void**)aNode); + NS_RELEASE(content); + } + else mPosition = -1; + + return res; +} + +nsresult nsDOMIterator::ToFirst(nsIDOMNode **aNode) +{ + nsIContent *content = nsnull; + nsresult res = NS_ERROR_FAILURE; + mPosition = 0; + content = mContent.ChildAt(mPosition); + if (nsnull != content) { + res = content->QueryInterface(kIDOMNodeIID, (void**)aNode); + NS_RELEASE(content); + } + + return res; +} + +nsresult nsDOMIterator::ToLast(nsIDOMNode **aNode) +{ + nsIContent *content = nsnull; + nsresult res = NS_ERROR_FAILURE; + mPosition = mPosition = mContent.ChildCount(); + content = mContent.ChildAt(mPosition); + if (nsnull != content) { + res = content->QueryInterface(kIDOMNodeIID, (void**)aNode); + NS_RELEASE(content); + } + + return res; +} + +nsresult nsDOMIterator::MoveTo(int aNth, nsIDOMNode **aNode) +{ + mPosition = aNth; + return GetCurrentNode(aNode); +} + + diff --git a/mozilla/layout/html/base/src/nsDOMIterator.h b/mozilla/layout/html/base/src/nsDOMIterator.h new file mode 100644 index 00000000000..2f08981ffdd --- /dev/null +++ b/mozilla/layout/html/base/src/nsDOMIterator.h @@ -0,0 +1,54 @@ +/* -*- 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. + */ + +#ifndef nsDOMIterator_h__ +#define nsDOMIterator_h__ + +#include "nsIDOMIterators.h" +#include "nsIContent.h" +#include "nsIScriptObjectOwner.h" + +class nsDOMIterator : public nsIDOMNodeIterator, public nsIScriptObjectOwner { +public: + nsDOMIterator(nsIContent &aContent); + virtual ~nsDOMIterator(); + + NS_DECL_ISUPPORTS + + virtual nsresult GetScriptObject(JSContext *aContext, void** aScriptObject); + virtual nsresult ResetScriptObject(); + + // nsIDOMIterator interface + virtual nsresult SetFilter(PRInt32 aFilter, PRBool aFilterOn); + virtual nsresult GetLength(PRUint32 *aLength); + virtual nsresult GetCurrentNode(nsIDOMNode **aNode); + virtual nsresult GetNextNode(nsIDOMNode **aNode); + virtual nsresult GetPreviousNode(nsIDOMNode **aNode); + virtual nsresult ToFirst(nsIDOMNode **aNode); + virtual nsresult ToLast(nsIDOMNode **aNode); + virtual nsresult MoveTo(int aNth, nsIDOMNode **aNode); + +private: + nsIContent &mContent; + PRInt32 mPosition; + void *mScriptObject; +}; + + +#endif + diff --git a/mozilla/layout/html/base/src/nsGlobalVariables.cpp b/mozilla/layout/html/base/src/nsGlobalVariables.cpp new file mode 100644 index 00000000000..6fb5a24d9c1 --- /dev/null +++ b/mozilla/layout/html/base/src/nsGlobalVariables.cpp @@ -0,0 +1,102 @@ +/* -*- 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 "nsGlobalVariables.h" + +nsGlobalVariables* nsGlobalVariables::gInstance; + +nsGlobalVariables::nsGlobalVariables() +{ + mPresentationContext = nsnull; + mBeveledLines=PR_TRUE; + mBlackLines=PR_FALSE; + mBlackText=PR_FALSE; +} + +nsGlobalVariables::~nsGlobalVariables() +{} + +/** +* +* WARNING: This should only be called when the program exits +* No attemp to release this prior to termination will have +* disastrous consequences. +* +**/ +void nsGlobalVariables::Release() +{ + if (gInstance != nsnull) + delete gInstance; + gInstance = nsnull; +} + +nsGlobalVariables * nsGlobalVariables::Instance() +{ + if (nsnull==gInstance) + gInstance = new nsGlobalVariables(); + return gInstance; +} + +PRBool nsGlobalVariables::GetPrinting(nsIPresContext * aPresentationContext) +{ + return (PRBool) (aPresentationContext == mPresentationContext); +} + +void nsGlobalVariables::SetPrinting(nsIPresContext * aPresentationContext) +{ + mPresentationContext = aPresentationContext; +} + +PRBool nsGlobalVariables::GetBeveledLines() +{ + return mBeveledLines; +} + +void nsGlobalVariables::SetBeveledLines(PRBool aBeveledLines) +{ + mBeveledLines = aBeveledLines; +} + +PRBool nsGlobalVariables::GetBlackLines() +{ + return mBlackLines; +} + +void nsGlobalVariables::SetBlackLines(PRBool aBlackLines) +{ + mBlackLines = aBlackLines; +} + +PRBool nsGlobalVariables::GetBlackText() +{ + return mBlackText; +} + +void nsGlobalVariables::SetBlackText(PRBool aBlackText) +{ + mBlackText = aBlackText; +} + +PRBool nsGlobalVariables::GetBackground() +{ + return mBackground; +} + +void nsGlobalVariables::SetBackground(PRBool aBackground) +{ + mBackground = aBackground; +} diff --git a/mozilla/layout/html/base/src/nsGlobalVariables.h b/mozilla/layout/html/base/src/nsGlobalVariables.h new file mode 100644 index 00000000000..36049f78b2f --- /dev/null +++ b/mozilla/layout/html/base/src/nsGlobalVariables.h @@ -0,0 +1,133 @@ +/* -*- 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. + */ +#ifndef globalvariables_h___ +#define globalvariables_h___ + +#include "nslayout.h" + +// forward declarations +class nsIPresContext; +class nsGlobalVariables; + +/** + * The objective is to emulate the Dogbert page setup control over printing + * behavior. The initial implementation used the style system. However, Kipp + * pointed out that the net result is that exactly one class used it and the + * weight to the system was probably around >2kb for what's really a simple + * PRBool property that only the rendering code uses - can you say bloatware! + * + * Hence, this class. + */ +class nsGlobalVariables +{ +private: + /** The PRBools below are only valid if the rendering presentation context + * is the printing presentation context. + */ + nsIPresContext * mPresentationContext; + + /** mBeveledLines == true means print all HRs as though they have set the + * NOSHADE attribute. + */ + PRBool mBeveledLines; + + /** mBlackLines == true means print all HR and table ruling lines black, + * ignoring whatever color attribute has been set. + */ + PRBool mBlackLines; + + /** mBlackText == true means print all text black, ignoring whatever color + * attribute has been set. + */ + PRBool mBlackText; + + /** mBackground == true means print the background. + */ + PRBool mBackground; + + /** mInstance is the one-and-only instantiation of this class. + * It is accessable only through Instance + */ + static nsGlobalVariables *gInstance; + + /** constructor + */ + nsGlobalVariables(); + +public: + + /** destructor + */ + virtual ~nsGlobalVariables(); + + /** public way to release global instance variables. + * WARNING: This should only be called when the program exits + * No attemp to release this prior to termination will have + * disastrous consequences. + */ + static NS_HTML void Release(); + + /** public accessor. + * This is the ONLY way to get the one-and-only GlobalVariable object. + * I own the storage for the returned pointer, so do not delete it when you're done! + */ + static nsGlobalVariables * Instance(); + + /** + */ + PRBool GetPrinting(nsIPresContext * aPresentationContext); + + /** + */ + void SetPrinting(nsIPresContext * aPresentationContext); + + /** + */ + PRBool GetBeveledLines(); + + /** + */ + void SetBeveledLines(PRBool aBeveledLines); + + /** + */ + PRBool GetBlackLines(); + + /** + */ + void SetBlackLines(PRBool aBlackLines); + + /** + */ + PRBool GetBlackText(); + + /** + */ + void SetBlackText(PRBool aBlackText); + + /** + */ + PRBool GetBackground(); + + /** + */ + void SetBackground(PRBool aBackground); + +}; + +#endif diff --git a/mozilla/layout/html/base/src/nsHRPart.cpp b/mozilla/layout/html/base/src/nsHRPart.cpp new file mode 100644 index 00000000000..ba6ecd4d0c0 --- /dev/null +++ b/mozilla/layout/html/base/src/nsHRPart.cpp @@ -0,0 +1,443 @@ +/* -*- 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 "nsHTMLParts.h" +#include "nsHTMLTagContent.h" +#include "nsLeafFrame.h" +#include "nsIRenderingContext.h" +#include "nsGlobalVariables.h" +#include "nsIStyleContext.h" +#include "nsColor.h" +#include "nsIPresContext.h" +#include "nsIStyleContext.h" +#include "nsHTMLIIDs.h" +#include "nsHTMLAtoms.h" +#include "nsIFontMetrics.h" +#include "nsIHTMLAttributes.h" +#include "nsStyleConsts.h" + +#undef DEBUG_HR_REFCNT + +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); +static NS_DEFINE_IID(kStyleFontSID, NS_STYLEFONT_SID); +static NS_DEFINE_IID(kStyleColorSID, NS_STYLECOLOR_SID); + +// Default alignment value (so we can tell an unset value from a set value) +#define ALIGN_UNSET PRUint8(-1) + +class HRulePart : public nsHTMLTagContent { +public: + HRulePart(nsIAtom* aTag); + +#ifdef DEBUG_HR_REFCNT + virtual nsrefcnt AddRef(void); + virtual nsrefcnt Release(void); +#endif + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void SetAttribute(nsIAtom* aAttribute, const nsString& aValue); + virtual nsContentAttr GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aResult) const; + virtual void UnsetAttribute(nsIAtom* aAttribute); + + PRInt32 mThickness; // in pixels + PRPackedBool mNoShade; + PRUint8 mAlign; + +protected: + virtual ~HRulePart(); + virtual nsContentAttr AttributeToString(nsIAtom* aAttribute, + nsHTMLValue& aValue, + nsString& aResult) const; +}; + +class HRuleFrame : public nsLeafFrame { +public: + HRuleFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + +protected: + virtual ~HRuleFrame(); + + virtual void GetDesiredSize(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize); + + // Weird color computing code stolen from winfe which was stolen + // from the xfe which was written originally by Eric Bina. So there. + static void Get3DColors(nscolor aResult[2], nscolor aColor); + static const int RED_LUMINOSITY; + static const int GREEN_LUMINOSITY; + static const int BLUE_LUMINOSITY; + static const int INTENSITY_FACTOR; + static const int LIGHT_FACTOR; + static const int LUMINOSITY_FACTOR; + static const int MAX_COLOR; + static const int COLOR_DARK_THRESHOLD; + static const int COLOR_LIGHT_THRESHOLD; +}; + +HRuleFrame::HRuleFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsLeafFrame(aContent, aIndexInParent, aParentFrame) +{ +} + +HRuleFrame::~HRuleFrame() +{ +} + +void HRuleFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + float p2t = aPresContext.GetPixelsToTwips(); + nscoord thickness = nscoord(p2t * ((HRulePart*)mContent)->mThickness); + + // Get style data + nsStyleMolecule* mol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + nsStyleColor* color = + (nsStyleColor*)mStyleContext->GetData(kStyleColorSID); + nscoord x0 = mol->borderPadding.left; + nscoord y0 = mol->borderPadding.top; + nscoord width = mRect.width - + (mol->borderPadding.left + mol->borderPadding.right); + nscoord height = mRect.height - + (mol->borderPadding.top + mol->borderPadding.bottom); + + // Center hrule vertically within the available space + y0 += (height - thickness) / 2; + height = thickness; + + // To shade or not to shade, that is the question. Begin by collecting the + // three decision criteria: rendering to the printer or the display, is the + // "Beveled Lines" checkbox set in the page setup dialog, and does the tag + // have the NOSHADE attribute set. + PRBool printing = nsGlobalVariables::Instance()->GetPrinting(&aPresContext); + + PRBool bevel = nsGlobalVariables::Instance()->GetBeveledLines(); + + PRBool noShadeAttribute = PRBool(((HRulePart*)mContent)->mNoShade); + + // Now that we have the data to make the shading criteria, we next + // collect the decision criteria for rending in solid black: + // printing (which we already have) and the "Black Lines" setting in + // the page setup dialog + + PRBool blackLines = nsGlobalVariables::Instance()->GetBlackLines(); + nscolor colors[2]; + // Get the background color that applies to this HR + if (printing && blackLines) + { + colors[0] = NS_RGB(0,0,0); + colors[1] = colors[0]; + } + else + { + // XXX Get correct color by finding the first parent that actually + // specifies a color. + Get3DColors(colors, color->mBackgroundColor); + } + + // Draw a "shadowed" box around the rule area + if (!noShadeAttribute && ((printing && bevel) || !printing)) { + // Lines render inclusively on the both the starting and ending + // coordinate, so reduce the end coordinates by one pixel. + nscoord x1 = nscoord(x0 + width - p2t); + nscoord y1 = nscoord(y0 + height - p2t); + + // Draw top and left lines + aRenderingContext.SetColor (colors[0]); + aRenderingContext.DrawLine (x0, y1, x0, y0); + aRenderingContext.DrawLine (x0, y0, x1, y0); + + // Draw bottom and right lines + aRenderingContext.SetColor (colors[1]); + aRenderingContext.DrawLine (x1, y0, x1, y1); + aRenderingContext.DrawLine (x1, y1, x0, y1); + } else { + // When a rule is not shaded, then we use a uniform color and + // draw half-circles on the end points. + aRenderingContext.SetColor (colors[0]); + float t2p = 1.0f / p2t; + nscoord diameter = height; + if ((diameter > width) || (diameter < nscoord(p2t * 3))) { + // The half-circles on the ends of the rule aren't going to + // look right so don't bother drawing them. + aRenderingContext.FillRect(x0, y0, width, height); + } else { + nscoord pix = NS_POINTS_TO_TWIPS_INT(1); + aRenderingContext.FillArc(x0, y0, diameter, diameter, 90.0f, 180.0f); + aRenderingContext.FillArc(x0 + width - diameter, y0, + diameter, diameter, 270.0f, 180.0f); + aRenderingContext.FillRect(x0 + diameter/2, y0, + width - diameter, height); + } + } +} + +// Weird color computing code stolen from winfe which was stolen +// from the xfe which was written originally by Eric Bina. So there. + +const int HRuleFrame::RED_LUMINOSITY = 30; +const int HRuleFrame::GREEN_LUMINOSITY = 59; +const int HRuleFrame::BLUE_LUMINOSITY = 11; +const int HRuleFrame::INTENSITY_FACTOR = 25; +const int HRuleFrame::LIGHT_FACTOR = 0; +const int HRuleFrame::LUMINOSITY_FACTOR = 75; +const int HRuleFrame::MAX_COLOR = 255; +const int HRuleFrame::COLOR_DARK_THRESHOLD = 51; +const int HRuleFrame::COLOR_LIGHT_THRESHOLD = 204; + + +void HRuleFrame::Get3DColors(nscolor aResult[2], nscolor aColor) +{ + int rb = NS_GET_R(aColor); + int gb = NS_GET_G(aColor); + int bb = NS_GET_B(aColor); + int intensity = (rb + gb + bb) / 3; + int luminosity = + ((RED_LUMINOSITY * rb) / 100) + + ((GREEN_LUMINOSITY * gb) / 100) + + ((BLUE_LUMINOSITY * bb) / 100); + int brightness = ((intensity * INTENSITY_FACTOR) + + (luminosity * LUMINOSITY_FACTOR)) / 100; + int f0, f1; + if (brightness < COLOR_DARK_THRESHOLD) { + f0 = 30; + f1 = 50; + } else if (brightness > COLOR_LIGHT_THRESHOLD) { + f0 = 45; + f1 = 50; + } else { + f0 = 30 + (brightness * (45 - 30) / MAX_COLOR); + f1 = f0; + } + int r = rb - (f0 * rb / 100); + int g = gb - (f0 * gb / 100); + int b = bb - (f0 * bb / 100); + aResult[0] = NS_RGB(r, g, b); + r = rb + (f1 * (MAX_COLOR - rb) / 100); + if (r > 255) r = 255; + g = gb + (f1 * (MAX_COLOR - gb) / 100); + if (g > 255) g = 255; + b = bb + (f1 * (MAX_COLOR - bb) / 100); + if (b > 255) b = 255; + aResult[1] = NS_RGB(r, g, b); +} + +void HRuleFrame::GetDesiredSize(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize) +{ + // Get style data + nsStyleFont* font = + (nsStyleFont*)mStyleContext->GetData(kStyleFontSID); + + if (aMaxSize.width == NS_UNCONSTRAINEDSIZE) { + aDesiredSize.width = 1; + } else { + // XXX look at width property; use percentage, etc. + // XXX apply centering using our align property + aDesiredSize.width = aMaxSize.width; + } + + // Get the thickness of the rule (this is not css's height property) + float p2t = aPresContext->GetPixelsToTwips(); + nscoord thickness = nscoord(p2t * ((HRulePart*)mContent)->mThickness); + + // Compute height of "line" that hrule will layout within + nscoord lineHeight = thickness + nscoord(p2t * 2); + nsIFontMetrics* fm = aPresContext->GetMetricsFor(font->mFont); + nscoord defaultLineHeight = fm->GetHeight(); + NS_RELEASE(fm); + if (lineHeight < defaultLineHeight) { + lineHeight = defaultLineHeight; + } + + aDesiredSize.height = lineHeight; + aDesiredSize.ascent = aDesiredSize.height; + aDesiredSize.descent = 0; +} + +//---------------------------------------------------------------------- + +HRulePart::HRulePart(nsIAtom* aTag) + : nsHTMLTagContent(aTag) +{ + mAlign = ALIGN_UNSET; +} + +HRulePart::~HRulePart() +{ +} + +#ifdef DEBUG_HR_REFCNT +nsrefcnt HRulePart::AddRef(void) +{ + return ++mRefCnt; +} + +nsrefcnt HRulePart::Release(void) +{ + NS_PRECONDITION(mRefCnt != 0, "too many release's"); + if (--mRefCnt == 0) { + if (mInHeap) { + delete this; + } + } + return mRefCnt; +} +#endif + +//---------------------------------------------------------------------- +// Attributes + +static nsHTMLTagContent::EnumTable kAlignTable[] = { + { "left", NS_STYLE_TEXT_ALIGN_LEFT }, + { "right", NS_STYLE_TEXT_ALIGN_RIGHT }, + { "center", NS_STYLE_TEXT_ALIGN_CENTER }, + { 0 } +}; + +void HRulePart::SetAttribute(nsIAtom* aAttribute, const nsString& aValue) +{ + if (aAttribute == nsHTMLAtoms::width) { + nsHTMLValue val; + ParseValueOrPercent(aValue, val); + nsHTMLTagContent::SetAttribute(aAttribute, val); + return; + } + if (aAttribute == nsHTMLAtoms::size) { + nsHTMLValue val; + ParseValue(aValue, 1, 100, val); + mThickness = val.GetIntValue(); + return; + } + if (aAttribute == nsHTMLAtoms::noshade) { + mNoShade = PR_TRUE; + return; + } + if (aAttribute == nsHTMLAtoms::align) { + nsHTMLValue val; + if (ParseEnumValue(aValue, kAlignTable, val)) { + mAlign = val.GetIntValue(); + } else { + mAlign = ALIGN_UNSET; + } + return; + } + + // Use default attribute catching code + nsHTMLTagContent::SetAttribute(aAttribute, aValue); +} + +nsContentAttr HRulePart::GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aResult) const +{ + nsContentAttr ca = eContentAttr_NotThere; + if (aAttribute == nsHTMLAtoms::size) { + aResult.Reset(); + if (0 != mThickness) { + aResult.Set(mThickness, eHTMLUnit_Absolute); + ca = eContentAttr_HasValue; + } + } + else if (aAttribute == nsHTMLAtoms::noshade) { + aResult.Reset(); + if (mNoShade) { + ca = eContentAttr_HasValue; + } + } + else if (aAttribute == nsHTMLAtoms::align) { + aResult.Reset(); + if (ALIGN_UNSET != mAlign) { + aResult.Set(mAlign, eHTMLUnit_Enumerated); + ca = eContentAttr_HasValue; + } + } + else { + ca = nsHTMLTagContent::GetAttribute(aAttribute, aResult); + } + return ca; +} + +void HRulePart::UnsetAttribute(nsIAtom* aAttribute) +{ + if (aAttribute == nsHTMLAtoms::noshade) { + mNoShade = PR_FALSE; + } + else if (aAttribute == nsHTMLAtoms::size) { + mThickness = 0; + } + else if (aAttribute == nsHTMLAtoms::align) { + mAlign = ALIGN_UNSET; + } + else { + // Use default attribute catching code + nsHTMLTagContent::UnsetAttribute(aAttribute); + } +} + +nsContentAttr HRulePart::AttributeToString(nsIAtom* aAttribute, + nsHTMLValue& aValue, + nsString& aResult) const +{ + nsContentAttr ca = eContentAttr_NotThere; + if (aAttribute == nsHTMLAtoms::align) { + if ((eHTMLUnit_Enumerated == aValue.GetUnit()) && + (ALIGN_UNSET != aValue.GetIntValue())) { + EnumValueToString(aValue, kAlignTable, aResult); + ca = eContentAttr_HasValue; + } + } + return ca; +} + +//---------------------------------------------------------------------- + +nsIFrame* HRulePart::CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + nsIFrame* rv = new HRuleFrame(this, aIndexInParent, aParentFrame); + return rv; +} + +nsresult +NS_NewHRulePart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIHTMLContent* body = new HRulePart(aTag); + if (nsnull == body) { + return NS_ERROR_OUT_OF_MEMORY; + } + return body->QueryInterface(kIHTMLContentIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/layout/html/base/src/nsHTMLAtoms.cpp b/mozilla/layout/html/base/src/nsHTMLAtoms.cpp new file mode 100644 index 00000000000..377ed58e605 --- /dev/null +++ b/mozilla/layout/html/base/src/nsHTMLAtoms.cpp @@ -0,0 +1,367 @@ +/* -*- 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 "nsHTMLAtoms.h" + +nsIAtom* nsHTMLAtoms::a; +nsIAtom* nsHTMLAtoms::above; +nsIAtom* nsHTMLAtoms::action; +nsIAtom* nsHTMLAtoms::align; +nsIAtom* nsHTMLAtoms::alink; +nsIAtom* nsHTMLAtoms::alt; +nsIAtom* nsHTMLAtoms::archive; +nsIAtom* nsHTMLAtoms::background; +nsIAtom* nsHTMLAtoms::below; +nsIAtom* nsHTMLAtoms::bgcolor; +nsIAtom* nsHTMLAtoms::body; +nsIAtom* nsHTMLAtoms::border; +nsIAtom* nsHTMLAtoms::bordercolor; +nsIAtom* nsHTMLAtoms::bottompadding; +nsIAtom* nsHTMLAtoms::br; +nsIAtom* nsHTMLAtoms::cellpadding; +nsIAtom* nsHTMLAtoms::cellspacing; +nsIAtom* nsHTMLAtoms::checked; +nsIAtom* nsHTMLAtoms::kClass; +nsIAtom* nsHTMLAtoms::classid; +nsIAtom* nsHTMLAtoms::clear; +nsIAtom* nsHTMLAtoms::clip; +nsIAtom* nsHTMLAtoms::code; +nsIAtom* nsHTMLAtoms::codebase; +nsIAtom* nsHTMLAtoms::color; +nsIAtom* nsHTMLAtoms::cols; +nsIAtom* nsHTMLAtoms::colspan; +nsIAtom* nsHTMLAtoms::compact; +nsIAtom* nsHTMLAtoms::coords; +nsIAtom* nsHTMLAtoms::data; +nsIAtom* nsHTMLAtoms::dir; +nsIAtom* nsHTMLAtoms::div; +nsIAtom* nsHTMLAtoms::dl; +nsIAtom* nsHTMLAtoms::encoding; +nsIAtom* nsHTMLAtoms::face; +nsIAtom* nsHTMLAtoms::font; +nsIAtom* nsHTMLAtoms::fontWeight; +nsIAtom* nsHTMLAtoms::frameborder; +nsIAtom* nsHTMLAtoms::gutter; +nsIAtom* nsHTMLAtoms::h1; +nsIAtom* nsHTMLAtoms::h2; +nsIAtom* nsHTMLAtoms::h3; +nsIAtom* nsHTMLAtoms::h4; +nsIAtom* nsHTMLAtoms::h5; +nsIAtom* nsHTMLAtoms::h6; +nsIAtom* nsHTMLAtoms::height; +nsIAtom* nsHTMLAtoms::hidden; +nsIAtom* nsHTMLAtoms::href; +nsIAtom* nsHTMLAtoms::hspace; +nsIAtom* nsHTMLAtoms::httpEquiv; +nsIAtom* nsHTMLAtoms::id; +nsIAtom* nsHTMLAtoms::ismap; +nsIAtom* nsHTMLAtoms::language; +nsIAtom* nsHTMLAtoms::li; +nsIAtom* nsHTMLAtoms::link; +nsIAtom* nsHTMLAtoms::left; +nsIAtom* nsHTMLAtoms::leftpadding; +nsIAtom* nsHTMLAtoms::lowsrc; +nsIAtom* nsHTMLAtoms::marginheight; +nsIAtom* nsHTMLAtoms::marginwidth; +nsIAtom* nsHTMLAtoms::maxlength; +nsIAtom* nsHTMLAtoms::mayscript; +nsIAtom* nsHTMLAtoms::menu; +nsIAtom* nsHTMLAtoms::method; +nsIAtom* nsHTMLAtoms::multicol; +nsIAtom* nsHTMLAtoms::multiple; +nsIAtom* nsHTMLAtoms::name; +nsIAtom* nsHTMLAtoms::noresize; +nsIAtom* nsHTMLAtoms::noshade; +nsIAtom* nsHTMLAtoms::nowrap; +nsIAtom* nsHTMLAtoms::ol; +nsIAtom* nsHTMLAtoms::onblur; +nsIAtom* nsHTMLAtoms::onfocus; +nsIAtom* nsHTMLAtoms::onload; +nsIAtom* nsHTMLAtoms::onunload; +nsIAtom* nsHTMLAtoms::overflow; +nsIAtom* nsHTMLAtoms::p; +nsIAtom* nsHTMLAtoms::pagex; +nsIAtom* nsHTMLAtoms::pagey; +nsIAtom* nsHTMLAtoms::pointSize; +nsIAtom* nsHTMLAtoms::pre; +nsIAtom* nsHTMLAtoms::prompt; +nsIAtom* nsHTMLAtoms::rel; +nsIAtom* nsHTMLAtoms::rightpadding; +nsIAtom* nsHTMLAtoms::rows; +nsIAtom* nsHTMLAtoms::rowspan; +nsIAtom* nsHTMLAtoms::scrolling; +nsIAtom* nsHTMLAtoms::selected; +nsIAtom* nsHTMLAtoms::shape; +nsIAtom* nsHTMLAtoms::size; +nsIAtom* nsHTMLAtoms::src; +nsIAtom* nsHTMLAtoms::start; +nsIAtom* nsHTMLAtoms::suppress; +nsIAtom* nsHTMLAtoms::tabstop; +nsIAtom* nsHTMLAtoms::target; +nsIAtom* nsHTMLAtoms::text; +nsIAtom* nsHTMLAtoms::top; +nsIAtom* nsHTMLAtoms::toppadding; +nsIAtom* nsHTMLAtoms::type; +nsIAtom* nsHTMLAtoms::ul; +nsIAtom* nsHTMLAtoms::usemap; +nsIAtom* nsHTMLAtoms::valign; +nsIAtom* nsHTMLAtoms::value; +nsIAtom* nsHTMLAtoms::variable; +nsIAtom* nsHTMLAtoms::visibility; +nsIAtom* nsHTMLAtoms::vlink; +nsIAtom* nsHTMLAtoms::vspace; +nsIAtom* nsHTMLAtoms::width; +nsIAtom* nsHTMLAtoms::wrap; +nsIAtom* nsHTMLAtoms::zindex; + + +static nsrefcnt gRefCnt; + +void nsHTMLAtoms::AddrefAtoms() +{ + if (0 == gRefCnt) { + a = NS_NewAtom("A"); + above = NS_NewAtom("ABOVE"); + action = NS_NewAtom("ACTION"); + align = NS_NewAtom("ALIGN"); + alink = NS_NewAtom("ALINK"); + alt = NS_NewAtom("ALT"); + archive = NS_NewAtom("ARCHIVE"); + background = NS_NewAtom("BACKGROUND"); + below = NS_NewAtom("BELOW"); + bgcolor = NS_NewAtom("BGCOLOR"); + body = NS_NewAtom("BODY"); + border = NS_NewAtom("BORDER"); + bordercolor = NS_NewAtom("BORDERCOLOR"); + bottompadding = NS_NewAtom("BOTTOMPADDING"); + br = NS_NewAtom("BR"); + cellpadding = NS_NewAtom("CELLPADDING"); + cellspacing = NS_NewAtom("CELLSPACING"); + checked = NS_NewAtom("CHECKED"); + kClass = NS_NewAtom("CLASS"); + classid = NS_NewAtom("CLASSID"); + clear = NS_NewAtom("CLEAR"); + clip = NS_NewAtom("CLIP"); + code = NS_NewAtom("CODE"); + codebase = NS_NewAtom("CODEBASE"); + color = NS_NewAtom("COLOR"); + cols = NS_NewAtom("COLS"); + colspan = NS_NewAtom("COLSPAN"); + compact = NS_NewAtom("COMPACT"); + coords = NS_NewAtom("COORDS"); + dir = NS_NewAtom("DIR"); + div = NS_NewAtom("DIV"); + dl = NS_NewAtom("DL"); + data = NS_NewAtom("DATA"); + encoding = NS_NewAtom("ENCODING"); + face = NS_NewAtom("FACE"); + font = NS_NewAtom("FONT"); + fontWeight = NS_NewAtom("FONT-WEIGHT"); + frameborder = NS_NewAtom("FRAMEBORDER"); + gutter = NS_NewAtom("GUTTER"); + h1 = NS_NewAtom("H1"); + h2 = NS_NewAtom("H2"); + h3 = NS_NewAtom("H3"); + h4 = NS_NewAtom("H4"); + h5 = NS_NewAtom("H5"); + h6 = NS_NewAtom("H6"); + height = NS_NewAtom("HEIGHT"); + hidden = NS_NewAtom("HIDDEN"); + href = NS_NewAtom("HREF"); + hspace = NS_NewAtom("HSPACE"); + httpEquiv = NS_NewAtom("HTTP-EQUIV"); + id = NS_NewAtom("ID"); + ismap = NS_NewAtom("ISMAP"); + language = NS_NewAtom("LANGUAGE"); + li = NS_NewAtom("LI"); + link = NS_NewAtom("LINK"); + left = NS_NewAtom("LEFT"); + leftpadding = NS_NewAtom("LEFTPADDING"); + lowsrc = NS_NewAtom("LOWSRC"); + marginheight = NS_NewAtom("MARGINHEIGHT"); + marginwidth = NS_NewAtom("MARGINWIDTH"); + maxlength = NS_NewAtom("MAXLENGTH"); + mayscript = NS_NewAtom("MAYSCRIPT"); + menu = NS_NewAtom("MENU"); + method = NS_NewAtom("METHOD"); + multicol = NS_NewAtom("MULTICOL"); + multiple = NS_NewAtom("MULTIPLE"); + name = NS_NewAtom("NAME"); + noresize = NS_NewAtom("NORESIZE"); + noshade = NS_NewAtom("NOSHADE"); + nowrap = NS_NewAtom("NOWRAP"); + ol = NS_NewAtom("OL"); + onblur = NS_NewAtom("ONBLUR"); + onfocus = NS_NewAtom("ONFOCUS"); + onload = NS_NewAtom("ONLOAD"); + onunload = NS_NewAtom("ONUNLOAD"); + overflow = NS_NewAtom("OVERFLOW"); + p = NS_NewAtom("P"); + pagex = NS_NewAtom("PAGEX"); + pagey = NS_NewAtom("PAGEY"); + pointSize = NS_NewAtom("POINT-SIZE"); + pre = NS_NewAtom("PRE"); + prompt = NS_NewAtom("PROMPT"); + rel = NS_NewAtom("REL"); + rightpadding = NS_NewAtom("RIGHTPADDING"); + rows = NS_NewAtom("ROWS"); + rowspan = NS_NewAtom("ROWSPAN"); + scrolling = NS_NewAtom("SCROLLING"); + selected = NS_NewAtom("SELECTED"); + shape = NS_NewAtom("SHAPE"); + size = NS_NewAtom("SIZE"); + src = NS_NewAtom("SRC"); + start = NS_NewAtom("START"); + suppress = NS_NewAtom("SUPPRESS"); + tabstop = NS_NewAtom("TABSTOP"); + target = NS_NewAtom("TARGET"); + text = NS_NewAtom("TEXT"); + top = NS_NewAtom("TOP"); + toppadding = NS_NewAtom("TOPPADDING"); + type = NS_NewAtom("TYPE"); + ul = NS_NewAtom("UL"); + usemap = NS_NewAtom("USEMAP"); + valign = NS_NewAtom("VALIGN"); + value = NS_NewAtom("VALUE"); + variable = NS_NewAtom("VARIABLE"); + visibility = NS_NewAtom("VISIBILITY"); + vlink = NS_NewAtom("VLINK"); + vspace = NS_NewAtom("VSPACE"); + width = NS_NewAtom("WIDTH"); + wrap = NS_NewAtom("WRAP"); + zindex = NS_NewAtom("ZINDEX"); + } + ++gRefCnt; +} + +void nsHTMLAtoms::ReleaseAtoms() +{ + NS_PRECONDITION(gRefCnt != 0, "bad release atoms"); + if (--gRefCnt == 0) { + NS_RELEASE(a); + NS_RELEASE(above); + NS_RELEASE(action); + NS_RELEASE(align); + NS_RELEASE(alink); + NS_RELEASE(alt); + NS_RELEASE(archive); + NS_RELEASE(background); + NS_RELEASE(below); + NS_RELEASE(bgcolor); + NS_RELEASE(body); + NS_RELEASE(border); + NS_RELEASE(bordercolor); + NS_RELEASE(bottompadding); + NS_RELEASE(br); + NS_RELEASE(cellpadding); + NS_RELEASE(cellspacing); + NS_RELEASE(checked); + NS_RELEASE(kClass); + NS_RELEASE(classid); + NS_RELEASE(clear); + NS_RELEASE(clip); + NS_RELEASE(code); + NS_RELEASE(codebase); + NS_RELEASE(color); + NS_RELEASE(cols); + NS_RELEASE(colspan); + NS_RELEASE(compact); + NS_RELEASE(coords); + NS_RELEASE(dir); + NS_RELEASE(div); + NS_RELEASE(dl); + NS_RELEASE(data); + NS_RELEASE(encoding); + NS_RELEASE(face); + NS_RELEASE(font); + NS_RELEASE(fontWeight); + NS_RELEASE(frameborder); + NS_RELEASE(gutter); + NS_RELEASE(h1); + NS_RELEASE(h2); + NS_RELEASE(h3); + NS_RELEASE(h4); + NS_RELEASE(h5); + NS_RELEASE(h6); + NS_RELEASE(height); + NS_RELEASE(hidden); + NS_RELEASE(href); + NS_RELEASE(hspace); + NS_RELEASE(httpEquiv); + NS_RELEASE(id); + NS_RELEASE(ismap); + NS_RELEASE(language); + NS_RELEASE(li); + NS_RELEASE(link); + NS_RELEASE(left); + NS_RELEASE(leftpadding); + NS_RELEASE(lowsrc); + NS_RELEASE(marginheight); + NS_RELEASE(marginwidth); + NS_RELEASE(maxlength); + NS_RELEASE(mayscript); + NS_RELEASE(menu); + NS_RELEASE(method); + NS_RELEASE(multicol); + NS_RELEASE(multiple); + NS_RELEASE(name); + NS_RELEASE(noresize); + NS_RELEASE(noshade); + NS_RELEASE(nowrap); + NS_RELEASE(ol); + NS_RELEASE(onblur); + NS_RELEASE(onfocus); + NS_RELEASE(onload); + NS_RELEASE(onunload); + NS_RELEASE(overflow); + NS_RELEASE(p); + NS_RELEASE(pagex); + NS_RELEASE(pagey); + NS_RELEASE(pointSize); + NS_RELEASE(pre); + NS_RELEASE(prompt); + NS_RELEASE(rel); + NS_RELEASE(rightpadding); + NS_RELEASE(rows); + NS_RELEASE(rowspan); + NS_RELEASE(scrolling); + NS_RELEASE(selected); + NS_RELEASE(shape); + NS_RELEASE(size); + NS_RELEASE(src); + NS_RELEASE(start); + NS_RELEASE(suppress); + NS_RELEASE(tabstop); + NS_RELEASE(target); + NS_RELEASE(text); + NS_RELEASE(top); + NS_RELEASE(toppadding); + NS_RELEASE(type); + NS_RELEASE(ul); + NS_RELEASE(usemap); + NS_RELEASE(valign); + NS_RELEASE(value); + NS_RELEASE(variable); + NS_RELEASE(visibility); + NS_RELEASE(vlink); + NS_RELEASE(vspace); + NS_RELEASE(width); + NS_RELEASE(wrap); + NS_RELEASE(zindex); + } +} + diff --git a/mozilla/layout/html/base/src/nsHTMLAtoms.h b/mozilla/layout/html/base/src/nsHTMLAtoms.h new file mode 100644 index 00000000000..0f1eb0a8df1 --- /dev/null +++ b/mozilla/layout/html/base/src/nsHTMLAtoms.h @@ -0,0 +1,168 @@ +/* -*- 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. + */ +#ifndef nsHTMLAtoms_h___ +#define nsHTMLAtoms_h___ + +#include "nsIAtom.h" + +/** + * This class wraps up the creation (and destruction) of the standard + * set of html atoms used during normal html handling. This objects + * are created when the first html content object is created and they + * are destroyed when the last html content object is destroyed. + */ +class nsHTMLAtoms { +public: + + static void AddrefAtoms(); + static void ReleaseAtoms(); + + // Alphabetical list of html attribute atoms + static nsIAtom* a; + static nsIAtom* above; + static nsIAtom* action; + static nsIAtom* align; + static nsIAtom* alink; + static nsIAtom* alt; + static nsIAtom* archive; + + static nsIAtom* background; + static nsIAtom* below; + static nsIAtom* bgcolor; + static nsIAtom* body; + static nsIAtom* border; + static nsIAtom* bordercolor; + static nsIAtom* bottompadding; + static nsIAtom* br; + + static nsIAtom* cellpadding; + static nsIAtom* cellspacing; + static nsIAtom* checked; + static nsIAtom* kClass; + static nsIAtom* classid; + static nsIAtom* clear; + static nsIAtom* clip; + static nsIAtom* code; + static nsIAtom* codebase; + static nsIAtom* color; + static nsIAtom* cols; + static nsIAtom* colspan; + static nsIAtom* compact; + static nsIAtom* coords; + + static nsIAtom* data; + static nsIAtom* dir; + static nsIAtom* div; + static nsIAtom* dl; + + static nsIAtom* encoding; + + static nsIAtom* face; + static nsIAtom* font; + static nsIAtom* fontWeight; + static nsIAtom* frameborder; + + static nsIAtom* gutter; + + static nsIAtom* h1; + static nsIAtom* h2; + static nsIAtom* h3; + static nsIAtom* h4; + static nsIAtom* h5; + static nsIAtom* h6; + static nsIAtom* height; + static nsIAtom* hidden; + static nsIAtom* href; + static nsIAtom* hspace; + static nsIAtom* httpEquiv; + + static nsIAtom* id; + static nsIAtom* ismap; + + static nsIAtom* language; + static nsIAtom* li; + static nsIAtom* link; + static nsIAtom* left; + static nsIAtom* leftpadding; + static nsIAtom* lowsrc; + + static nsIAtom* marginheight; + static nsIAtom* marginwidth; + static nsIAtom* maxlength; + static nsIAtom* mayscript; + static nsIAtom* menu; + static nsIAtom* method; + static nsIAtom* multicol; + static nsIAtom* multiple; + + static nsIAtom* name; + static nsIAtom* noresize; + static nsIAtom* noshade; + static nsIAtom* nowrap; + + static nsIAtom* ol; + static nsIAtom* onblur; + static nsIAtom* onfocus; + static nsIAtom* onload; + static nsIAtom* onunload; + static nsIAtom* overflow; + + static nsIAtom* p; + static nsIAtom* pagex; + static nsIAtom* pagey; + static nsIAtom* pointSize; + static nsIAtom* pre; + static nsIAtom* prompt; + + static nsIAtom* rel; + static nsIAtom* rightpadding; + static nsIAtom* rows; + static nsIAtom* rowspan; + + static nsIAtom* scrolling; + static nsIAtom* selected; + static nsIAtom* shape; + static nsIAtom* size; + static nsIAtom* src; + static nsIAtom* start; + static nsIAtom* suppress; + + static nsIAtom* tabstop; + static nsIAtom* target; + static nsIAtom* text; + static nsIAtom* top; + static nsIAtom* toppadding; + static nsIAtom* type; + + static nsIAtom* ul; + static nsIAtom* usemap; + + static nsIAtom* valign; + static nsIAtom* value; + static nsIAtom* variable; + static nsIAtom* visibility; + static nsIAtom* vlink; + static nsIAtom* vspace; + + static nsIAtom* width; + static nsIAtom* wrap; + + static nsIAtom* zindex; +}; + +#endif /* nsHTMLAtoms_h___ */ diff --git a/mozilla/layout/html/base/src/nsHTMLContainer.cpp b/mozilla/layout/html/base/src/nsHTMLContainer.cpp new file mode 100644 index 00000000000..eb2ac7904c6 --- /dev/null +++ b/mozilla/layout/html/base/src/nsHTMLContainer.cpp @@ -0,0 +1,848 @@ +/* -*- 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 "nsHTMLParts.h" +#include "nsHTMLContainer.h" +#include "nsIDocument.h" +#include "nsIAtom.h" +#include "nsIArena.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsBlockFrame.h" +#include "nsInlineFrame.h" +#include "nsListItemFrame.h" +#include "nsIPresContext.h" +#include "nsHTMLIIDs.h" +#include "nsHTMLAtoms.h" +#include "nsIHTMLAttributes.h" +#include "nsDOMIterator.h" +#include "nsUnitConversion.h" +#include "nsIURL.h" +#include "prprf.h" + +static NS_DEFINE_IID(kStyleFontSID, NS_STYLEFONT_SID); +static NS_DEFINE_IID(kStyleColorSID, NS_STYLECOLOR_SID); +static NS_DEFINE_IID(kStyleListSID, NS_STYLELIST_SID); + +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); + +nsresult +NS_NewHTMLContainer(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag) +{ + nsHTMLContainer* it = new nsHTMLContainer(aTag); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIHTMLContentIID, (void **) aInstancePtrResult); +} + +nsresult +NS_NewHTMLContainer(nsIHTMLContent** aInstancePtrResult, + nsIArena* aArena, nsIAtom* aTag) +{ + nsHTMLContainer* it = new(aArena) nsHTMLContainer(aTag); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIHTMLContentIID, (void **) aInstancePtrResult); +} + +nsHTMLContainer::nsHTMLContainer() +{ +} + +nsHTMLContainer::nsHTMLContainer(nsIAtom* aTag) + : nsHTMLTagContent(aTag) +{ +} + +nsHTMLContainer::~nsHTMLContainer() +{ + PRInt32 n = mChildren.Count(); + for (PRInt32 i = 0; i < n; i++) { + nsIContent* kid = (nsIContent*) mChildren.ElementAt(i); + NS_RELEASE(kid); + } +} + +PRBool nsHTMLContainer::CanContainChildren() const +{ + return PR_TRUE; +} + +PRInt32 nsHTMLContainer::ChildCount() const +{ + return mChildren.Count(); +} + +nsIContent* nsHTMLContainer::ChildAt(PRInt32 aIndex) const +{ + nsIContent *child = (nsIContent*) mChildren.ElementAt(aIndex); + if (nsnull != child) { + NS_ADDREF(child); + } + return child; +} + +PRInt32 nsHTMLContainer::IndexOf(nsIContent* aPossibleChild) const +{ + NS_PRECONDITION(nsnull != aPossibleChild, "null ptr"); + return mChildren.IndexOf(aPossibleChild); +} + +PRBool nsHTMLContainer::InsertChildAt(nsIContent* aKid, PRInt32 aIndex) +{ + NS_PRECONDITION(nsnull != aKid, "null ptr"); + PRBool rv = mChildren.InsertElementAt(aKid, aIndex); + if (rv) { + NS_ADDREF(aKid); + aKid->SetParent(this); + nsIDocument* doc = mDocument; + if (nsnull != doc) { + aKid->SetDocument(doc); + doc->ContentInserted(this, aKid, aIndex); + } + } + return rv; +} + +PRBool nsHTMLContainer::ReplaceChildAt(nsIContent* aKid, PRInt32 aIndex) +{ + NS_PRECONDITION(nsnull != aKid, "null ptr"); + nsIContent* oldKid = (nsIContent*) mChildren.ElementAt(aIndex); + PRBool rv = mChildren.ReplaceElementAt(aKid, aIndex); + if (rv) { + NS_ADDREF(aKid); + aKid->SetParent(this); + nsIDocument* doc = mDocument; + if (nsnull != doc) { + aKid->SetDocument(doc); + doc->ContentReplaced(this, oldKid, aKid, aIndex); + } + oldKid->SetDocument(nsnull); + oldKid->SetParent(nsnull); + NS_RELEASE(oldKid); + } + return rv; +} + +PRBool nsHTMLContainer::AppendChild(nsIContent* aKid) +{ + NS_PRECONDITION(nsnull != aKid, "null ptr"); + PRBool rv = mChildren.AppendElement(aKid); + if (rv) { + NS_ADDREF(aKid); + aKid->SetParent(this); + nsIDocument* doc = mDocument; + if (nsnull != doc) { + aKid->SetDocument(doc); + doc->ContentAppended(this); + } + } + return rv; +} + +PRBool nsHTMLContainer::RemoveChildAt(PRInt32 aIndex) +{ + nsIContent* oldKid = (nsIContent*) mChildren.ElementAt(aIndex); + if (nsnull != oldKid ) { + nsIDocument* doc = mDocument; + if (nsnull != doc) { + doc->ContentWillBeRemoved(this, oldKid, aIndex); + } + PRBool rv = mChildren.RemoveElementAt(aIndex); + if (nsnull != doc) { + doc->ContentHasBeenRemoved(this, oldKid, aIndex); + } + oldKid->SetDocument(nsnull); + oldKid->SetParent(nsnull); + NS_RELEASE(oldKid); + return rv; + } + return PR_FALSE; +} + +void nsHTMLContainer::Compact() +{ + //XXX I'll turn this on in a bit... mChildren.Compact(); +} + +nsIFrame* nsHTMLContainer::CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + // Resolve style for the piece of content + nsIStyleContext* styleContext = + aPresContext->ResolveStyleContextFor(this, aParentFrame); + nsStyleMolecule* mol = + (nsStyleMolecule*)styleContext->GetData(kStyleMoleculeSID); + + // Use style to choose what kind of frame to create + nsIFrame* rv; + nsresult fr; + switch (mol->display) { + case NS_STYLE_DISPLAY_BLOCK: + fr = nsBlockFrame::NewFrame(&rv, this, aIndexInParent, aParentFrame); + break; + case NS_STYLE_DISPLAY_INLINE: + fr = nsInlineFrame::NewFrame(&rv, this, aIndexInParent, aParentFrame); + break; + case NS_STYLE_DISPLAY_LIST_ITEM: + fr = nsListItemFrame::NewFrame(&rv, this, aIndexInParent, aParentFrame); + break; + default: + // Create an empty frame for holding content that is not being + // reflowed. + fr = nsFrame::NewFrame(&rv, this, aIndexInParent, aParentFrame); + break; + } + + rv->SetStyleContext(styleContext); + NS_RELEASE(styleContext); + return rv; +} + +//---------------------------------------------------------------------- + +static nsHTMLTagContent::EnumTable kListTypeTable[] = { + { "none", NS_STYLE_LIST_STYLE_NONE }, + { "disc", NS_STYLE_LIST_STYLE_DISC }, + { "circle", NS_STYLE_LIST_STYLE_CIRCLE }, + { "round", NS_STYLE_LIST_STYLE_CIRCLE }, + { "square", NS_STYLE_LIST_STYLE_SQUARE }, + { "decimal", NS_STYLE_LIST_STYLE_DECIMAL }, + { "lower-roman", NS_STYLE_LIST_STYLE_LOWER_ROMAN }, + { "upper-roman", NS_STYLE_LIST_STYLE_UPPER_ROMAN }, + { "lower-alpha", NS_STYLE_LIST_STYLE_LOWER_ALPHA }, + { "upper-alpha", NS_STYLE_LIST_STYLE_UPPER_ALPHA }, + { "A", NS_STYLE_LIST_STYLE_UPPER_ALPHA }, + { "a", NS_STYLE_LIST_STYLE_LOWER_ALPHA }, + { "I", NS_STYLE_LIST_STYLE_UPPER_ROMAN }, + { "i", NS_STYLE_LIST_STYLE_LOWER_ROMAN }, + { 0 } +}; + +static nsHTMLTagContent::EnumTable kListItemTypeTable[] = { + { "circle", NS_STYLE_LIST_STYLE_CIRCLE }, + { "round", NS_STYLE_LIST_STYLE_CIRCLE }, + { "square", NS_STYLE_LIST_STYLE_SQUARE }, + { "A", NS_STYLE_LIST_STYLE_UPPER_ALPHA }, + { "a", NS_STYLE_LIST_STYLE_LOWER_ALPHA }, + { "I", NS_STYLE_LIST_STYLE_UPPER_ROMAN }, + { "i", NS_STYLE_LIST_STYLE_LOWER_ROMAN }, + { 0 } +}; + +void nsHTMLContainer::SetAttribute(nsIAtom* aAttribute, + const nsString& aValue) +{ + // Special handling code for various html container attributes; note + // that if an attribute doesn't require special handling then we + // fall through and use the default base class implementation. + + nsHTMLValue val; + if (mTag == nsHTMLAtoms::p) { + if ((aAttribute == nsHTMLAtoms::align) && + ParseDivAlignParam(aValue, val)) { + nsHTMLTagContent::SetAttribute(aAttribute, val); + return; + } + } + else if (mTag == nsHTMLAtoms::a) { + if (aAttribute == nsHTMLAtoms::href) { + nsAutoString href(aValue); + href.StripWhitespace(); + nsHTMLTagContent::SetAttribute(aAttribute, href); + return; + } + if (aAttribute == nsHTMLAtoms::suppress) { + if (aValue.EqualsIgnoreCase("true")) { + nsHTMLValue val; + val.Set(1, eHTMLUnit_Absolute); + nsHTMLTagContent::SetAttribute(aAttribute, val); + return; + } + } + // XXX PRE? + } + else if (mTag == nsHTMLAtoms::font) { + if ((aAttribute == nsHTMLAtoms::size) || + (aAttribute == nsHTMLAtoms::pointSize) || + (aAttribute == nsHTMLAtoms::fontWeight)) { + nsAutoString tmp(aValue); + PRInt32 ec, v = tmp.ToInteger(&ec); + tmp.CompressWhitespace(PR_TRUE, PR_FALSE); + PRUnichar ch = tmp.First(); + val.Set(v, ((ch == '+') || (ch == '-')) ? + eHTMLUnit_Absolute : eHTMLUnit_Enumerated); + nsHTMLTagContent::SetAttribute(aAttribute, val); + return; + } + if (aAttribute == nsHTMLAtoms::color) { + ParseColor(aValue, val); + nsHTMLTagContent::SetAttribute(aAttribute, val); + return; + } + } + else if ((mTag == nsHTMLAtoms::div) || (mTag == nsHTMLAtoms::multicol)) { + if ((mTag == nsHTMLAtoms::div) && (aAttribute == nsHTMLAtoms::align) && + ParseDivAlignParam(aValue, val)) { + nsHTMLTagContent::SetAttribute(aAttribute, val); + return; + } + if (aAttribute == nsHTMLAtoms::cols) { + ParseValue(aValue, 0, val); + nsHTMLTagContent::SetAttribute(aAttribute, val); + return; + } + + // Note: These attributes only apply when cols > 1 + if (aAttribute == nsHTMLAtoms::gutter) { + ParseValue(aValue, 1, val); + nsHTMLTagContent::SetAttribute(aAttribute, val); + return; + } + if (aAttribute == nsHTMLAtoms::width) { + ParseValueOrPercent(aValue, val); + nsHTMLTagContent::SetAttribute(aAttribute, val); + return; + } + } + else if ((mTag == nsHTMLAtoms::h1) || (mTag == nsHTMLAtoms::h2) || + (mTag == nsHTMLAtoms::h3) || (mTag == nsHTMLAtoms::h4) || + (mTag == nsHTMLAtoms::h5) || (mTag == nsHTMLAtoms::h6)) { + if ((aAttribute == nsHTMLAtoms::align) && + ParseDivAlignParam(aValue, val)) { + nsHTMLTagContent::SetAttribute(aAttribute, val); + return; + } + } + else if (mTag == nsHTMLAtoms::pre) { + if ((aAttribute == nsHTMLAtoms::wrap) || + (aAttribute == nsHTMLAtoms::variable)) { + val.Set(1, eHTMLUnit_Absolute); + nsHTMLTagContent::SetAttribute(aAttribute, val); + return; + } + if (aAttribute == nsHTMLAtoms::cols) { + ParseValue(aValue, 0, val); + nsHTMLTagContent::SetAttribute(aAttribute, val); + return; + } + if (aAttribute == nsHTMLAtoms::tabstop) { + PRInt32 ec, tabstop = aValue.ToInteger(&ec); + if (tabstop <= 0) { + tabstop = 8; + } + val.Set(tabstop, eHTMLUnit_Absolute); + nsHTMLTagContent::SetAttribute(aAttribute, val); + return; + } + } + else if (mTag == nsHTMLAtoms::li) { + if (aAttribute == nsHTMLAtoms::type) { + if (ParseEnumValue(aValue, kListItemTypeTable, val)) { + nsHTMLTagContent::SetAttribute(aAttribute, val); + return; + } + // Illegal type values are left as is for the dom + } + if (aAttribute == nsHTMLAtoms::value) { + ParseValue(aValue, 1, val); + nsHTMLTagContent::SetAttribute(aAttribute, val); + return; + } + } + else if ((mTag == nsHTMLAtoms::ul) || (mTag == nsHTMLAtoms::ol) || + (mTag == nsHTMLAtoms::menu) || (mTag == nsHTMLAtoms::dir)) { + if (aAttribute == nsHTMLAtoms::type) { + if (!ParseEnumValue(aValue, kListTypeTable, val)) { + val.Set(NS_STYLE_LIST_STYLE_BASIC, eHTMLUnit_Enumerated); + } + nsHTMLTagContent::SetAttribute(aAttribute, val); + return; + } + if (aAttribute == nsHTMLAtoms::start) { + ParseValue(aValue, 1, val); + nsHTMLTagContent::SetAttribute(aAttribute, val); + return; + } + if (aAttribute == nsHTMLAtoms::compact) { + val.Set(1, eHTMLUnit_Absolute); + nsHTMLTagContent::SetAttribute(aAttribute, val); + return; + } + } + else if (mTag == nsHTMLAtoms::dl) { + if (aAttribute == nsHTMLAtoms::compact) { + val.Set(1, eHTMLUnit_Absolute); + nsHTMLTagContent::SetAttribute(aAttribute, val); + return; + } + } + else if (mTag == nsHTMLAtoms::body) { + if (aAttribute == nsHTMLAtoms::background) { + nsAutoString href(aValue); + href.StripWhitespace(); + nsHTMLTagContent::SetAttribute(aAttribute, href); + return; + } + if (aAttribute == nsHTMLAtoms::bgcolor) { + ParseColor(aValue, val); + nsHTMLTagContent::SetAttribute(aAttribute, val); + return; + } + } + + // Use default attribute catching code + nsHTMLTagContent::SetAttribute(aAttribute, aValue); +} + +nsContentAttr nsHTMLContainer::AttributeToString(nsIAtom* aAttribute, + nsHTMLValue& aValue, + nsString& aResult) const +{ + nsContentAttr ca = eContentAttr_NotThere; + if (aValue.GetUnit() == eHTMLUnit_Enumerated) { + if (aAttribute == nsHTMLAtoms::align) { + DivAlignParamToString(aValue, aResult); + ca = eContentAttr_HasValue; + } + else if (mTag == nsHTMLAtoms::li) { + if (aAttribute == nsHTMLAtoms::type) { + EnumValueToString(aValue, kListItemTypeTable, aResult); + ca = eContentAttr_HasValue; + } + } + else if ((mTag == nsHTMLAtoms::ul) || (mTag == nsHTMLAtoms::ol) || + (mTag == nsHTMLAtoms::menu) || (mTag == nsHTMLAtoms::dir)) { + if (aAttribute == nsHTMLAtoms::type) { + EnumValueToString(aValue, kListTypeTable, aResult); + ca = eContentAttr_HasValue; + } + } + else if (mTag == nsHTMLAtoms::font) { + if ((aAttribute == nsHTMLAtoms::size) || + (aAttribute == nsHTMLAtoms::pointSize) || + (aAttribute == nsHTMLAtoms::fontWeight)) { + aResult.Truncate(); + aResult.Append(aValue.GetIntValue(), 10); + ca = eContentAttr_HasValue; + } + } + } + return ca; +} + +void nsHTMLContainer::MapAttributesInto(nsIStyleContext* aContext, + nsIPresContext* aPresContext) +{ + if (nsnull != mAttributes) { + nsHTMLValue value; + + if (mTag == nsHTMLAtoms::p) { + // align: enum + GetAttribute(nsHTMLAtoms::align, value); + if (value.GetUnit() == eHTMLUnit_Enumerated) { + // XXX set align from enum + } + } + else if (mTag == nsHTMLAtoms::a) { + // suppress: bool (absolute) + GetAttribute(nsHTMLAtoms::suppress, value); + if (value.GetUnit() == eHTMLUnit_Absolute) { + // XXX set suppress + } + } + else if (mTag == nsHTMLAtoms::font) { + nsStyleFont* font = (nsStyleFont*)aContext->GetData(kStyleFontSID); + nsStyleFont* parentFont = font; + nsIStyleContext* parentContext = aContext->GetParent(); + if (nsnull != parentContext) { + parentFont = (nsStyleFont*)parentContext->GetData(kStyleFontSID); + } + + // face: string list + GetAttribute(nsHTMLAtoms::face, value); + if (value.GetUnit() == eHTMLUnit_String) { + nsAutoString familyList; + value.GetStringValue(familyList); + // XXX needs font support to determine usable fonts + // parse up the string & remove the quotes + // XXX only does first until we can tell what are installed fonts + nsAutoString family; + PRInt32 index = familyList.Find(PRUnichar(',')); + if (-1 < index) { + familyList.Left(family, index); + } + else { + family.Append(familyList); + } + family.StripChars("\""); + family.StripWhitespace(); + + font->mFont.name = family; + } + + // pointSize: abs, enum + GetAttribute(nsHTMLAtoms::pointSize, value); + if (value.GetUnit() == eHTMLUnit_Absolute) { + // XXX should probably sanitize value + font->mFont.size = parentFont->mFont.size + NS_POINTS_TO_TWIPS_INT(value.GetIntValue()); + } + else if (value.GetUnit() == eHTMLUnit_Enumerated) { + font->mFont.size = NS_POINTS_TO_TWIPS_INT(value.GetIntValue()); + } + else { + // size: abs, enum + GetAttribute(nsHTMLAtoms::size, value); + if ((value.GetUnit() == eHTMLUnit_Absolute) || (value.GetUnit() == eHTMLUnit_Enumerated)) { + static float kFontScale[7] = { + 0.7f, + 0.8f, + 1.0f, + 1.2f, + 1.5f, + 2.0f, + 3.0f + }; + PRInt32 size = value.GetIntValue(); + + const nsFont& normal = aPresContext->GetDefaultFont(); // XXX should be BASEFONT + + if (value.GetUnit() == eHTMLUnit_Enumerated) { + size = ((0 < size) ? ((size < 8) ? size : 7) : 0); + font->mFont.size = (nscoord)((float)normal.size * kFontScale[size - 1]); + } + else { // enum (+/-) + if ((0 < size) && (size <= 7)) { // + + PRInt32 index; + for (index = 0; index < 6; index++) + if (parentFont->mFont.size < (nscoord)((float)normal.size * kFontScale[index])) + break; + size = ((index - 1) + size); + if (7 < size) size = 7; + font->mFont.size = (nscoord)((float)normal.size * kFontScale[size]); + } + else if ((-7 <= size) && (size < 0)) { + PRInt32 index; + for (index = 6; index > 0; index--) + if (parentFont->mFont.size > (nscoord)((float)normal.size * kFontScale[index])) + break; + size = ((index + 1) + size); + if (size < 0) size = 0; + font->mFont.size = (nscoord)((float)normal.size * kFontScale[size]); + } + else if (0 == size) { + font->mFont.size = parentFont->mFont.size; + } + } + } + } + + // fontWeight: abs, enum + GetAttribute(nsHTMLAtoms::fontWeight, value); + if (value.GetUnit() == eHTMLUnit_Absolute) { // +/- + PRInt32 weight = parentFont->mFont.weight + value.GetIntValue(); + font->mFont.weight = ((100 < weight) ? ((weight < 700) ? weight : 700) : 100); + } + else if (value.GetUnit() == eHTMLUnit_Enumerated) { + PRInt32 weight = value.GetIntValue(); + weight = ((100 < weight) ? ((weight < 700) ? weight : 700) : 100); + font->mFont.weight = weight; + } + + // color: color + GetAttribute(nsHTMLAtoms::color, value); + if (value.GetUnit() == eHTMLUnit_Color) { + nsStyleColor* color = (nsStyleColor*)aContext->GetData(kStyleColorSID); + color->mColor = value.GetColorValue(); + } + else if (value.GetUnit() == eHTMLUnit_String) { + nsAutoString buffer; + value.GetStringValue(buffer); + char cbuf[40]; + buffer.ToCString(cbuf, sizeof(cbuf)); + + nsStyleColor* color = (nsStyleColor*)aContext->GetData(kStyleColorSID); + NS_ColorNameToRGB(cbuf, &(color->mColor)); + } + + NS_IF_RELEASE(parentContext); + } + else if ((mTag == nsHTMLAtoms::div) || (mTag == nsHTMLAtoms::multicol)) { + if (mTag == nsHTMLAtoms::div) { + // align: enum + GetAttribute(nsHTMLAtoms::align, value); + if (value.GetUnit() == eHTMLUnit_Enumerated) { + // XXX set align + } + } + + PRInt32 numCols = 1; + // cols: int + GetAttribute(nsHTMLAtoms::cols, value); + if (value.GetUnit() == eHTMLUnit_Absolute) { + numCols = value.GetIntValue(); + // XXX + } + + // Note: These attributes only apply when cols > 1 + if (1 < numCols) { + // gutter: int + GetAttribute(nsHTMLAtoms::gutter, value); + if (value.GetUnit() == eHTMLUnit_Absolute) { + // XXX set + } + + // width: int, % + GetAttribute(nsHTMLAtoms::width, value); + if (value.GetUnit() == eHTMLUnit_Absolute) { + // XXX set + } + else if (value.GetUnit() == eHTMLUnit_Enumerated) { + // XXX set + } + } + } + else if ((mTag == nsHTMLAtoms::h1) || (mTag == nsHTMLAtoms::h2) || + (mTag == nsHTMLAtoms::h3) || (mTag == nsHTMLAtoms::h4) || + (mTag == nsHTMLAtoms::h5) || (mTag == nsHTMLAtoms::h6)) { + // align: enum + GetAttribute(nsHTMLAtoms::align, value); + if (value.GetUnit() == eHTMLUnit_Enumerated) { + // XXX set + } + } + else if (mTag == nsHTMLAtoms::pre) { + // wrap: flag (abs==1) + GetAttribute(nsHTMLAtoms::wrap, value); + if (value.GetUnit() == eHTMLUnit_Absolute) { + // XXX set + } + + // variable: flag (abs==1) + GetAttribute(nsHTMLAtoms::variable, value); + if (value.GetUnit() == eHTMLUnit_Absolute) { + // XXX set + } + + // cols: int + GetAttribute(nsHTMLAtoms::cols, value); + if (value.GetUnit() == eHTMLUnit_Absolute) { + // XXX set + } + + // tabstop: int + if (value.GetUnit() == eHTMLUnit_Absolute) { + // XXX set + } + } + else if (mTag == nsHTMLAtoms::li) { + nsStyleList* list = (nsStyleList*)aContext->GetData(kStyleListSID); + + // type: enum + GetAttribute(nsHTMLAtoms::type, value); + if (value.GetUnit() == eHTMLUnit_Enumerated) { + list->mListStyleType = value.GetIntValue(); + } + } + else if ((mTag == nsHTMLAtoms::ul) || (mTag == nsHTMLAtoms::ol) || + (mTag == nsHTMLAtoms::menu) || (mTag == nsHTMLAtoms::dir)) { + nsStyleList* list = (nsStyleList*)aContext->GetData(kStyleListSID); + + // type: enum + GetAttribute(nsHTMLAtoms::type, value); + if (value.GetUnit() == eHTMLUnit_Enumerated) { + list->mListStyleType = value.GetIntValue(); + } + + // compact: flag (abs==1) + GetAttribute(nsHTMLAtoms::compact, value); + if (value.GetUnit() == eHTMLUnit_Absolute) { + // XXX set + } + } + else if (mTag == nsHTMLAtoms::dl) { + // compact: flag (abs==1) + GetAttribute(nsHTMLAtoms::compact, value); + if (value.GetUnit() == eHTMLUnit_Absolute) { + // XXX set + } + } + else if (mTag == nsHTMLAtoms::body) { + MapBackgroundAttributesInto(aContext, aPresContext); + } + } +} + + +void +nsHTMLContainer::MapBackgroundAttributesInto(nsIStyleContext* aContext, + nsIPresContext* aPresContext) +{ + nsHTMLValue value; + + // background + if (eContentAttr_HasValue == GetAttribute(nsHTMLAtoms::background, value)) { + if (eHTMLUnit_String == value.GetUnit()) { + // Resolve url to an absolute url + nsIURL* docURL = nsnull; + nsIDocument* doc = mDocument; + if (nsnull != doc) { + docURL = doc->GetDocumentURL(); + } + + nsAutoString absURLSpec; + nsAutoString spec; + value.GetStringValue(spec); + nsresult rv = NS_MakeAbsoluteURL(docURL, "", spec, absURLSpec); + if (nsnull != docURL) { + NS_RELEASE(docURL); + } + nsStyleColor* color = (nsStyleColor*)aContext->GetData(kStyleColorSID); + color->mBackgroundImage = absURLSpec; + color->mBackgroundFlags &= ~NS_STYLE_BG_IMAGE_NONE; + color->mBackgroundRepeat = NS_STYLE_BG_REPEAT_XY; + } + } + + // bgcolor + if (eContentAttr_HasValue == GetAttribute(nsHTMLAtoms::bgcolor, value)) { + if (eHTMLUnit_Color == value.GetUnit()) { + nsStyleColor* color = (nsStyleColor*)aContext->GetData(kStyleColorSID); + color->mBackgroundColor = value.GetColorValue(); + color->mBackgroundFlags &= ~NS_STYLE_BG_COLOR_TRANSPARENT; + } + else if (eHTMLUnit_String == value.GetUnit()) { + nsAutoString buffer; + value.GetStringValue(buffer); + char cbuf[40]; + buffer.ToCString(cbuf, sizeof(cbuf)); + + nsStyleColor* color = (nsStyleColor*)aContext->GetData(kStyleColorSID); + NS_ColorNameToRGB(cbuf, &(color->mBackgroundColor)); + color->mBackgroundFlags &= ~NS_STYLE_BG_COLOR_TRANSPARENT; + } + } +} + + +// nsIDOMNode interface +static NS_DEFINE_IID(kIDOMNodeIID, NS_IDOMNODE_IID); +static NS_DEFINE_IID(kIContentIID, NS_ICONTENT_IID); + +nsresult nsHTMLContainer::GetChildNodes(nsIDOMNodeIterator **aIterator) +{ + NS_PRECONDITION(nsnull != aIterator, "null pointer"); + *aIterator = new nsDOMIterator(*this); + return NS_OK; +} + +nsresult nsHTMLContainer::HasChildNodes() +{ + if (0 != mChildren.Count()) { + return NS_OK; + } + else { + return NS_ERROR_FAILURE; + } +} + +nsresult nsHTMLContainer::GetFirstChild(nsIDOMNode **aNode) +{ + nsIDOMNode* node = nsnull; + nsIContent *child = (nsIContent*) mChildren.ElementAt(0); + if (nsnull != child) { + nsresult res = child->QueryInterface(kIDOMNodeIID, (void**)aNode); + NS_ASSERTION(NS_OK == res, "Must be a DOM Node"); // must be a DOM Node + + return res; + } + + return NS_ERROR_FAILURE; +} + +nsresult nsHTMLContainer::InsertBefore(nsIDOMNode *newChild, nsIDOMNode *refChild) +{ + nsIContent* content = nsnull; + nsresult res = refChild->QueryInterface(kIContentIID, (void**)&content); + NS_ASSERTION(NS_OK == res, "Must be an nsIContent"); + if (NS_OK == res) { + PRInt32 pos = IndexOf(content); + if (pos >= 0) { + nsIContent* newContent = nsnull; + res = newChild->QueryInterface(kIContentIID, (void**)&newContent); + NS_ASSERTION(NS_OK == res, "Must be an nsIContent"); + if (NS_OK == res) { + if (PR_FALSE == InsertChildAt(newContent, pos)) { + res = NS_ERROR_FAILURE; + } + NS_RELEASE(newContent); + } + } + NS_RELEASE(content); + } + + return res; +} + +nsresult nsHTMLContainer::ReplaceChild(nsIDOMNode *newChild, + nsIDOMNode *oldChild) +{ + nsIContent* content = nsnull; + nsresult res = oldChild->QueryInterface(kIContentIID, (void**)&content); + NS_ASSERTION(NS_OK == res, "Must be an nsIContent"); + if (NS_OK == res) { + PRInt32 pos = IndexOf(content); + if (pos >= 0) { + nsIContent* newContent = nsnull; + nsresult res = newChild->QueryInterface(kIContentIID, (void**)&newContent); + NS_ASSERTION(NS_OK == res, "Must be an nsIContent"); + if (NS_OK == res) { + if (PR_FALSE == ReplaceChildAt(newContent, pos)) { + res = NS_ERROR_FAILURE; + } + NS_RELEASE(newContent); + } + } + NS_RELEASE(content); + } + + return res; +} + +nsresult nsHTMLContainer::RemoveChild(nsIDOMNode *oldChild) +{ + nsIDOMNode* oldNode = nsnull; + nsIContent* content = nsnull; + nsresult res = oldChild->QueryInterface(kIContentIID, (void**)&content); + NS_ASSERTION(NS_OK == res, "Must be an nsIContent"); + if (NS_OK == res) { + PRInt32 pos = IndexOf(content); + if (pos >= 0) { + if (PR_TRUE == RemoveChildAt(pos)) { + res = NS_ERROR_FAILURE; + } + } + NS_RELEASE(content); + } + + return res; +} + diff --git a/mozilla/layout/html/base/src/nsHTMLContainer.h b/mozilla/layout/html/base/src/nsHTMLContainer.h new file mode 100644 index 00000000000..56f78a9dea9 --- /dev/null +++ b/mozilla/layout/html/base/src/nsHTMLContainer.h @@ -0,0 +1,75 @@ +/* -*- 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. + */ +#ifndef nsHTMLContainer_h___ +#define nsHTMLContainer_h___ + +#include "nsHTMLTagContent.h" +#include "nsVoidArray.h" + +// Generic HTML container class. This code manages an array of +// children nodes that can be any kind of nsIContent +class nsHTMLContainer : public nsHTMLTagContent { +public: + nsHTMLContainer(nsIAtom* aTag); + + virtual PRBool CanContainChildren() const; + virtual PRInt32 ChildCount() const; + virtual nsIContent* ChildAt(PRInt32 aIndex) const; + virtual PRInt32 IndexOf(nsIContent* aPossibleChild) const; + virtual PRBool InsertChildAt(nsIContent* aKid, PRInt32 aIndex); + virtual PRBool ReplaceChildAt(nsIContent* aKid, PRInt32 aIndex); + virtual PRBool AppendChild(nsIContent* aKid); + virtual PRBool RemoveChildAt(PRInt32 aIndex); + + virtual void Compact(); + + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void SetAttribute(nsIAtom* aAttribute, const nsString& aValue); + virtual void MapAttributesInto(nsIStyleContext* aContext, + nsIPresContext* aPresContext); + + virtual nsresult GetChildNodes(nsIDOMNodeIterator **aIterator); + virtual nsresult HasChildNodes(); + virtual nsresult GetFirstChild(nsIDOMNode **aNode); + virtual nsresult InsertBefore(nsIDOMNode *newChild, nsIDOMNode *refChild); + virtual nsresult ReplaceChild(nsIDOMNode *newChild, + nsIDOMNode *oldChild); + virtual nsresult RemoveChild(nsIDOMNode *oldChild); + +protected: + nsHTMLContainer(); + virtual ~nsHTMLContainer(); + + virtual nsContentAttr AttributeToString(nsIAtom* aAttribute, + nsHTMLValue& aValue, + nsString& aResult) const; + + /** + * Helper method that maps "background" and "bgcolor" into + * the style context. + */ + void MapBackgroundAttributesInto(nsIStyleContext* aContext, + nsIPresContext* aPresContext); + + nsVoidArray mChildren; +}; + +#endif /* nsHTMLContainer_h___ */ diff --git a/mozilla/layout/html/base/src/nsHTMLContainerFrame.cpp b/mozilla/layout/html/base/src/nsHTMLContainerFrame.cpp new file mode 100644 index 00000000000..960b6c0396d --- /dev/null +++ b/mozilla/layout/html/base/src/nsHTMLContainerFrame.cpp @@ -0,0 +1,321 @@ +/* -*- 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 "nsHTMLContainerFrame.h" +#include "nsIRenderingContext.h" +#include "nsIPresContext.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsCSSRendering.h" +#include "nsIContent.h" +#include "nsHTMLAtoms.h" +#include "nsIWidget.h" +#include "nsILinkHandler.h" +#include "nsHTMLValue.h" +#include "nsGUIEvent.h" +#include "nsIDocument.h" +#include "nsIURL.h" + +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); +static NS_DEFINE_IID(kStyleColorSID, NS_STYLECOLOR_SID); + +nsHTMLContainerFrame::nsHTMLContainerFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) + : nsContainerFrame(aContent, aIndexInParent, aParent) +{ +} + +nsHTMLContainerFrame::~nsHTMLContainerFrame() +{ +} + +void +nsHTMLContainerFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + // Do not paint ourselves if we are a pseudo-frame + if (PR_FALSE == IsPseudoFrame()) { + PRIntn skipSides = GetSkipSides(); + nsStyleColor* color = + (nsStyleColor*)mStyleContext->GetData(kStyleColorSID); + nsStyleMolecule* mol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this, + aDirtyRect, mRect, *color); + nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, + aDirtyRect, mRect, *mol, skipSides); + } + + PaintChildren(aPresContext, aRenderingContext, aDirtyRect); + + if (nsIFrame::GetShowFrameBorders()) { + aRenderingContext.SetColor(NS_RGB(255,0,0)); + aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height); + } +} + +void nsHTMLContainerFrame::TriggerLink(nsIPresContext& aPresContext, + const nsString& aBase, + const nsString& aURLSpec, + const nsString& aTargetSpec) +{ + nsILinkHandler* handler; + if (NS_OK == aPresContext.GetLinkHandler(&handler)) { + // Resolve url to an absolute url + nsIURL* docURL = nsnull; + nsIDocument* doc = mContent->GetDocument(); + if (nsnull != doc) { + docURL = doc->GetDocumentURL(); + NS_RELEASE(doc); + } + + nsAutoString absURLSpec; + nsresult rv = NS_MakeAbsoluteURL(docURL, aBase, aURLSpec, absURLSpec); + if (nsnull != docURL) { + NS_RELEASE(docURL); + } + + // Now pass on absolute url to the click handler + handler->OnLinkClick(this, absURLSpec, aTargetSpec); + } +} + +nsEventStatus nsHTMLContainerFrame::HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent) +{ + nsEventStatus rv = nsEventStatus_eIgnore; + switch (aEvent->message) { + case NS_MOUSE_LEFT_BUTTON_UP: + if (nsEventStatus_eIgnore == + nsContainerFrame::HandleEvent(aPresContext, aEvent)) { + // If our child didn't take the click then since we are an + // anchor, we take the click. + nsIAtom* tag = mContent->GetTag(); + if (tag == nsHTMLAtoms::a) { + nsAutoString base, href, target; + mContent->GetAttribute("href", href); + mContent->GetAttribute("target", target); + TriggerLink(aPresContext, base, href, target); + rv = nsEventStatus_eConsumeNoDefault; + } + NS_IF_RELEASE(tag); + } + break; + + case NS_MOUSE_RIGHT_BUTTON_DOWN: + // XXX Bring up a contextual menu provided by the application + break; + + default: + rv = nsContainerFrame::HandleEvent(aPresContext, aEvent); + break; + } + return rv; +} + +PRInt32 nsHTMLContainerFrame::GetCursorAt(nsIPresContext& aPresContext, + const nsPoint& aPoint, + nsIFrame** aFrame) +{ + nsStyleMolecule* mol = (nsStyleMolecule*) + mStyleContext->GetData(kStyleMoleculeSID); + if (mol->cursor != NS_STYLE_CURSOR_INHERIT) { + // If this container has a particular cursor, use it, otherwise + // let the child decide. + *aFrame = this; + return (PRInt32) mol->cursor; + } + return nsContainerFrame::GetCursorAt(aPresContext, aPoint, aFrame); +} + +#if 0 +nsIFrame::ReflowStatus +nsHTMLContainerFrame::IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsISpaceManager* aSpaceManager, + nsReflowCommand& aReflowCommand) +{ + // 0. Get to the correct flow block for this frame that applies to + // the effected frame. If the reflow command is not for us or it's + // deleted or changed then "child" is the child being + // effected. Otherwise child is the child before the effected + // content child (or null if the effected child is our first child) + * flow = FindFlowBlock(aReflowCommand, &child); + + // 1. Recover reflow state + State state; + RecoverState(aPresContext, ..., state); + + // 2. Put state into presentation shell cache so child frames can find + // it. + + if (aReflowCommand.GetTarget() == this) { + // Apply reflow command to the flow frame; one of it's immediate + // children has changed state. + ReflowStatus status; + switch (aReflowCommand.GetType()) { + case nsReflowCommand::rcContentAppended: + status = ReflowAppended(aPresContext, aDesiredSize, aMaxSize, + aSpaceManager, state, flow); + break; + case nsReflowCommand::rcContentInserted: + status = ReflowInserted(aPresContext, aDesiredSize, aMaxSize, + aSpaceManager, state, flow); + break; + case nsReflowCommand::rcContentDeleted: + status = ReflowDeleted(aPresContext, aDesiredSize, aMaxSize, + aSpaceManager, state, flow); + break; + case nsReflowCommand::rcContentChanged: + status = ReflowChanged(aPresContext, aDesiredSize, aMaxSize, + aSpaceManager, state, flow); + break; + case nsReflowCommand::rcUserDefined: + switch ( + break; + default: + // Ignore all other reflow commands + status = frComplete; + break; + } + } else { + // Reflow command applies to one of our children. We need to + // figure out which child because it's going to change size most + // likely and we need to be prepared to deal with it. + nsIFrame* kid = nsnull; + status = aReflowCommand.Next(aDesiredSize, aMaxSize, aSpaceManager, kid); + + // Execute the ReflowChanged post-processing code that deals with + // the child frame's size change; next-in-flows, overflow-lists, + // etc. + } + + // 4. Remove state from presentation shell cache + + return status; +} + +nsIFrame::ReflowStatus +nsHTMLContainerFrame::ReflowAppended(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsISpaceManager* aSpaceManager, + nsReflowCommand& aReflowCommand) +{ + // 1. compute state up to but not including new content w/o reflowing + // everything that's already been flowed + + // 2. if this container uses pseudo-frames then 2b, else 2a + + // 2a. start a reflow-unmapped of the new children + + // 2b. reflow-mapped the last-child if it's a pseudo as it might + // pickup the new children; smarter containers can avoid this if + // they can determine that the last-child won't pickup the new + // children up. Once reflowing the last-child is complete then if + // the status is frComplete then and only then try reflowing any + // remaining unmapped children + + // 2c. For inline and column code the result of a reflow mapped + // cannot impact any previously reflowed children. For block this + // is not true so block needs to reconstruct the line and then + // proceed as if the line were being reflowed for the first time + // (skipping over the existing children, of course). The line still + // needs to be flushed out, vertically aligned, etc, which may cause + // it to not fit. + + // 3. we may end up pushing kids to next-in-flow or stopping before + // all children have been mapped because we are out of room. parent + // needs to look at our return status and create a next-in-flow for + // us; the currently implemented reflow-unmapped code will do the + // right thing in that a child that is being appended and reflowed + // will get it's continuations created by us; if we run out of room + // we return an incomplete status to our parent and it does the same + // to us. +} + +// use a custom reflow command when we push or create an overflow list; + +nsIFrame::ReflowStatus +nsHTMLContainerFrame::ReflowInserted(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsISpaceManager* aSpaceManager, + nsReflowCommand& aReflowCommand) +{ + // 1. compute state up to but not including new content w/o reflowing + // everything that's already been flowed + + // 2. Content insertion implies a new child of this container; the + // content inserted may need special attention (see + // ContentAppended). The same rules apply. However, if the + // pseudo-frame doesn't pullup the child then we need to + // ResizeReflow the addition (We cannot go through the + // reflow-unmapped path because the child frame(s) will need to be + // inserted into the list). + + // 2a if reflow results in a push then go through push reflow + // command path else go through deal-with-size-change +} + +nsIFrame::ReflowStatus +nsHTMLContainerFrame::ReflowDeleted(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsISpaceManager* aSpaceManager, + nsReflowCommand& aReflowCommand) +{ + // 1. compute state up to but not including deleted content w/o reflowing + // everything that's already been flowed + + // 2. remove all of the child frames that belong to the deleted + // child; this includes next-in-flows. mark all of our next-in-flows + // that are impacted by this as dirty (or generate another reflow + // command) + + // 3. Run reflow-mapped code starting at the deleted child point; + // return the usual status to the parent. + + + // Generate reflow commands for my next-in-flows if they are + // impacted by deleting my child's next-in-flows +} + +// Meta point about ReflowChanged; we will factor out the change so +// that only stylistic changes that actually require a reflow end up +// at this frame. The style system will differentiate between +// rendering-only changes and reflow changes. + +nsIFrame::ReflowStatus +nsHTMLContainerFrame::ReflowChanged(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsISpaceManager* aSpaceManager, + nsReflowCommand& aReflowCommand) +{ + // 1. compute state up to but not including deleted content w/o reflowing + // everything that's already been flowed + + // 2. delete the frame that corresponds to the changed child (and + // it's next-in-flows, etc.) + + // 3. run the ReflowInserted code on the content +} +#endif diff --git a/mozilla/layout/html/base/src/nsHTMLContainerFrame.h b/mozilla/layout/html/base/src/nsHTMLContainerFrame.h new file mode 100644 index 00000000000..974db84442d --- /dev/null +++ b/mozilla/layout/html/base/src/nsHTMLContainerFrame.h @@ -0,0 +1,89 @@ +/* -*- 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. + */ +#ifndef nsHTMLContainerFrame_h___ +#define nsHTMLContainerFrame_h___ + +#include "nsContainerFrame.h" +class nsString; +struct nsStyleMolecule; + +// Base class for html container frames that provides common +// functionality. +class nsHTMLContainerFrame : public nsContainerFrame { +public: + nsHTMLContainerFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + virtual void Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + virtual nsEventStatus HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent); + + virtual PRInt32 GetCursorAt(nsIPresContext& aPresContext, + const nsPoint& aPoint, + nsIFrame** aFrame); + +#if 0 + virtual ReflowStatus IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsISpaceManager* aSpaceManager, + nsReflowCommand& aReflowCommand); +#endif + +protected: + virtual ~nsHTMLContainerFrame(); + + virtual PRIntn GetSkipSides() const = 0; + + void TriggerLink(nsIPresContext& aPresContext, + const nsString& aBase, + const nsString& aURLSpec, + const nsString& aTargetSpec); + +#if 0 + virtual ReflowStatus ReflowAppended(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsISpaceManager* aSpaceManager, + nsReflowCommand& aReflowCommand); + + virtual ReflowStatus ReflowInserted(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsISpaceManager* aSpaceManager, + nsReflowCommand& aReflowCommand); + + virtual ReflowStatus ReflowDeleted(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsISpaceManager* aSpaceManager, + nsReflowCommand& aReflowCommand); + + virtual ReflowStatus ReflowChanged(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsISpaceManager* aSpaceManager, + nsReflowCommand& aReflowCommand); +#endif +}; + +#endif /* nsHTMLContainerFrame_h___ */ diff --git a/mozilla/layout/html/base/src/nsHTMLContent.cpp b/mozilla/layout/html/base/src/nsHTMLContent.cpp new file mode 100644 index 00000000000..d2a64f7a89b --- /dev/null +++ b/mozilla/layout/html/base/src/nsHTMLContent.cpp @@ -0,0 +1,510 @@ +/* -*- 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 "nsHTMLContent.h" +#include "nsString.h" +#include "nsIArena.h" +#include "nsIAtom.h" +#include "nsIHTMLAttributes.h" +#include "nsIContentDelegate.h" +#include "nsFrame.h" +#include "nsHTMLIIDs.h" +#include "nsISupportsArray.h" +#include "nsCRT.h" +#include "nsIDocument.h" + +static NS_DEFINE_IID(kIContentDelegateIID, NS_ICONTENTDELEGATE_IID); +static NS_DEFINE_IID(kIContentIID, NS_ICONTENT_IID); +static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); +static NS_DEFINE_IID(kIDOMNodeIID, NS_IDOMNODE_IID); +static NS_DEFINE_IID(kIScriptObjectOwnerIID, NS_ISCRIPTOBJECTOWNER_IID); + +static nsIContentDelegate* gContentDelegate; + +/** + * THE html content delegate. There is exactly one instance of this + * class and it's used for all html content. It just turns around + * and asks the content object to create the frame. + */ +class ContentDelegate : public nsIContentDelegate { +public: + ContentDelegate(); + NS_DECL_ISUPPORTS + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); +protected: + ~ContentDelegate(); +}; + +ContentDelegate::ContentDelegate() +{ + NS_INIT_REFCNT(); +} + +NS_IMPL_ISUPPORTS(ContentDelegate, kIContentDelegateIID); + +ContentDelegate::~ContentDelegate() +{ +} + +nsIFrame* ContentDelegate::CreateFrame(nsIPresContext* aPresContext, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + NS_PRECONDITION(nsnull != aContent, "null ptr"); + + // Make sure the content is html content + nsIHTMLContent* hc; + nsIFrame* rv; + nsresult status = aContent->QueryInterface(kIHTMLContentIID, (void**) &hc); + if (NS_OK != status) { + // This means that *somehow* somebody which is not an html + // content object got ahold of this delegate and tried to + // create a frame with it. Give them back an nsFrame. + status = nsFrame::NewFrame(&rv, aContent, aIndexInParent, aParentFrame); + return rv; + } + + // Ask the content object to create the frame + rv = hc->CreateFrame(aPresContext, aIndexInParent, aParentFrame); + NS_RELEASE(hc); + return rv; +} + +//---------------------------------------------------------------------- + +void* nsHTMLContent::operator new(size_t size) +{ + nsHTMLContent* rv = (nsHTMLContent*) ::operator new(size); + nsCRT::zero(rv, size); + rv->mInHeap = 1; + return (void*) rv; +} + +void* nsHTMLContent::operator new(size_t size, nsIArena* aArena) +{ + nsHTMLContent* rv = (nsHTMLContent*) aArena->Alloc(PRInt32(size)); + nsCRT::zero(rv, size); + return (void*) rv; +} + +void nsHTMLContent::operator delete(void* ptr) +{ + NS_PRECONDITION(nsnull != ptr, "null ptr"); + nsHTMLContent* hc = (nsHTMLContent*) ptr; + if (nsnull != hc) { + if (hc->mInHeap) { + ::delete ptr; + } + } +} + +nsHTMLContent::nsHTMLContent() +{ + // Create shared content delegate if this is the first html content + // object being created. + if (nsnull == gContentDelegate) { + gContentDelegate = new ContentDelegate(); + } + + // Add a reference to the shared content delegate object + NS_ADDREF(gContentDelegate); +} + +nsHTMLContent::~nsHTMLContent() +{ + NS_PRECONDITION(nsnull != gContentDelegate, "null content delegate"); + if (nsnull != gContentDelegate) { + // Remove our reference to the shared content delegate object. If + // the last reference just went away, null out gContentDelegate. + nsrefcnt rc = gContentDelegate->Release(); + if (0 == rc) { + gContentDelegate = nsnull; + } + } +} + +NS_IMPL_ADDREF(nsHTMLContent) +NS_IMPL_RELEASE(nsHTMLContent) + +nsresult nsHTMLContent::QueryInterface(const nsIID& aIID, + void** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kIHTMLContentIID)) { + *aInstancePtrResult = (void*) ((nsIHTMLContent*)this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIContentIID)) { + *aInstancePtrResult = (void*) ((nsIContent*)this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kISupportsIID)) { + *aInstancePtrResult = (void*)(nsISupports*)(nsIContent*)this; + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIDOMNodeIID)) { + *aInstancePtrResult = (void*)(nsIDOMNode*)this; + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIScriptObjectOwnerIID)) { + *aInstancePtrResult = (void*)(nsIScriptObjectOwner*)this; + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +void nsHTMLContent::Compact() +{ +} + +nsIDocument* nsHTMLContent::GetDocument() const +{ + NS_IF_ADDREF(mDocument); + return mDocument; +} + +void nsHTMLContent::SetDocument(nsIDocument* aDocument) +{ + mDocument = aDocument; +} + +nsIContent* nsHTMLContent::GetParent() const +{ + NS_IF_ADDREF(mParent); + return mParent; +} + +void nsHTMLContent::SetParent(nsIContent* aParent) +{ + mParent = aParent; +} + +PRBool nsHTMLContent::CanContainChildren() const +{ + return PR_FALSE; +} + +PRInt32 nsHTMLContent::ChildCount() const +{ + return 0; +} + +nsIContent* nsHTMLContent::ChildAt(PRInt32 aIndex) const +{ + return nsnull; +} + +PRInt32 nsHTMLContent::IndexOf(nsIContent* aPossibleChild) const +{ + return -1; +} + +PRBool nsHTMLContent::InsertChildAt(nsIContent* aKid, PRInt32 aIndex) +{ + return PR_FALSE; +} + +PRBool nsHTMLContent::ReplaceChildAt(nsIContent* aKid, PRInt32 aIndex) +{ + return PR_FALSE; +} + +PRBool nsHTMLContent::AppendChild(nsIContent* aKid) +{ + return PR_FALSE; +} + +PRBool nsHTMLContent::RemoveChildAt(PRInt32 aIndex) +{ + return PR_FALSE; +} + +void nsHTMLContent::SetAttribute(const nsString& aName, const nsString& aValue) +{ +} + +nsContentAttr nsHTMLContent::GetAttribute(const nsString& aName, + nsString& aResult) const +{ + aResult.SetLength(0); + return eContentAttr_NotThere; +} + +void nsHTMLContent::SetAttribute(nsIAtom* aAttribute, const nsString& aValue) +{ +} + +void nsHTMLContent::SetAttribute(nsIAtom* aAttribute, const nsHTMLValue& aValue) +{ +} + +void nsHTMLContent::UnsetAttribute(nsIAtom* aAttribute) +{ +} + +nsContentAttr nsHTMLContent::GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aValue) const +{ + aValue.Reset(); + return eContentAttr_NotThere; +} + +PRInt32 nsHTMLContent::GetAllAttributeNames(nsISupportsArray* aArray) const +{ + return 0; +} + +PRInt32 nsHTMLContent::GetAttributeCount(void) const +{ + return 0; +} + +void nsHTMLContent::SetID(nsIAtom* aID) +{ +} + +nsIAtom* nsHTMLContent::GetID(void) const +{ + return nsnull; +} + +void nsHTMLContent::SetClass(nsIAtom* aClass) +{ +} + +nsIAtom* nsHTMLContent::GetClass(void) const +{ + return nsnull; +} + +nsIStyleRule* nsHTMLContent::GetStyleRule(void) +{ + return nsnull; +} + +void nsHTMLContent::MapAttributesInto(nsIStyleContext* aContext, + nsIPresContext* aPresContext) +{ +} + + +void nsHTMLContent::ListAttributes(FILE* out) const +{ + nsISupportsArray* attrs; + if (NS_OK == NS_NewISupportsArray(&attrs)) { + GetAllAttributeNames(attrs); + PRInt32 count = attrs->Count(); + PRInt32 index; + for (index = 0; index < count; index++) { + nsIAtom* attr = (nsIAtom*)attrs->ElementAt(index); + nsAutoString buffer; + attr->ToString(buffer); +#if 0 // use nsHTMLValue api + nsHTMLValue value; + GetAttribute(attr, value); +#else // use string api + nsAutoString value; + GetAttribute(buffer, value); +#endif + buffer.Append("="); +#if 0 + value.AppendToString(buffer); +#else + buffer.Append(value); +#endif + fputs(" ", out); + fputs(buffer, out); + NS_RELEASE(attr); + } + NS_RELEASE(attrs); + } +} + +void nsHTMLContent::List(FILE* out, PRInt32 aIndent) const +{ + NS_PRECONDITION(nsnull != mDocument, "bad content"); + + PRInt32 index; + for (index = aIndent; --index >= 0; ) fputs(" ", out); + + nsIAtom* tag = GetTag(); + if (tag != nsnull) { + nsAutoString buf; + tag->ToString(buf); + fputs(buf, out); + NS_RELEASE(tag); + } + + ListAttributes(out); + + fprintf(out, " RefCount=%d<\n", mRefCnt); + + if (CanContainChildren()) { + PRInt32 kids = ChildCount(); + for (index = 0; index < kids; index++) { + nsIContent* kid = ChildAt(index); + kid->List(out, aIndent + 1); + NS_RELEASE(kid); + } + } + + for (index = aIndent; --index >= 0; ) fputs(" ", out); + fputs(">\n", out); +} + +PRUint32 nsHTMLContent::SizeOf(nsISizeofHandler* aHandler) const +{ + return 0; +} + +nsIAtom* nsHTMLContent::GetTag() const +{ + return nsnull; +} + +void nsHTMLContent::ToHTML(FILE* out) const +{ + nsAutoString tmp; + ToHTMLString(tmp); + fputs(tmp, out); +} + +nsIContentDelegate* nsHTMLContent::GetDelegate(nsIPresContext* aCX) +{ + gContentDelegate->AddRef(); + return gContentDelegate; +} + +void nsHTMLContent::NewGlobalAtom(const char* aString, nsIAtom** aAtomResult) +{ + if (nsnull == *aAtomResult) { + *aAtomResult = NS_NewAtom(aString); + } else { + NS_ADDREF(*aAtomResult); + } +} + +void nsHTMLContent::ReleaseGlobalAtom(nsIAtom** aAtomResult) +{ + nsIAtom* atom = *aAtomResult; + if (nsnull != atom) { + if (0 == atom->Release()) { + *aAtomResult = nsnull; + } + } +} + +nsresult nsHTMLContent::ResetScriptObject() +{ + mScriptObject = nsnull; + return NS_OK; +} + +// nsIDOMNode interface +nsresult nsHTMLContent::GetParentNode(nsIDOMNode **aNode) +{ + if (nsnull != mParent) { + nsresult res = mParent->QueryInterface(kIDOMNodeIID, (void**)aNode); + NS_ASSERTION(NS_OK == res, "Must be a DOM Node"); + return res; + } + + return NS_ERROR_FAILURE; +} + +nsresult nsHTMLContent::GetChildNodes(nsIDOMNodeIterator **aIterator) +{ + return NS_ERROR_FAILURE; +} + +nsresult nsHTMLContent::HasChildNodes() +{ + return NS_ERROR_FAILURE; +} + +nsresult nsHTMLContent::GetFirstChild(nsIDOMNode **aNode) +{ + return NS_ERROR_FAILURE; +} + +nsresult nsHTMLContent::GetPreviousSibling(nsIDOMNode **aNode) +{ + if (nsnull != mParent) { + PRInt32 pos = mParent->IndexOf(this); + if (pos > -1) { + nsIContent* prev = mParent->ChildAt(--pos); + if (nsnull != prev) { + nsresult res = prev->QueryInterface(kIDOMNodeIID, (void**)aNode); + NS_ASSERTION(NS_OK == res, "Must be a DOM Node"); + + NS_RELEASE(prev); // balance the AddRef in ChildAt() + + return res; + } + } + } + + return NS_ERROR_FAILURE; +} + +nsresult nsHTMLContent::GetNextSibling(nsIDOMNode **aNode) +{ + if (nsnull != mParent) { + PRInt32 pos = mParent->IndexOf(this); + if (pos > -1 ) { + nsIContent* prev = mParent->ChildAt(++pos); + if (nsnull != prev) { + nsresult res = prev->QueryInterface(kIDOMNodeIID, (void**)aNode); + NS_ASSERTION(NS_OK == res, "Must be a DOM Node"); + NS_RELEASE(prev); // balance the AddRef in ChildAt() + + return res; + } + } + } + + return NS_ERROR_FAILURE; +} + +nsresult nsHTMLContent::InsertBefore(nsIDOMNode *newChild, nsIDOMNode *refChild) +{ + return NS_ERROR_FAILURE; +} + +nsresult nsHTMLContent::ReplaceChild(nsIDOMNode *newChild, + nsIDOMNode *oldChild) +{ + return NS_ERROR_FAILURE; +} + +nsresult nsHTMLContent::RemoveChild(nsIDOMNode *oldChild) +{ + return NS_ERROR_FAILURE; +} + diff --git a/mozilla/layout/html/base/src/nsHTMLContent.h b/mozilla/layout/html/base/src/nsHTMLContent.h new file mode 100644 index 00000000000..5a65670ba55 --- /dev/null +++ b/mozilla/layout/html/base/src/nsHTMLContent.h @@ -0,0 +1,136 @@ +/* -*- 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. + */ +#ifndef nsHTMLContent_h___ +#define nsHTMLContent_h___ + +#include "nsIHTMLContent.h" +#include "nsIDOMNode.h" +#include "nsIScriptObjectOwner.h" +class nsIArena; +class nsIAtom; + +/** + * Abstract base class for un-tagged html content objects. Supports + * allocation from the malloc heap as well as from an arena. Note + * that instances of this object are created with zero'd memory. + */ +class nsHTMLContent : public nsIHTMLContent, public nsIDOMNode, public nsIScriptObjectOwner { +public: + /** + * This new method allocates memory from the standard malloc heap + * and zeros out the content object. + */ + void* operator new(size_t size); + + /** + * This new method allocates memory from the given arena and + * and zeros out the content object. + */ + void* operator new(size_t size, nsIArena* aArena); + + /** + * Release the memory associated with the content object. If the + * object was allocated from an arena then nothing happens. + */ + void operator delete(void* ptr); + + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + + virtual nsIDocument* GetDocument() const; + virtual void SetDocument(nsIDocument* aDocument); + + virtual nsIContent* GetParent() const; + virtual void SetParent(nsIContent* aParent); + + virtual PRBool CanContainChildren() const; + virtual PRInt32 ChildCount() const; + virtual nsIContent* ChildAt(PRInt32 aIndex) const; + virtual PRInt32 IndexOf(nsIContent* aPossibleChild) const; + virtual PRBool InsertChildAt(nsIContent* aKid, PRInt32 aIndex); + virtual PRBool ReplaceChildAt(nsIContent* aKid, PRInt32 aIndex); + virtual PRBool AppendChild(nsIContent* aKid); + virtual PRBool RemoveChildAt(PRInt32 aIndex); + + virtual void Compact(); + + virtual void SetAttribute(const nsString& aName, const nsString& aValue); + virtual nsContentAttr GetAttribute(const nsString& aName, + nsString& aResult) const; + + virtual void SetAttribute(nsIAtom* aAttribute, const nsString& aValue); + virtual void SetAttribute(nsIAtom* aAttribute, + const nsHTMLValue& aValue = nsHTMLValue::kNull); + virtual void UnsetAttribute(nsIAtom* aAttribute); + virtual nsContentAttr GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aValue) const; + virtual PRInt32 GetAllAttributeNames(nsISupportsArray* aArray) const; + virtual PRInt32 GetAttributeCount(void) const; + + virtual void SetID(nsIAtom* aID); + virtual nsIAtom* GetID(void) const; + virtual void SetClass(nsIAtom* aClass); // XXX this will have to change for CSS2 + virtual nsIAtom* GetClass(void) const; // XXX this will have to change for CSS2 + + virtual nsIStyleRule* GetStyleRule(void); + + virtual void MapAttributesInto(nsIStyleContext* aContext, + nsIPresContext* aPresContext); + + virtual void List(FILE* out, PRInt32 aIndent) const; + + virtual PRUint32 SizeOf(nsISizeofHandler* aHandler) const; + + virtual nsIAtom* GetTag() const; + + virtual void ToHTML(FILE* out) const; + + virtual nsIContentDelegate* GetDelegate(nsIPresContext* aCX); + + static void NewGlobalAtom(const char* aString, nsIAtom** aAtomResult); + + static void ReleaseGlobalAtom(nsIAtom** aAtomResult); + +public: + virtual nsresult ResetScriptObject(); + + // nsIDOMNode interface + virtual nsresult GetParentNode(nsIDOMNode **aNode); + virtual nsresult GetChildNodes(nsIDOMNodeIterator **aIterator); + virtual nsresult HasChildNodes(); + virtual nsresult GetFirstChild(nsIDOMNode **aNode); + virtual nsresult GetPreviousSibling(nsIDOMNode **aNode); + virtual nsresult GetNextSibling(nsIDOMNode **aNode); + virtual nsresult InsertBefore(nsIDOMNode *newChild, nsIDOMNode *refChild); + virtual nsresult ReplaceChild(nsIDOMNode *newChild, nsIDOMNode *oldChild); + virtual nsresult RemoveChild(nsIDOMNode *oldChild); + +protected: + nsHTMLContent(); + virtual ~nsHTMLContent(); + virtual void ListAttributes(FILE* out) const; + + PRUint32 mInHeap : 1; + PRUint32 mRefCnt : 31; + nsIDocument* mDocument; + nsIContent* mParent; + void* mScriptObject; +}; + +#endif /* nsHTMLContent_h___ */ diff --git a/mozilla/layout/html/base/src/nsHTMLIIDs.cpp b/mozilla/layout/html/base/src/nsHTMLIIDs.cpp new file mode 100644 index 00000000000..64f39328acc --- /dev/null +++ b/mozilla/layout/html/base/src/nsHTMLIIDs.cpp @@ -0,0 +1,23 @@ +/* -*- 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 "nsHTMLIIDs.h" +#include "nsIHTMLContent.h" +#include "nsIHTMLFrameType.h" + +const nsIID kIHTMLContentIID = NS_IHTMLCONTENT_IID; +const nsIID kIHTMLFrameTypeIID = NS_IHTMLFRAMETYPE_IID; diff --git a/mozilla/layout/html/base/src/nsHTMLIIDs.h b/mozilla/layout/html/base/src/nsHTMLIIDs.h new file mode 100644 index 00000000000..8a4e3e694ca --- /dev/null +++ b/mozilla/layout/html/base/src/nsHTMLIIDs.h @@ -0,0 +1,26 @@ +/* -*- 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. + */ +#ifndef nsHTMLIIDs_h___ +#define nsHTMLIIDs_h___ + +#include "nsISupports.h" + +extern const nsIID kIHTMLContentIID; +extern const nsIID kIHTMLFrameTypeIID; + +#endif /* nsHTMLIIDs_h___ */ diff --git a/mozilla/layout/html/base/src/nsHTMLImage.cpp b/mozilla/layout/html/base/src/nsHTMLImage.cpp new file mode 100644 index 00000000000..b7252c7f684 --- /dev/null +++ b/mozilla/layout/html/base/src/nsHTMLImage.cpp @@ -0,0 +1,559 @@ +/* -*- 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 "nsHTMLParts.h" +#include "nsHTMLTagContent.h" +#include "nsString.h" +#include "nsLeafFrame.h" +#include "nsIPresContext.h" +#include "nsIRenderingContext.h" +#include "nsHTMLIIDs.h" +#include "nsIImage.h" +#include "nsIWidget.h" +#include "nsIImage.h" +#include "nsHTMLAtoms.h" +#include "nsIHTMLAttributes.h" +#include "nsIDocument.h" +#include "nsIHTMLDocument.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsIImageMap.h" +#include "nsILinkHandler.h" +#include "nsIURL.h" + +static NS_DEFINE_IID(kIHTMLDocumentIID, NS_IHTMLDOCUMENT_IID); +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); + +class ImageFrame : public nsLeafFrame { +public: + ImageFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + virtual nsEventStatus HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent); + + virtual PRInt32 GetCursorAt(nsIPresContext& aPresContext, + const nsPoint& aPoint, + nsIFrame** aFrame); + +protected: + virtual ~ImageFrame(); + + virtual void GetDesiredSize(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize); + + nsIImage* GetImage(nsIPresContext& aPresContext); + + nsIImageMap* GetImageMap(); + + void TriggerLink(nsIPresContext& aPresContext, + const nsString& aURLSpec, + const nsString& aTargetSpec); +}; + +class ImagePart : public nsHTMLTagContent { +public: + ImagePart(nsIAtom* aTag); + + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void SetAttribute(nsIAtom* aAttribute, const nsString& aValue); + virtual nsContentAttr GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aResult) const; + virtual void UnsetAttribute(nsIAtom* aAttribute); + + PRPackedBool mIsMap; + PRUint8 mSuppress; + PRUint8 mAlign; + nsString* mAltText; + nsString* mSrc; + nsString* mLowSrc; + nsString* mUseMap; + +protected: + virtual ~ImagePart(); + + virtual nsContentAttr AttributeToString(nsIAtom* aAttribute, + nsHTMLValue& aValue, + nsString& aResult) const; +}; + +// Value's for mSuppress +#define SUPPRESS_UNSET 0 +#define DONT_SUPPRESS 1 +#define SUPPRESS 2 +#define DEFAULT_SUPPRESS 3 + +// Default alignment value (so we can tell an unset value from a set value) +#define ALIGN_UNSET PRUint8(-1) + +//---------------------------------------------------------------------- + +ImageFrame::ImageFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsLeafFrame(aContent, aIndexInParent, aParentFrame) +{ +} + +ImageFrame::~ImageFrame() +{ +} + +nsIImage* ImageFrame::GetImage(nsIPresContext& aPresContext) +{ + nsAutoString src; + if (eContentAttr_HasValue == mContent->GetAttribute("SRC", src)) { + return aPresContext.LoadImage(src, this); + } + return nsnull; +} + +void ImageFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + nsIImage* image = GetImage(aPresContext); + if (nsnull == image) { + return; + } + + // First paint background and borders + nsLeafFrame::Paint(aPresContext, aRenderingContext, aDirtyRect); + + // Now render the image into our inner area (the area without the + // borders and padding) + nsRect inner; + GetInnerArea(&aPresContext, inner); + aRenderingContext.DrawImage(image, inner); + + if (GetShowFrameBorders()) { + nsIImageMap* map = GetImageMap(); + if (nsnull != map) { + aRenderingContext.SetColor(NS_RGB(0, 0, 0)); + map->Draw(aPresContext, aRenderingContext); + } + } +} + +nsIImageMap* ImageFrame::GetImageMap() +{ + ImagePart* part = (ImagePart*)mContent; + if (nsnull == part->mUseMap) { + return nsnull; + } + + nsIDocument* doc = mContent->GetDocument(); + if (nsnull == doc) { + return nsnull; + } + + nsAutoString mapName(*part->mUseMap); + if (mapName.First() == '#') { + mapName.Cut(0, 1); + } + nsIHTMLDocument* hdoc; + nsresult rv = doc->QueryInterface(kIHTMLDocumentIID, (void**)&hdoc); + NS_RELEASE(doc); + if (NS_OK == rv) { + nsIImageMap* map; + rv = hdoc->GetImageMap(mapName, &map); + NS_RELEASE(hdoc); + if (NS_OK == rv) { + return map; + } + } + + return nsnull; +} + +void ImageFrame::TriggerLink(nsIPresContext& aPresContext, + const nsString& aURLSpec, + const nsString& aTargetSpec) +{ + nsILinkHandler* handler; + if (NS_OK == aPresContext.GetLinkHandler(&handler)) { + // Now pass on absolute url to the click handler + handler->OnLinkClick(this, aURLSpec, aTargetSpec); + } +} + +// XXX what about transparent pixels? +nsEventStatus ImageFrame::HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent) +{ + nsEventStatus rv = nsEventStatus_eIgnore; + + switch (aEvent->message) { + case NS_MOUSE_LEFT_BUTTON_UP: + { + nsIImageMap* map = GetImageMap(); + if (nsnull != map) { + nsIURL* docURL = nsnull; + nsIDocument* doc = mContent->GetDocument(); + if (nsnull != doc) { + docURL = doc->GetDocumentURL(); + NS_RELEASE(doc); + } + + // Translate coordinates to pixels + float t2p = aPresContext.GetTwipsToPixels(); + nscoord x = nscoord(t2p * aEvent->point.x); + nscoord y = nscoord(t2p * aEvent->point.y); + + // Ask map if the x,y coordinates are in a clickable area + PRBool suppress; + nsAutoString absURL, target, altText; + nsresult r = map->IsInside(x, y, docURL, absURL, target, altText, + &suppress); + NS_IF_RELEASE(docURL); + NS_RELEASE(map); + if (NS_OK == r) { + // We hit a clickable area. Time to go somewhere... + TriggerLink(aPresContext, absURL, target); + rv = nsEventStatus_eConsumeNoDefault; + } + break; + } + } + // FALL THROUGH + + default: + // Let default event handler deal with it + return nsLeafFrame::HandleEvent(aPresContext, aEvent); + } + + return rv; +} + +PRInt32 ImageFrame::GetCursorAt(nsIPresContext& aPresContext, + const nsPoint& aPoint, + nsIFrame** aFrame) +{ + nsStyleMolecule* mol = (nsStyleMolecule*) + mStyleContext->GetData(kStyleMoleculeSID); + if (mol->cursor != NS_STYLE_CURSOR_INHERIT) { + // If this container has a particular cursor, use it, otherwise + // let the child decide. + *aFrame = this; + return (PRInt32) mol->cursor; + } + nsIImageMap* map = GetImageMap(); + if (nsnull != map) { + PRInt32 rv = NS_STYLE_CURSOR_DEFAULT; + float t2p = aPresContext.GetTwipsToPixels(); + nscoord x = nscoord(t2p * aPoint.x); + nscoord y = nscoord(t2p * aPoint.y); + if (NS_OK == map->IsInside(x, y)) { + rv = NS_STYLE_CURSOR_HAND; + } + NS_RELEASE(map); + return rv; + } + return NS_STYLE_CURSOR_INHERIT; +} + +void ImageFrame::GetDesiredSize(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize) +{ + // XXX temporary hack: Get width & height from attributes + nscoord width = -1; + nscoord height = -1; + ImagePart* part = (ImagePart*) mContent; + nsHTMLValue value; + nsContentAttr ca; + ca = part->nsHTMLTagContent::GetAttribute(nsHTMLAtoms::width, value); + if (eContentAttr_HasValue == ca) { + // XXX Percents + width = value.GetIntValue(); + } + ca = part->nsHTMLTagContent::GetAttribute(nsHTMLAtoms::height, value); + if (eContentAttr_HasValue == ca) { + // XXX Percents + height = value.GetIntValue(); + } + + float p2t = aPresContext->GetPixelsToTwips(); + if ((0 < width) && (0 < height)) { + // Use dimensions from style attributes + aDesiredSize.width = nscoord(width * p2t); + aDesiredSize.height = nscoord(height * p2t); + } else { + nsIImage* image = GetImage(*aPresContext); + if (nsnull == image) { + // XXX Here is where we trigger a resize-reflow later on; or block + // layout or whatever our policy wants to be + aDesiredSize.width = nscoord(50 * p2t); + aDesiredSize.height = nscoord(50 * p2t); + } else { + aDesiredSize.width = nscoord(image->GetWidth() * p2t); + aDesiredSize.height = nscoord(image->GetHeight() * p2t); + } + } +} + +//---------------------------------------------------------------------- + +ImagePart::ImagePart(nsIAtom* aTag) + : nsHTMLTagContent(aTag) +{ + mAlign = ALIGN_UNSET; + mSuppress = SUPPRESS_UNSET; +} + +ImagePart::~ImagePart() +{ + if (nsnull != mAltText) delete mAltText; + if (nsnull != mSrc) delete mSrc; + if (nsnull != mLowSrc) delete mLowSrc; + if (nsnull != mUseMap) delete mUseMap; +} + +void ImagePart::SetAttribute(nsIAtom* aAttribute, const nsString& aString) +{ + if (aAttribute == nsHTMLAtoms::ismap) { + mIsMap = PR_TRUE; + return; + } + if (aAttribute == nsHTMLAtoms::usemap) { + nsAutoString src(aString); + src.StripWhitespace(); + if (nsnull == mUseMap) { + mUseMap = new nsString(src); + } else { + *mUseMap = src; + } + return; + } + if (aAttribute == nsHTMLAtoms::align) { + nsHTMLValue val; + if (ParseAlignParam(aString, val)) { + mAlign = val.GetIntValue(); + // Reflect the attribute into the syle system + nsHTMLTagContent::SetAttribute(aAttribute, val); + } else { + mAlign = ALIGN_UNSET; + } + return; + } + if (aAttribute == nsHTMLAtoms::src) { + nsAutoString src(aString); + src.StripWhitespace(); + if (nsnull == mSrc) { + mSrc = new nsString(src); + } else { + *mSrc = src; + } + return; + } + if (aAttribute == nsHTMLAtoms::lowsrc) { + nsAutoString src(aString); + src.StripWhitespace(); + if (nsnull == mLowSrc) { + mLowSrc = new nsString(src); + } else { + *mLowSrc = src; + } + return; + } + if (aAttribute == nsHTMLAtoms::alt) { + if (nsnull == mAltText) { + mAltText = new nsString(aString); + } else { + *mAltText = aString; + } + return; + } + if (aAttribute == nsHTMLAtoms::suppress) { + if (aString.EqualsIgnoreCase("true")) { + mSuppress = SUPPRESS; + } else if (aString.EqualsIgnoreCase("false")) { + mSuppress = DONT_SUPPRESS; + } else { + mSuppress = DEFAULT_SUPPRESS; + } + return; + } + + // Try other attributes + nsHTMLValue val; + if (ParseImageProperty(aAttribute, aString, val)) { + nsHTMLTagContent::SetAttribute(aAttribute, val); + return; + } + + // Use default attribute catching code + nsHTMLTagContent::SetAttribute(aAttribute, aString); +} + +nsContentAttr ImagePart::GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aResult) const +{ + nsContentAttr ca = eContentAttr_NotThere; + aResult.Reset(); + if (aAttribute == nsHTMLAtoms::ismap) { + if (mIsMap) { + ca = eContentAttr_HasValue; + } + } + else if (aAttribute == nsHTMLAtoms::usemap) { + if (nsnull != mUseMap) { + aResult.Set(*mUseMap); + ca = eContentAttr_HasValue; + } + } + else if (aAttribute == nsHTMLAtoms::align) { + if (ALIGN_UNSET != mAlign) { + aResult.Set(mAlign, eHTMLUnit_Enumerated); + ca = eContentAttr_HasValue; + } + } + else if (aAttribute == nsHTMLAtoms::src) { + if (nsnull != mSrc) { + aResult.Set(*mSrc); + ca = eContentAttr_HasValue; + } + } + else if (aAttribute == nsHTMLAtoms::lowsrc) { + if (nsnull != mLowSrc) { + aResult.Set(*mLowSrc); + ca = eContentAttr_HasValue; + } + } + else if (aAttribute == nsHTMLAtoms::alt) { + if (nsnull != mAltText) { + aResult.Set(*mAltText); + ca = eContentAttr_HasValue; + } + } + else if (aAttribute == nsHTMLAtoms::suppress) { + if (SUPPRESS_UNSET != mSuppress) { + switch (mSuppress) { + case SUPPRESS: aResult.Set(1, eHTMLUnit_Absolute); break; + case DONT_SUPPRESS: aResult.Set(0, eHTMLUnit_Absolute); break; + case DEFAULT_SUPPRESS: aResult.Reset(); break; + } + ca = eContentAttr_HasValue; + } + } + else { + ca = nsHTMLTagContent::GetAttribute(aAttribute, aResult); + } + return ca; +} + +void ImagePart::UnsetAttribute(nsIAtom* aAttribute) +{ + nsContentAttr ca = eContentAttr_NotThere; + if (aAttribute == nsHTMLAtoms::ismap) { + mIsMap = PR_FALSE; + } + else if (aAttribute == nsHTMLAtoms::usemap) { + if (nsnull != mUseMap) { + delete mUseMap; + mUseMap = nsnull; + } + } + else if (aAttribute == nsHTMLAtoms::align) { + mAlign = ALIGN_UNSET; + } + else if (aAttribute == nsHTMLAtoms::src) { + if (nsnull != mSrc) { + delete mSrc; + mSrc = nsnull; + } + } + else if (aAttribute == nsHTMLAtoms::lowsrc) { + if (nsnull != mLowSrc) { + delete mLowSrc; + mSrc = nsnull; + } + } + else if (aAttribute == nsHTMLAtoms::alt) { + if (nsnull != mAltText) { + delete mAltText; + mAltText = nsnull; + } + } + else if (aAttribute == nsHTMLAtoms::suppress) { + mSuppress = SUPPRESS_UNSET; + } + else { + nsHTMLTagContent::UnsetAttribute(aAttribute); + } +} + +nsContentAttr ImagePart::AttributeToString(nsIAtom* aAttribute, + nsHTMLValue& aValue, + nsString& aResult) const +{ + nsContentAttr ca = eContentAttr_NotThere; + if (aAttribute == nsHTMLAtoms::align) { + if ((eHTMLUnit_Enumerated == aValue.GetUnit()) && + (ALIGN_UNSET != aValue.GetIntValue())) { + AlignParamToString(aValue, aResult); + ca = eContentAttr_HasValue; + } + } + else if (aAttribute == nsHTMLAtoms::suppress) { + if (SUPPRESS_UNSET != mSuppress) { + aResult.SetLength(0); + switch (mSuppress) { + case SUPPRESS: aResult.Append("true"); break; + case DONT_SUPPRESS: aResult.Append("false"); break; + case DEFAULT_SUPPRESS: break; + } + ca = eContentAttr_HasValue; + } + } + else if (ImagePropertyToString(aAttribute, aValue, aResult)) { + ca = eContentAttr_HasValue; + } + return ca; +} + +nsIFrame* ImagePart::CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + ImageFrame* rv = new ImageFrame(this, aIndexInParent, aParentFrame); + return rv; +} + +nsresult +NS_NewHTMLImage(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIHTMLContent* img = new ImagePart(aTag); + if (nsnull == img) { + return NS_ERROR_OUT_OF_MEMORY; + } + return img->QueryInterface(kIHTMLContentIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/layout/html/base/src/nsHTMLParts.h b/mozilla/layout/html/base/src/nsHTMLParts.h new file mode 100644 index 00000000000..4004a300b13 --- /dev/null +++ b/mozilla/layout/html/base/src/nsHTMLParts.h @@ -0,0 +1,134 @@ +/* -*- 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. + */ +#ifndef nsHTMLParts_h___ +#define nsHTMLParts_h___ + +#include "nscore.h" +#include "nsISupports.h" +class nsIArena; +class nsIAtom; +class nsIContent; +class nsIDocument; +class nsIHTMLContent; +class nsIHTMLContentSink; +class nsITextContent; +class nsIURL; +class nsString; + +// XXX naming consistency puhleeze! + +extern nsresult NS_NewHTMLContentSink(nsIHTMLContentSink** aInstancePtrResult, + nsIDocument* aDoc, + nsIURL* aURL); + +// Create an html root part +extern nsresult + NS_NewRootPart(nsIHTMLContent** aInstancePtrResult, + nsIDocument* aDocument); + +// Create an html body part +extern nsresult + NS_NewBodyPart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag); + +// Create a new generic html container (e.g. P, DIV, SPAN, B, I, etc). +// Not used for tables or framesets (see below). +extern nsresult + NS_NewHTMLContainer(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag); +extern nsresult + NS_NewHTMLContainer(nsIHTMLContent** aInstancePtrResult, + nsIArena* aArena, nsIAtom* aTag); + +extern nsresult + NS_NewHTMLBreak(nsIHTMLContent** aInstancePtrResult, nsIAtom* aTag); + +extern nsresult + NS_NewHTMLWordBreak(nsIHTMLContent** aInstancePtrResult, nsIAtom* aTag); + +extern nsresult + NS_NewHTMLSpacer(nsIHTMLContent** aInstancePtrResult, nsIAtom* aTag); + +// Create a new text content object. The memory for the unicode string +// will be allocated from the heap. The object returned will support +// the nsIHTMLContent interface as well as the nsITextContent +// interface +extern nsresult + NS_NewHTMLText(nsIHTMLContent** aInstancePtrResult, + const PRUnichar* us, PRInt32 uslen = 0); +extern nsresult + NS_NewHTMLText(nsIHTMLContent** aInstancePtrResult, + nsIArena* aArena, const PRUnichar* us, PRInt32 uslen = 0); + +// Create a new text content object. The memory for the unicode string +// is allocated by the caller. The caller is responsible for +// deallocating the memory (e.g. use an nsIArena). The object returned +// will support the nsIHTMLContent interface as well as the +// nsITextContent interface +extern nsresult + NS_NewSharedHTMLText(nsIHTMLContent** aInstancePtrResult, + PRUnichar* us, PRInt32 uslen = 0); +extern nsresult + NS_NewSharedHTMLText(nsIHTMLContent** aInstancePtrResult, + nsIArena* aArena, PRUnichar* us, PRInt32 uslen = 0); + +/** Create a new horizontal rule content object (e.g
.) */ +extern nsresult +NS_NewHRulePart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag); + +/** Create a new table content object */ +extern nsresult +NS_NewTablePart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag); + +/** Create a new table row group object */ +extern nsresult +NS_NewTableRowGroupPart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag); + +/** Create a new table row content object */ +extern nsresult +NS_NewTableRowPart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag); + +/** Create a new table column group content object */ +extern nsresult +NS_NewTableColGroupPart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag); + +/** Create a new table column content object */ +extern nsresult +NS_NewTableColPart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag); + +/** Create a new table cell content object + + + + + + + + diff --git a/mozilla/parser/htmlparser/tests/html/list002.html b/mozilla/parser/htmlparser/tests/html/list002.html new file mode 100644 index 00000000000..f5c31fb4079 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/list002.html @@ -0,0 +1,15 @@ + +Welcome to Hewlett-Packard + + + +This file was created on 9/16/97 for bug #85117, assert in parser +when closing dd tag. + + +abcd efg + + + + + diff --git a/mozilla/parser/htmlparser/tests/html/list003.html b/mozilla/parser/htmlparser/tests/html/list003.html new file mode 100644 index 00000000000..c47e5ab5094 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/list003.html @@ -0,0 +1,19 @@ + + + +text line 1 + +Text after font color=red +
    +
  • first list item +

    still in list item. +

  • . second list item. + ... +
+ +Text after list, still in font color=red +
+Text after font color=red. +text at tend. + + \ No newline at end of file diff --git a/mozilla/parser/htmlparser/tests/html/newlines.html b/mozilla/parser/htmlparser/tests/html/newlines.html new file mode 100644 index 00000000000..a949cc70e90 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/newlines.html @@ -0,0 +1,3 @@ +#1: This is a line of input terminated by a \n +#2: This is another line of input terminated by a \r\n +#3: This is a line of input terminated by a \r #4: This is the last line diff --git a/mozilla/parser/htmlparser/tests/html/obj001.html b/mozilla/parser/htmlparser/tests/html/obj001.html new file mode 100644 index 00000000000..823b1939d43 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/obj001.html @@ -0,0 +1,12 @@ + + + + + + + Java applet that plays a welcoming sound. + + + diff --git a/mozilla/parser/htmlparser/tests/html/obj002.html b/mozilla/parser/htmlparser/tests/html/obj002.html new file mode 100644 index 00000000000..b0805ba8eae --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/obj002.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/mozilla/parser/htmlparser/tests/html/obj003.html b/mozilla/parser/htmlparser/tests/html/obj003.html new file mode 100644 index 00000000000..e7cb0f03ee2 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/obj003.html @@ -0,0 +1,17 @@ + + + + + object element with no attributes. + object element with lang attribute set to en. + object element with dir attribute set to ltr. + + param element with no attributes:
+ +
+ + param element with the name attribute and an end tag:
+ +
+ + diff --git a/mozilla/parser/htmlparser/tests/html/param001.html b/mozilla/parser/htmlparser/tests/html/param001.html new file mode 100644 index 00000000000..5085d70b008 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/param001.html @@ -0,0 +1,10 @@ + + + + + + param element with no attributes:
+ +
+ + diff --git a/mozilla/parser/htmlparser/tests/html/param002.html b/mozilla/parser/htmlparser/tests/html/param002.html new file mode 100644 index 00000000000..84658e60664 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/param002.html @@ -0,0 +1,14 @@ + + + + + test case for Object and Param tags. + + param element with + the name attribute, and an illeagal end tag:
+ +
+ PARAM element out side OBJECT, ignored. + + + diff --git a/mozilla/parser/htmlparser/tests/html/pre001.html b/mozilla/parser/htmlparser/tests/html/pre001.html new file mode 100644 index 00000000000..a64eef6fe27 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/pre001.html @@ -0,0 +1,9 @@ + + +Hi +
+  text line in    pre    tag.
+
+There + + \ No newline at end of file diff --git a/mozilla/parser/htmlparser/tests/html/pre002.html b/mozilla/parser/htmlparser/tests/html/pre002.html new file mode 100644 index 00000000000..e7bca5ab929 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/pre002.html @@ -0,0 +1,11 @@ + + +Only new lines in PRE block. +
+
+
+
+
+There + + \ No newline at end of file diff --git a/mozilla/parser/htmlparser/tests/html/pre003.html b/mozilla/parser/htmlparser/tests/html/pre003.html new file mode 100644 index 00000000000..e7f4647dc94 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/pre003.html @@ -0,0 +1,8 @@ + + +Empty PRE block. +
+
+There + + \ No newline at end of file diff --git a/mozilla/parser/htmlparser/tests/html/pre004.html b/mozilla/parser/htmlparser/tests/html/pre004.html new file mode 100644 index 00000000000..360c3dce93b --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/pre004.html @@ -0,0 +1,18 @@ + + +Pre tag can contain many things, inclusing P tag. + +
+First   text line in PRE block. You     can see
+the     spaces       between words      not compressed.
+

+ Text line after P tag. + bold text and italic text. + and many more. There is a empty line at the end + of PRE block. + +

+Text outside PRE block. + + + \ No newline at end of file diff --git a/mozilla/parser/htmlparser/tests/html/pre005.html b/mozilla/parser/htmlparser/tests/html/pre005.html new file mode 100644 index 00000000000..5568d8e2769 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/pre005.html @@ -0,0 +1,53 @@ + + +use a PRE tag for C or JAVA source code. +
The lt and gt signes are problematic. + + +
+  cc = 123;
+  // test lt
+  if( cc < hhh ) {
+    if(cc gh) {
+        //do womthing here;
+    }
+  }
+  if( cc <= iii ) {
+    if(cc<=yyy) {
+    if(cc<-yyy) {
+    if(cc<+yyy) {
+    if(cc<3) {
+    if(cc<33) {
+    if(cc<_abc) {
+        //do womthing here;
+    }
+  }
+  // test gt
+  if( cc > rrr ) {
+    if(cc>eee) {
+        //do womthing here;
+    }
+  }
+  if( cc >= www ) {
+    if(cc>=qqq) {
+        //do womthing here;
+    }
+  }
+  // what if the variable name is a valid tag name.
+  if( cc < B && cc > kk ) {
+    if(cc gg) {
+        //do womthing here;
+    }
+  }
+  cc = aa<>3;
+  gt = true;
+  for(a=0,gt=true; (a>0)&> a++) {
+  }
+  a = 0x0004;
+  lt = 0x0002;
+  for(; a< ) {
+  }
+
+ + \ No newline at end of file diff --git a/mozilla/parser/htmlparser/tests/html/pre006.html b/mozilla/parser/htmlparser/tests/html/pre006.html new file mode 100644 index 00000000000..a6f0d605cab --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/pre006.html @@ -0,0 +1,28 @@ +Test of PRE tag + + + +
+This      is some preformatted text.
+
+ +

Before PRE +

some        preformatted text.
+    
+ After PRE. +

+ +

Before PRE +

some     preformatted text.
+        
This     is nested preformatted (In Nav4.0, green and formatted)
+        
+ This is still preformatted? (Not in Nav4.0) +
+ After PRE. +

+ +

End of test

diff --git a/mozilla/parser/htmlparser/tests/html/pre007.html b/mozilla/parser/htmlparser/tests/html/pre007.html new file mode 100644 index 00000000000..ec0698a2232 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/pre007.html @@ -0,0 +1,12 @@ +

Here is a paragraph where the image that is +floated left is the first piece of content of the paragraph... +

+
+This is a     pre section
+Boldis    a nice thing.
+
+ +
+This is      some pre text
+la de da

More text

And more text - what is the vertical space look like? +

diff --git a/mozilla/parser/htmlparser/tests/html/pre012.html b/mozilla/parser/htmlparser/tests/html/pre012.html new file mode 100644 index 00000000000..a05f2d11f15 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/pre012.html @@ -0,0 +1,22 @@ +The following is copied from test tag002.html
+Broken tags are shown, only if no gt sign can be found. + + +ccccccc +Now wrapped with a PRE tag. +
+Broken tags are shown, only if no gt sign can be found.
+
+
+ccccccc
+
\ No newline at end of file
diff --git a/mozilla/parser/htmlparser/tests/html/pre015.html b/mozilla/parser/htmlparser/tests/html/pre015.html
new file mode 100644
index 00000000000..f07de01c753
--- /dev/null
+++ b/mozilla/parser/htmlparser/tests/html/pre015.html
@@ -0,0 +1,18 @@
+The following is copied from test tag005.html
+first line +
empty brakets are displayed as text +This +and this eat next br tag. +and another one. +Last text. +
Now wrapped with a PRE tag. +
+first line
+
empty brakets are displayed as text +This +and this eat next br tag. +and another one. +Last text. +
\ No newline at end of file diff --git a/mozilla/parser/htmlparser/tests/html/pre016.html b/mozilla/parser/htmlparser/tests/html/pre016.html new file mode 100644 index 00000000000..cfd595dce40 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/pre016.html @@ -0,0 +1,17 @@ +The following is copied from test tag006.html
+first line +
invalide tags are ignored by 4.0 +
*/ +extern nsresult +NS_NewTableCellPart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag); + +/** Create a new table caption content object
*/ +extern nsresult +NS_NewTableCaptionPart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag); + +extern nsresult +NS_NewHTMLImage(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag); + +#endif /* nsHTMLParts_h___ */ diff --git a/mozilla/layout/html/base/src/nsHTMLTagContent.cpp b/mozilla/layout/html/base/src/nsHTMLTagContent.cpp new file mode 100644 index 00000000000..50fdb672c56 --- /dev/null +++ b/mozilla/layout/html/base/src/nsHTMLTagContent.cpp @@ -0,0 +1,669 @@ +/* -*- 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 "nsHTMLTagContent.h" +#include "nsIDocument.h" +#include "nsIHTMLAttributes.h" +#include "nsIStyleRule.h" +#include "nsHTMLAtoms.h" +#include "nsStyleConsts.h" +#include "nsString.h" +#include "prprf.h" +#include "nsDOMAttributes.h" + +static NS_DEFINE_IID(kIStyleRuleIID, NS_ISTYLE_RULE_IID); +static NS_DEFINE_IID(kIDOMElementIID, NS_IDOMELEMENT_IID); +static NS_DEFINE_IID(kIScriptObjectOwner, NS_ISCRIPTOBJECTOWNER_IID); + +nsHTMLTagContent::nsHTMLTagContent() +{ +} + +nsHTMLTagContent::nsHTMLTagContent(nsIAtom* aTag) +{ + NS_PRECONDITION(nsnull != aTag, "null ptr"); + mTag = aTag; + NS_IF_ADDREF(mTag); +} + +nsHTMLTagContent::~nsHTMLTagContent() +{ + NS_IF_RELEASE(mTag); + NS_IF_RELEASE(mAttributes); +} + +nsresult nsHTMLTagContent::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + nsresult res = nsHTMLContent::QueryInterface(aIID, aInstancePtr); + if (NS_NOINTERFACE == res) { + if (aIID.Equals(kIDOMElementIID)) { + *aInstancePtr = (void*)(nsIDOMElement*)this; + AddRef(); + return NS_OK; + } + } + + return res; +} + +nsrefcnt nsHTMLTagContent::AddRef(void) +{ + return nsHTMLContent::AddRef(); +} + +nsrefcnt nsHTMLTagContent::Release(void) +{ + return nsHTMLContent::Release(); +} + +nsIAtom* nsHTMLTagContent::GetTag() const +{ + NS_IF_ADDREF(mTag); + return mTag; +} + +void nsHTMLTagContent::ToHTMLString(nsString& aBuf) const +{ + aBuf.SetLength(0); + aBuf.Append('<'); + + nsIAtom* tag = GetTag(); + if (nsnull != tag) { + nsAutoString tmp; + tag->ToString(tmp); + aBuf.Append(tmp); + } else { + aBuf.Append("?NULL"); + } + aBuf.Append('>'); +} + +void nsHTMLTagContent::SetAttribute(const nsString& aName, + const nsString& aValue) +{ + nsAutoString upper; + aName.ToUpperCase(upper); + nsIAtom* attr = NS_NewAtom(upper); + SetAttribute(attr, aValue); + NS_RELEASE(attr); +} + +nsContentAttr nsHTMLTagContent::GetAttribute(const nsString& aName, + nsString& aResult) const +{ + nsAutoString upper; + aName.ToUpperCase(upper); + nsIAtom* attr = NS_NewAtom(upper); + + nsHTMLValue value; + nsContentAttr result = GetAttribute(attr, value); + + char cbuf[20]; + nscolor color; + if (eContentAttr_HasValue == result) { + // Try subclass conversion routine first + if (eContentAttr_HasValue == AttributeToString(attr, value, aResult)) { + return result; + } + + // Provide default conversions for most everything + switch (value.GetUnit()) { + case eHTMLUnit_String: + case eHTMLUnit_Null: + value.GetStringValue(aResult); + break; + + case eHTMLUnit_Absolute: + case eHTMLUnit_Pixel: + aResult.SetLength(0); + aResult.Append(value.GetIntValue(), 10); + break; + + case eHTMLUnit_Percent: + aResult.SetLength(0); + aResult.Append(PRInt32(value.GetFloatValue() * 100.0f), 10); + break; + + case eHTMLUnit_Color: + color = nscolor(value.GetColorValue()); + PR_snprintf(cbuf, sizeof(cbuf), "#%02x%02x%02x", + NS_GET_R(color), NS_GET_G(color), NS_GET_B(color)); + aResult.SetLength(0); + aResult.Append(cbuf); + break; + + case eHTMLUnit_Enumerated: + NS_NOTREACHED("no default enumerated value to string conversion"); + result = eContentAttr_NotThere; + break; + } + } + + NS_RELEASE(attr); + return result; +} + +nsContentAttr nsHTMLTagContent::AttributeToString(nsIAtom* aAttribute, + nsHTMLValue& aValue, + nsString& aResult) const +{ + aResult.Truncate(); + return eContentAttr_NotThere; +} + +// XXX subclasses should override to parse the value string +void nsHTMLTagContent::SetAttribute(nsIAtom* aAttribute, + const nsString& aValue) +{ + if (nsnull == mAttributes) { + NS_NewHTMLAttributes(&mAttributes, this); + } + if (nsnull != mAttributes) { + mAttributes->SetAttribute(aAttribute, aValue); + } +} + +void nsHTMLTagContent::SetAttribute(nsIAtom* aAttribute, + const nsHTMLValue& aValue) +{ + if (nsnull == mAttributes) { + NS_NewHTMLAttributes(&mAttributes, this); + } + if (nsnull != mAttributes) { + mAttributes->SetAttribute(aAttribute, aValue); + } +} + +void nsHTMLTagContent::UnsetAttribute(nsIAtom* aAttribute) +{ + if (nsnull != mAttributes) { + PRInt32 count = mAttributes->UnsetAttribute(aAttribute); + if (0 == count) { + NS_RELEASE(mAttributes); + } + } +} + +nsContentAttr nsHTMLTagContent::GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aValue) const +{ + if (nsnull != mAttributes) { + return mAttributes->GetAttribute(aAttribute, aValue); + } + aValue.Reset(); + return eContentAttr_NotThere; +} + +PRInt32 nsHTMLTagContent::GetAllAttributeNames(nsISupportsArray* aArray) const +{ + if (nsnull != mAttributes) { + return mAttributes->GetAllAttributeNames(aArray); + } + return 0; +} + +PRInt32 nsHTMLTagContent::GetAttributeCount(void) const +{ + if (nsnull != mAttributes) { + return mAttributes->Count(); + } + return 0; +} + +void nsHTMLTagContent::SetID(nsIAtom* aID) +{ + if (nsnull != aID) { + if (nsnull == mAttributes) { + NS_NewHTMLAttributes(&mAttributes, this); + } + if (nsnull != mAttributes) { + mAttributes->SetID(aID); + } + } + else { + if (nsnull != mAttributes) { + PRInt32 count = mAttributes->SetID(nsnull); + if (0 == count) { + NS_RELEASE(mAttributes); + } + } + } +} + +nsIAtom* nsHTMLTagContent::GetID(void) const +{ + if (nsnull != mAttributes) { + return mAttributes->GetID(); + } + return nsnull; +} + +void nsHTMLTagContent::SetClass(nsIAtom* aClass) +{ + if (nsnull != aClass) { + if (nsnull == mAttributes) { + NS_NewHTMLAttributes(&mAttributes, this); + } + if (nsnull != mAttributes) { + mAttributes->SetClass(aClass); + } + } + else { + if (nsnull != mAttributes) { + PRInt32 count = mAttributes->SetClass(nsnull); + if (0 == count) { + NS_RELEASE(mAttributes); + } + } + } +} + +nsIAtom* nsHTMLTagContent::GetClass(void) const +{ + if (nsnull != mAttributes) { + return mAttributes->GetClass(); + } + return nsnull; +} + + +nsIStyleRule* nsHTMLTagContent::GetStyleRule(void) +{ + nsIStyleRule* result = nsnull; + + if (nsnull != mAttributes) { + mAttributes->QueryInterface(kIStyleRuleIID, (void**)&result); + } + return result; +} + +nsresult nsHTMLTagContent::GetScriptObject(JSContext *aContext, void** aScriptObject) +{ + nsresult res = NS_OK; + if (nsnull == mScriptObject) { + *aScriptObject = nsnull; + if (nsnull != mParent) { + nsIScriptObjectOwner *parent; + if (NS_OK == mParent->QueryInterface(kIScriptObjectOwner, (void**)&parent)) { + parent->GetScriptObject(aContext, aScriptObject); + NS_RELEASE(parent); + } + } + res = NS_NewScriptElement(aContext, this, (JSObject*)*aScriptObject, (JSObject**)&mScriptObject); + } + *aScriptObject = mScriptObject; + return res; +} + +nsresult nsHTMLTagContent::GetNodeType(PRInt32 *aType) +{ + *aType = nsHTMLContent::ELEMENT; + return NS_OK; +} + +nsresult nsHTMLTagContent::GetParentNode(nsIDOMNode **aNode) +{ + return nsHTMLContent::GetParentNode(aNode); +} + +nsresult nsHTMLTagContent::GetChildNodes(nsIDOMNodeIterator **aIterator) +{ + return nsHTMLContent::GetChildNodes(aIterator); +} + +nsresult nsHTMLTagContent::HasChildNodes() +{ + return nsHTMLContent::HasChildNodes(); +} + +nsresult nsHTMLTagContent::GetFirstChild(nsIDOMNode **aNode) +{ + return nsHTMLContent::GetFirstChild(aNode); +} + +nsresult nsHTMLTagContent::GetPreviousSibling(nsIDOMNode **aNode) +{ + return nsHTMLContent::GetPreviousSibling(aNode); +} + +nsresult nsHTMLTagContent::GetNextSibling(nsIDOMNode **aNode) +{ + return nsHTMLContent::GetNextSibling(aNode); +} + +nsresult nsHTMLTagContent::InsertBefore(nsIDOMNode *newChild, nsIDOMNode *refChild) +{ + return nsHTMLContent::InsertBefore(newChild, refChild); +} + +nsresult nsHTMLTagContent::ReplaceChild(nsIDOMNode *newChild, nsIDOMNode *oldChild) +{ + return nsHTMLContent::ReplaceChild(newChild, oldChild); +} + +nsresult nsHTMLTagContent::RemoveChild(nsIDOMNode *oldChild) +{ + return nsHTMLContent::RemoveChild(oldChild); +} + +nsresult nsHTMLTagContent::GetTagName(nsString &aName) +{ + NS_ASSERTION(nsnull != mTag, "no tag"); + mTag->ToString(aName); + return NS_OK; +} + +nsresult nsHTMLTagContent::GetAttributes(nsIDOMAttributeList **aAttributeList) +{ + NS_PRECONDITION(nsnull != aAttributeList, "null pointer argument"); + if (nsnull != mAttributes) { + *aAttributeList = new nsDOMAttributeList(*this); + return NS_OK; + } + + return NS_ERROR_FAILURE; +} + +nsresult nsHTMLTagContent::GetDOMAttribute(nsString &aName, nsString &aValue) +{ + GetAttribute(aName, aValue); + return NS_OK; +} + +nsresult nsHTMLTagContent::SetDOMAttribute(nsString &aName, nsString &aValue) +{ + SetAttribute(aName, aValue); + return NS_OK; +} + +nsresult nsHTMLTagContent::RemoveAttribute(nsString &aName) +{ + nsAutoString upper; + aName.ToUpperCase(upper); + nsIAtom* attr = NS_NewAtom(upper); + UnsetAttribute(attr); + return NS_OK; +} + +nsresult nsHTMLTagContent::GetAttributeNode(nsString &aName, nsIDOMAttribute **aAttribute) +{ + nsAutoString value; + if(eContentAttr_NotThere != GetAttribute(aName, value)) { + *aAttribute = new nsDOMAttribute(aName, value); + } + + return NS_OK; +} + +nsresult nsHTMLTagContent::SetAttributeNode(nsIDOMAttribute *aAttribute) +{ + NS_PRECONDITION(nsnull != aAttribute, "null attribute"); + + nsresult res = NS_ERROR_FAILURE; + + if (nsnull != aAttribute) { + nsString name, value; + res = aAttribute->GetName(name); + if (NS_OK == res) { + res = aAttribute->GetValue(value); + if (NS_OK == res) { + SetAttribute(name, value); + } + } + } + + return res; +} + +nsresult nsHTMLTagContent::RemoveAttributeNode(nsIDOMAttribute *aAttribute) +{ + NS_PRECONDITION(nsnull != aAttribute, "null attribute"); + + nsresult res = NS_ERROR_FAILURE; + + if (nsnull != aAttribute) { + nsAutoString name; + res = aAttribute->GetName(name); + if (NS_OK == res) { + nsAutoString upper; + name.ToUpperCase(upper); + nsIAtom* attr = NS_NewAtom(upper); + UnsetAttribute(attr); + } + } + + return res; +} + +nsresult nsHTMLTagContent::Normalize() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult nsHTMLTagContent::GetElementsByTagName(nsString &aName,nsIDOMNodeIterator **aIterator) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + + +//---------------------------------------------------------------------- + +// Attribute parsing utility methods + +PRBool nsHTMLTagContent::ParseEnumValue(const nsString& aValue, + EnumTable* aTable, + nsHTMLValue& aResult) +{ + while (nsnull != aTable->tag) { + if (aValue.EqualsIgnoreCase(aTable->tag)) { + aResult.Set(aTable->value, eHTMLUnit_Enumerated); + return PR_TRUE; + } + aTable++; + } + return PR_FALSE; +} + +PRBool nsHTMLTagContent::EnumValueToString(const nsHTMLValue& aValue, + EnumTable* aTable, + nsString& aResult) +{ + aResult.SetLength(0); + if (aValue.GetUnit() == eHTMLUnit_Enumerated) { + PRInt32 v = aValue.GetIntValue(); + while (nsnull != aTable->tag) { + if (aTable->value == v) { + aResult.Append(aTable->tag); + return PR_TRUE; + } + aTable++; + } + } + return PR_FALSE; +} + +// XXX check all mappings against ebina's usage +static nsHTMLTagContent::EnumTable kAlignTable[] = { + { "left", NS_STYLE_TEXT_ALIGN_LEFT }, + { "right", NS_STYLE_TEXT_ALIGN_RIGHT }, + { "texttop", NS_STYLE_VERTICAL_ALIGN_TEXT_TOP }, + { "baseline", NS_STYLE_VERTICAL_ALIGN_BASELINE }, + { "center", NS_STYLE_TEXT_ALIGN_CENTER }, + { "bottom", NS_STYLE_VERTICAL_ALIGN_BOTTOM }, + { "top", NS_STYLE_VERTICAL_ALIGN_TOP }, + { "middle", NS_STYLE_VERTICAL_ALIGN_MIDDLE }, + { "absbottom", NS_STYLE_VERTICAL_ALIGN_BOTTOM }, + { "abscenter", NS_STYLE_VERTICAL_ALIGN_MIDDLE }, + { "absmiddle", NS_STYLE_VERTICAL_ALIGN_MIDDLE }, + { 0 } +}; + +PRBool nsHTMLTagContent::ParseAlignParam(const nsString& aString, + nsHTMLValue& aResult) +{ + return ParseEnumValue(aString, kAlignTable, aResult); +} + +PRBool nsHTMLTagContent::AlignParamToString(const nsHTMLValue& aValue, + nsString& aResult) +{ + return EnumValueToString(aValue, kAlignTable, aResult); +} + +static nsHTMLTagContent::EnumTable kDivAlignTable[] = { + { "left", NS_STYLE_TEXT_ALIGN_LEFT }, + { "right", NS_STYLE_TEXT_ALIGN_RIGHT }, + { "center", NS_STYLE_TEXT_ALIGN_CENTER }, + { "justify", NS_STYLE_TEXT_ALIGN_JUSTIFY }, + { 0 } +}; + +PRBool nsHTMLTagContent::ParseDivAlignParam(const nsString& aString, + nsHTMLValue& aResult) +{ + return ParseEnumValue(aString, kDivAlignTable, aResult); +} + +PRBool nsHTMLTagContent::DivAlignParamToString(const nsHTMLValue& aValue, + nsString& aResult) +{ + return EnumValueToString(aValue, kDivAlignTable, aResult); +} + +void nsHTMLTagContent::ParseValueOrPercent(const nsString& aString, + nsHTMLValue& aResult) +{ + nsAutoString tmp(aString); + tmp.CompressWhitespace(PR_TRUE, PR_TRUE); + PRInt32 ec, val = tmp.ToInteger(&ec); + if (tmp.Last() == '%') {/* XXX not 100% compatible with ebina's code */ + if (val < 0) val = 0; + if (val > 100) val = 100; + aResult.Set(float(val)/100.0f, eHTMLUnit_Percent); + } else { + aResult.Set(val, eHTMLUnit_Absolute); + } +} + +PRBool nsHTMLTagContent::ValueOrPercentToString(const nsHTMLValue& aValue, + nsString& aResult) +{ + aResult.SetLength(0); + switch (aValue.GetUnit()) { + case eHTMLUnit_Absolute: + aResult.Append(aValue.GetIntValue(), 10); + return PR_TRUE; + case eHTMLUnit_Percent: + aResult.Append(PRInt32(aValue.GetFloatValue() * 100.0f), 10); + aResult.Append('%'); + return PR_TRUE; + } + return PR_FALSE; +} + +void nsHTMLTagContent::ParseValue(const nsString& aString, PRInt32 aMin, + nsHTMLValue& aResult) +{ + PRInt32 ec, val = aString.ToInteger(&ec); + if (val < aMin) val = aMin; + aResult.Set(val, eHTMLUnit_Absolute); +} + +void nsHTMLTagContent::ParseValue(const nsString& aString, PRInt32 aMin, + PRInt32 aMax, + nsHTMLValue& aResult) +{ + PRInt32 ec, val = aString.ToInteger(&ec); + if (val < aMin) val = aMin; + if (val > aMax) val = aMax; + aResult.Set(val, eHTMLUnit_Absolute); +} + +PRBool nsHTMLTagContent::ParseImageProperty(nsIAtom* aAttribute, + const nsString& aString, + nsHTMLValue& aResult) +{ + if ((aAttribute == nsHTMLAtoms::width) || + (aAttribute == nsHTMLAtoms::height)) { + ParseValueOrPercent(aString, aResult); + return PR_TRUE; + } else if ((aAttribute == nsHTMLAtoms::border) || + (aAttribute == nsHTMLAtoms::hspace) || + (aAttribute == nsHTMLAtoms::vspace)) { + ParseValue(aString, 0, aResult); + return PR_TRUE; + } + return PR_FALSE; +} + +PRBool nsHTMLTagContent::ImagePropertyToString(nsIAtom* aAttribute, + const nsHTMLValue& aValue, + nsString& aResult) +{ + if ((aAttribute == nsHTMLAtoms::width) || + (aAttribute == nsHTMLAtoms::height) || + (aAttribute == nsHTMLAtoms::border) || + (aAttribute == nsHTMLAtoms::hspace) || + (aAttribute == nsHTMLAtoms::vspace)) { + return ValueOrPercentToString(aValue, aResult); + } + return PR_FALSE; +} + +PRBool nsHTMLTagContent::ParseColor(const nsString& aString, + nsHTMLValue& aResult) +{ + char cbuf[40]; + aString.ToCString(cbuf, sizeof(cbuf)); + if (aString.Length() > 0) { + nscolor color; + if (cbuf[0] == '#') { + if (NS_HexToRGB(cbuf, &color)) { + aResult.Set(color); + return PR_TRUE; + } + } else { + if (NS_ColorNameToRGB(cbuf, &color)) { + aResult.Set(aString); + return PR_TRUE; + } + } + } + + // Illegal values are mapped to 0 + aResult.Set(0, eHTMLUnit_Absolute); + return PR_FALSE; +} + +PRBool nsHTMLTagContent::ColorToString(const nsHTMLValue& aValue, + nsString& aResult) +{ + if (aValue.GetUnit() == eHTMLUnit_Absolute) { + nscolor v = (nscolor) aValue.GetIntValue(); + char buf[10]; + PR_snprintf(buf, sizeof(buf), "#%02x%02x%02x", + NS_GET_R(v), NS_GET_G(v), NS_GET_B(v)); + aResult.SetLength(0); + aResult.Append(buf); + return PR_TRUE; + } + if (aValue.GetUnit() == eHTMLUnit_String) { + aValue.GetStringValue(aResult); + return PR_TRUE; + } + return PR_FALSE; +} diff --git a/mozilla/layout/html/base/src/nsHTMLTagContent.h b/mozilla/layout/html/base/src/nsHTMLTagContent.h new file mode 100644 index 00000000000..0bc1507088d --- /dev/null +++ b/mozilla/layout/html/base/src/nsHTMLTagContent.h @@ -0,0 +1,186 @@ +/* -*- 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. + */ +#ifndef nsHTMLTagContent_h___ +#define nsHTMLTagContent_h___ + +#include "nsHTMLContent.h" +#include "nsIDOMElement.h" + +class nsIHTMLAttributes; + +/** + * Base class for tagged html content objects, holds attributes. + */ +class nsHTMLTagContent : public nsHTMLContent, public nsIDOMElement { +public: + /** + * Return nsnull if no tag set. + */ + virtual nsIAtom* GetTag() const; + + /** + * Translate the content object into it's source html format + */ + virtual void ToHTMLString(nsString& out) const; + + /** + * Generic implementation of SetAttribute that translates aName into + * an uppercase'd atom and invokes SetAttribute(atom, aValue). + */ + virtual void SetAttribute(const nsString& aName, const nsString& aValue); + + /** + * Generic implementation of GetAttribute that knows how to map + * nsHTMLValue's to string's. Note that it cannot map enumerated + * values directly, but will use AttributeToString to supply a + * conversion. Subclasses must override AttributeToString to map + * enumerates to strings and return eContentAttr_HasValue when a + * conversion is succesful. Subclasses should also override this + * method if the default string conversions used don't apply + * correctly to the given attribute. + */ + virtual nsContentAttr GetAttribute(const nsString& aName, + nsString& aResult) const; + + virtual void SetAttribute(nsIAtom* aAttribute, const nsString& aValue); + + virtual void SetAttribute(nsIAtom* aAttribute, const nsHTMLValue& aValue); + virtual void UnsetAttribute(nsIAtom* aAttribute); + + /** + * Subclasses must override to fill the value object for values that + * are not stored in mAttributes. If the returned value is of an + * enumerated type then the subclass must also override the + * AttributeToString method (see the comment on the other GetAttribute + * method) + */ + virtual nsContentAttr GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aValue) const; + + virtual PRInt32 GetAllAttributeNames(nsISupportsArray* aArray) const; + virtual PRInt32 GetAttributeCount(void) const; + + virtual void SetID(nsIAtom* aID); + virtual nsIAtom* GetID(void) const; + virtual void SetClass(nsIAtom* aClass); // XXX this will have to change for CSS2 + virtual nsIAtom* GetClass(void) const; // XXX this will have to change for CSS2 + + virtual nsIStyleRule* GetStyleRule(void); + + // nsIScriptObjectOwner interface + virtual nsresult GetScriptObject(JSContext *aContext, void** aScriptObject); + + // nsIDOMElement interface + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(void); + NS_IMETHOD_(nsrefcnt) Release(void); + virtual nsresult GetNodeType(PRInt32 *aType); + virtual nsresult GetParentNode(nsIDOMNode **aNode); + virtual nsresult GetChildNodes(nsIDOMNodeIterator **aIterator); + virtual nsresult HasChildNodes(); + virtual nsresult GetFirstChild(nsIDOMNode **aNode); + virtual nsresult GetPreviousSibling(nsIDOMNode **aNode); + virtual nsresult GetNextSibling(nsIDOMNode **aNode); + virtual nsresult InsertBefore(nsIDOMNode *newChild, nsIDOMNode *refChild); + virtual nsresult ReplaceChild(nsIDOMNode *newChild, nsIDOMNode *oldChild); + virtual nsresult RemoveChild(nsIDOMNode *oldChild); + virtual nsresult GetTagName(nsString &aName); + virtual nsresult GetAttributes(nsIDOMAttributeList **aAttributeList); + virtual nsresult GetDOMAttribute(nsString &aName, nsString &aValue); + virtual nsresult SetDOMAttribute(nsString &aName, nsString &aValue); + virtual nsresult RemoveAttribute(nsString &aName); + virtual nsresult GetAttributeNode(nsString &aName, nsIDOMAttribute **aAttribute); + virtual nsresult SetAttributeNode(nsIDOMAttribute *aAttribute); + virtual nsresult RemoveAttributeNode(nsIDOMAttribute *aAttribute); + virtual nsresult GetElementsByTagName(nsString &aName,nsIDOMNodeIterator **aIterator); + virtual nsresult Normalize(); + + // Utility routines for making attribute parsing easier + + struct EnumTable { + const char* tag; + PRInt32 value; + }; + + static PRBool ParseEnumValue(const nsString& aValue, + EnumTable* aTable, + nsHTMLValue& aResult); + + static PRBool EnumValueToString(const nsHTMLValue& aValue, + EnumTable* aTable, + nsString& aResult); + + static void ParseValueOrPercent(const nsString& aString, + nsHTMLValue& aResult); + + static PRBool ValueOrPercentToString(const nsHTMLValue& aValue, + nsString& aResult); + + static void ParseValue(const nsString& aString, PRInt32 aMin, + nsHTMLValue& aResult); + + static void ParseValue(const nsString& aString, PRInt32 aMin, PRInt32 aMax, + nsHTMLValue& aResult); + + static PRBool ParseColor(const nsString& aString, nsHTMLValue& aResult); + + static PRBool ColorToString(const nsHTMLValue& aValue, + nsString& aResult); + + /** + * Parse width, height, border, hspace, vspace. Returns PR_TRUE if + * the aAttribute is one of the listed attributes. + */ + static PRBool ParseImageProperty(nsIAtom* aAttribute, + const nsString& aString, + nsHTMLValue& aResult); + + static PRBool ImagePropertyToString(nsIAtom* aAttribute, + const nsHTMLValue& aValue, + nsString& aResult); + + static PRBool ParseAlignParam(const nsString& aString, nsHTMLValue& aResult); + + static PRBool AlignParamToString(const nsHTMLValue& aValue, + nsString& aResult); + + static PRBool ParseDivAlignParam(const nsString& aString, nsHTMLValue& aRes); + + static PRBool DivAlignParamToString(const nsHTMLValue& aValue, + nsString& aResult); + +protected: + nsHTMLTagContent(); + + nsHTMLTagContent(nsIAtom* aTag); + + virtual ~nsHTMLTagContent(); + + /** + * Helper method used by GetAttribute to map an attribute + * to a string value. + */ + virtual nsContentAttr AttributeToString(nsIAtom* aAttribute, + nsHTMLValue& aValue, + nsString& aResult) const; + + nsIAtom* mTag; + nsIHTMLAttributes* mAttributes; +}; + +#endif /* nsHTMLTagContent_h___ */ diff --git a/mozilla/layout/html/base/src/nsHTMLTagIDs.h b/mozilla/layout/html/base/src/nsHTMLTagIDs.h new file mode 100644 index 00000000000..52645a0375c --- /dev/null +++ b/mozilla/layout/html/base/src/nsHTMLTagIDs.h @@ -0,0 +1,92 @@ +/* Do not edit - generated by genhash.pl */ +#define TAG_A 0 +#define TAG_ADDRESS 1 +#define TAG_APPLET 2 +#define TAG_AREA 3 +#define TAG_B 4 +#define TAG_BASE 5 +#define TAG_BASEFONT 6 +#define TAG_BIG 7 +#define TAG_BLINK 8 +#define TAG_BLOCKQUOTE 9 +#define TAG_BODY 10 +#define TAG_BR 11 +#define TAG_CAPTION 12 +#define TAG_CENTER 13 +#define TAG_CERTIFICATE 14 +#define TAG_CITE 15 +#define TAG_CODE 16 +#define TAG_DD 17 +#define TAG_DIR 18 +#define TAG_DIV 19 +#define TAG_DL 20 +#define TAG_DT 21 +#define TAG_EM 22 +#define TAG_EMBED 23 +#define TAG_FONT 24 +#define TAG_FORM 25 +#define TAG_FRAME 26 +#define TAG_FRAMESET 27 +#define TAG_H1 28 +#define TAG_H2 29 +#define TAG_H3 30 +#define TAG_H4 31 +#define TAG_H5 32 +#define TAG_H6 33 +#define TAG_HEAD 34 +#define TAG_HR 35 +#define TAG_HTML 36 +#define TAG_I 37 +#define TAG_IFRAME 38 +#define TAG_ILAYER 39 +#define TAG_IMG 40 +#define TAG_INPUT 41 +#define TAG_ISINDEX 42 +#define TAG_KBD 43 +#define TAG_KEYGEN 44 +#define TAG_LAYER 45 +#define TAG_LI 46 +#define TAG_LINK 47 +#define TAG_LISTING 48 +#define TAG_MAP 49 +#define TAG_MENU 50 +#define TAG_META 51 +#define TAG_MULTICOL 52 +#define TAG_NOBR 53 +#define TAG_NOEMBED 54 +#define TAG_NOFRAMES 55 +#define TAG_NOLAYER 56 +#define TAG_NOSCRIPT 57 +#define TAG_OBJECT 58 +#define TAG_OL 59 +#define TAG_OPTION 60 +#define TAG_P 61 +#define TAG_PARAM 62 +#define TAG_PLAINTEXT 63 +#define TAG_PRE 64 +#define TAG_S 65 +#define TAG_SAMP 66 +#define TAG_SCRIPT 67 +#define TAG_SELECT 68 +#define TAG_SERVER 69 +#define TAG_SMALL 70 +#define TAG_SPACER 71 +#define TAG_SPAN 72 +#define TAG_STRIKE 73 +#define TAG_STRONG 74 +#define TAG_STYLE 75 +#define TAG_SUB 76 +#define TAG_SUP 77 +#define TAG_TABLE 78 +#define TAG_TD 79 +#define TAG_TEXTAREA 80 +#define TAG_TH 81 +#define TAG_TITLE 82 +#define TAG_TR 83 +#define TAG_TT 84 +#define TAG_U 85 +#define TAG_UL 86 +#define TAG_VAR 87 +#define TAG_WBR 88 +#define TAG_XMP 89 +#define TAG_MAX 90 diff --git a/mozilla/layout/html/base/src/nsHTMLTags.cpp b/mozilla/layout/html/base/src/nsHTMLTags.cpp new file mode 100644 index 00000000000..ecf33024cd2 --- /dev/null +++ b/mozilla/layout/html/base/src/nsHTMLTags.cpp @@ -0,0 +1,377 @@ + +/* +** This is a generated file, do not edit it. This file is created by +** genhash.pl +*/ + +#include "plstr.h" +#include "nsHTMLTags.h" +#define TOTAL_KEYWORDS 90 +#define MIN_WORD_LENGTH 1 +#define MAX_WORD_LENGTH 11 +#define MIN_HASH_VALUE 1 +#define MAX_HASH_VALUE 264 +/* maximum key range = 264, duplicates = 0 */ + + +struct StaticNameTable { + char* tag; + PRInt32 id; +}; + +static const unsigned char kLowerLookup[256] = { + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, + 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, + 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, + 64, + 97,98,99,100,101,102,103,104,105,106,107,108,109, + 110,111,112,113,114,115,116,117,118,119,120,121,122, + + 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, + + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 +}; + +#define MYLOWER(x) kLowerLookup[((x) & 0x7f)] + +/** + * Map a name to an ID or -1 + */ +PRInt32 nsHTMLTags::LookupName(const char* str) +{ + static unsigned short asso_values[] = + { + 265, 265, 265, 265, 265, 265, 265, 265, 265, 265, + 265, 265, 265, 265, 265, 265, 265, 265, 265, 265, + 265, 265, 265, 265, 265, 265, 265, 265, 265, 265, + 265, 265, 265, 265, 265, 265, 265, 265, 265, 265, + 265, 265, 265, 265, 265, 265, 265, 265, 265, 5, + 20, 65, 70, 75, 80, 265, 265, 265, 265, 265, + 265, 265, 265, 265, 265, 265, 265, 265, 265, 265, + 265, 265, 265, 265, 265, 265, 265, 265, 265, 265, + 265, 265, 265, 265, 265, 265, 265, 265, 265, 265, + 265, 265, 265, 265, 265, 265, 265, 0, 35, 100, + 40, 0, 15, 60, 30, 40, 0, 45, 10, 40, + 0, 120, 45, 265, 0, 15, 5, 85, 15, 0, + 10, 0, 265, 265, 265, 265, 265, 265, + }; + static unsigned char lengthtable[] = + { + 0, 1, 0, 0, 4, 0, 0, 2, 0, 0, 0, 0, 0, 0, + 0, 5, 0, 2, 3, 0, 5, 6, 0, 8, 0, 5, 6, 0, + 8, 0, 0, 1, 2, 0, 0, 0, 6, 2, 3, 0, 0, 0, + 2, 0, 0, 5, 0, 0, 3, 4, 0, 6, 2, 0, 4, 5, + 6, 0, 0, 0, 0, 6, 2, 8, 4, 0, 6, 2, 0, 9, + 5, 1, 2, 0, 4, 0, 0, 0, 0, 0, 0, 1, 2, 3, + 0, 0, 6, 2, 0, 4, 5, 1, 2, 0, 0, 5, 0, 0, + 0, 4, 0, 6, 7, 0, 4, 0, 6, 2, 0, 0, 0, 11, + 7, 3, 0, 0, 0, 0, 0, 0, 5, 0, 2, 0, 0, 0, + 6, 0, 0, 4, 0, 0, 7, 3, 0, 5, 0, 7, 0, 0, + 0, 0, 2, 3, 4, 0, 0, 0, 8, 4, 0, 0, 7, 8, + 0, 0, 0, 0, 8, 4, 0, 0, 2, 3, 0, 0, 6, 7, + 0, 0, 0, 1, 2, 3, 0, 10, 6, 0, 0, 4, 0, 0, + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0, + 0, 0, 3, 4, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, + }; + static struct StaticNameTable wordlist[] = + { + {"",}, + {"a", 0}, + {"",}, {"",}, + {"area", 3}, + {"",}, {"",}, + {"tr", 83}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"layer", 45}, + {"",}, + {"tt", 84}, + {"var", 87}, + {"",}, + {"frame", 26}, + {"server", 69}, + {"",}, + {"textarea", 80}, + {"",}, + {"style", 75}, + {"strike", 73}, + {"",}, + {"frameset", 27}, + {"",}, {"",}, + {"s", 65}, + {"hr", 35}, + {"",}, {"",}, {"",}, + {"select", 68}, + {"br", 11}, + {"wbr", 88}, + {"",}, {"",}, {"",}, + {"h1", 28}, + {"",}, {"",}, + {"table", 78}, + {"",}, {"",}, + {"pre", 64}, + {"meta", 51}, + {"",}, + {"keygen", 44}, + {"dt", 21}, + {"",}, + {"base", 5}, + {"title", 82}, + {"ilayer", 39}, + {"",}, {"",}, {"",}, {"",}, + {"iframe", 38}, + {"dl", 20}, + {"basefont", 6}, + {"span", 72}, + {"",}, + {"spacer", 71}, + {"th", 81}, + {"",}, + {"plaintext", 63}, + {"small", 70}, + {"b", 4}, + {"h2", 29}, + {"",}, + {"head", 34}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"i", 37}, + {"em", 22}, + {"dir", 18}, + {"",}, {"",}, + {"strong", 74}, + {"td", 79}, + {"",}, + {"html", 36}, + {"param", 62}, + {"p", 61}, + {"li", 46}, + {"",}, {"",}, + {"input", 41}, + {"",}, {"",}, {"",}, + {"link", 47}, + {"",}, + {"applet", 2}, + {"address", 1}, + {"",}, + {"samp", 66}, + {"",}, + {"center", 13}, + {"ul", 86}, + {"",}, {"",}, {"",}, + {"certificate", 14}, + {"isindex", 42}, + {"div", 19}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"embed", 23}, + {"",}, + {"dd", 17}, + {"",}, {"",}, {"",}, + {"script", 67}, + {"",}, {"",}, + {"menu", 50}, + {"",}, {"",}, + {"listing", 48}, + {"map", 49}, + {"",}, + {"blink", 8}, + {"",}, + {"nolayer", 56}, + {"",}, {"",}, {"",}, {"",}, + {"ol", 59}, + {"xmp", 89}, + {"font", 24}, + {"",}, {"",}, {"",}, + {"noscript", 57}, + {"cite", 15}, + {"",}, {"",}, + {"caption", 12}, + {"multicol", 52}, + {"",}, {"",}, {"",}, {"",}, + {"noframes", 55}, + {"nobr", 53}, + {"",}, {"",}, + {"h3", 30}, + {"kbd", 43}, + {"",}, {"",}, + {"object", 58}, + {"noembed", 54}, + {"",}, {"",}, {"",}, + {"u", 85}, + {"h4", 31}, + {"sub", 76}, + {"",}, + {"blockquote", 9}, + {"option", 60}, + {"",}, {"",}, + {"form", 25}, + {"",}, {"",}, + {"h5", 32}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"h6", 33}, + {"sup", 77}, + {"",}, {"",}, {"",}, {"",}, + {"big", 7}, + {"body", 10}, + {"",}, {"",}, {"",}, + {"img", 40}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"code", 16}, + }; + + if (str != NULL) { + int len = PL_strlen(str); + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) { + register int hval = len; + + switch (hval) + { + default: + case 3: + hval += asso_values[MYLOWER(str[2])]; + case 2: + hval += asso_values[MYLOWER(str[1])]; + case 1: + hval += asso_values[MYLOWER(str[0])]; + break; + } + hval += asso_values[MYLOWER(str[len - 1])]; + if (hval <= MAX_HASH_VALUE && hval >= MIN_HASH_VALUE) { + if (len == lengthtable[hval]) { + register const char *tag = wordlist[hval].tag; + + /* + ** While not at the end of the string, if they ever differ + ** they are not equal. We know "tag" is already lower case. + */ + while ((*tag != '\0')&&(*str != '\0')) { + if (*tag != (char) MYLOWER(*str)) { + return -1; + } + tag++; + str++; + } + + /* + ** One of the strings has ended, if they are both ended, then they + ** are equal, otherwise not. + */ + if ((*tag == '\0')&&(*str == '\0')) { + return wordlist[hval].id; + } + } + } + } + } + return -1; +} + +const nsHTMLTags::NameTableEntry nsHTMLTags::kNameTable[] = { + { "a", 0 }, + { "address", 1 }, + { "applet", 2 }, + { "area", 3 }, + { "b", 4 }, + { "base", 5 }, + { "basefont", 6 }, + { "big", 7 }, + { "blink", 8 }, + { "blockquote", 9 }, + { "body", 10 }, + { "br", 11 }, + { "caption", 12 }, + { "center", 13 }, + { "certificate", 14 }, + { "cite", 15 }, + { "code", 16 }, + { "dd", 17 }, + { "dir", 18 }, + { "div", 19 }, + { "dl", 20 }, + { "dt", 21 }, + { "em", 22 }, + { "embed", 23 }, + { "font", 24 }, + { "form", 25 }, + { "frame", 26 }, + { "frameset", 27 }, + { "h1", 28 }, + { "h2", 29 }, + { "h3", 30 }, + { "h4", 31 }, + { "h5", 32 }, + { "h6", 33 }, + { "head", 34 }, + { "hr", 35 }, + { "html", 36 }, + { "i", 37 }, + { "iframe", 38 }, + { "ilayer", 39 }, + { "img", 40 }, + { "input", 41 }, + { "isindex", 42 }, + { "kbd", 43 }, + { "keygen", 44 }, + { "layer", 45 }, + { "li", 46 }, + { "link", 47 }, + { "listing", 48 }, + { "map", 49 }, + { "menu", 50 }, + { "meta", 51 }, + { "multicol", 52 }, + { "nobr", 53 }, + { "noembed", 54 }, + { "noframes", 55 }, + { "nolayer", 56 }, + { "noscript", 57 }, + { "object", 58 }, + { "ol", 59 }, + { "option", 60 }, + { "p", 61 }, + { "param", 62 }, + { "plaintext", 63 }, + { "pre", 64 }, + { "s", 65 }, + { "samp", 66 }, + { "script", 67 }, + { "select", 68 }, + { "server", 69 }, + { "small", 70 }, + { "spacer", 71 }, + { "span", 72 }, + { "strike", 73 }, + { "strong", 74 }, + { "style", 75 }, + { "sub", 76 }, + { "sup", 77 }, + { "table", 78 }, + { "td", 79 }, + { "textarea", 80 }, + { "th", 81 }, + { "title", 82 }, + { "tr", 83 }, + { "tt", 84 }, + { "u", 85 }, + { "ul", 86 }, + { "var", 87 }, + { "wbr", 88 }, + { "xmp", 89 }, +}; diff --git a/mozilla/layout/html/base/src/nsHTMLTags.h b/mozilla/layout/html/base/src/nsHTMLTags.h new file mode 100644 index 00000000000..4c294cf87ad --- /dev/null +++ b/mozilla/layout/html/base/src/nsHTMLTags.h @@ -0,0 +1,40 @@ +/* -*- 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. + */ +#ifndef nsHTMLTags_h___ +#define nsHTMLTags_h___ + +#include "nslayout.h" +#include "nsHTMLTagIDs.h" + +class NS_LAYOUT nsHTMLTags { +public: + // Given a null terminated string of 7 bit characters, return the + // tag id (see nsHTMLTagIDs.h) for the tag or -1 if the tag is not + // known. The lookup function uses a perfect hash. + static PRInt32 LookupName(const char* str); + + struct NameTableEntry { + const char* name; + PRInt32 id; + }; + + // A table whose index is the tag id (from LookupName) + static const NameTableEntry kNameTable[]; +}; + +#endif /* nsHTMLTags_h___ */ diff --git a/mozilla/layout/html/base/src/nsIAnchoredItems.h b/mozilla/layout/html/base/src/nsIAnchoredItems.h new file mode 100644 index 00000000000..2a754f6eb2b --- /dev/null +++ b/mozilla/layout/html/base/src/nsIAnchoredItems.h @@ -0,0 +1,53 @@ +/* -*- 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. + */ +#ifndef nsIAnchoredItems_h___ +#define nsIAnchoredItems_h___ + +#include +#include "nsISupports.h" + +// IID for the nsIAnchoredItems interface {7327A0A0-BC8D-11d1-8539-00A02468FAB6} +#define NS_IANCHOREDITEMS_IID \ +{ 0x7327a0a0, 0xbc8d, 0x11d1, \ + {0x85, 0x39, 0x0, 0xa0, 0x24, 0x68, 0xfa, 0xb6}} + +/** + * An interface for managing anchored items. Note that this interface is not + * an nsISupports interface, and therefore you cannot QueryInterface() back + */ +class nsIAnchoredItems +{ +public: + enum AnchoringPosition {anHTMLFloater}; + + /** + * Request to add an anchored item to this geometric parent. This is for handling + * anchored items that are not displayed inline (at the current point). + */ + virtual void AddAnchoredItem(nsIFrame* aAnchoredItem, + AnchoringPosition aPosition, + nsIFrame* aContainer) = 0; + + /** + * Called to remove an anchored item, most likely because the associated + * piece of content has been removed. + **/ + virtual void RemoveAnchoredItem(nsIFrame* aAnchoredItem) = 0; +}; + +#endif /* nsIAnchoredItems_h___ */ diff --git a/mozilla/layout/html/base/src/nsIFloaterContainer.h b/mozilla/layout/html/base/src/nsIFloaterContainer.h new file mode 100644 index 00000000000..e0f84f206e2 --- /dev/null +++ b/mozilla/layout/html/base/src/nsIFloaterContainer.h @@ -0,0 +1,63 @@ +/* -*- 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. + */ +#ifndef nsIFloaterContainer_h___ +#define nsIFloaterContainer_h___ + +#include +class PlaceholderFrame; +class nsIPresContext; + +// IID for the nsIFloaterContainer interface {5A305EE0-CB55-11d1-8556-00A02468FAB6} +#define NS_IFLOATERCONTAINER_IID \ +{ 0x5a305ee0, 0xcb55, 0x11d1, \ + {0x85, 0x56, 0x0, 0xa0, 0x24, 0x68, 0xfa, 0xb6}} + +/** + * An interface for communicating with the enclosing block-level container + * about floating elements. Note that this interface is not an nsISupports + * interface, and therefore you cannot QueryInterface() back + */ +class nsIFloaterContainer +{ +public: + /** + * Notification of a newly created floating element. + * + * @param aFloater the floating element + * @param aPlaceholder the placeholder frame associated with the floating + * element. + */ + virtual PRBool AddFloater(nsIPresContext* aPresContext, + nsIFrame* aFloater, + PlaceholderFrame* aPlaceholder) = 0; + + /** + * Call to place the floating element, because the placeholder frame has been + * reflowed. + * + * XXX This is kind of hokey and unreliable, because it relies on the placeholder + * getting reflowed. That won't necessarily happen if its geometric parent just + * decides to move it... It would probably be better if the implementor of this + * interface managed the tracking of the placeholder within the containing line + **/ + virtual void PlaceFloater(nsIPresContext* aPresContext, + nsIFrame* aFloater, + PlaceholderFrame* aPlaceholder) = 0; +}; + +#endif /* nsIFloaterContainer_h___ */ diff --git a/mozilla/layout/html/base/src/nsIHTMLContent.h b/mozilla/layout/html/base/src/nsIHTMLContent.h new file mode 100644 index 00000000000..339132b4a31 --- /dev/null +++ b/mozilla/layout/html/base/src/nsIHTMLContent.h @@ -0,0 +1,89 @@ +/* -*- 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. + */ +#ifndef nsIHTMLContent_h___ +#define nsIHTMLContent_h___ + +#include "nsIContent.h" +#include "nsHTMLValue.h" +class nsString; +class nsIFrame; +class nsISupportsArray; +class nsIStyleRule; +class nsIStyleContext; +class nsIPresContext; + +// IID for the nsIHTMLContent class +#define NS_IHTMLCONTENT_IID \ +{ 0xb9e110b0, 0x94d6, 0x11d1, \ + {0x89, 0x5c, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } + +// Abstract interface for all html content +class nsIHTMLContent : public nsIContent { +public: + /** + * If this html content is a container, then compact asks it to minimize + * it's storage usage. + */ + virtual void Compact() = 0; + + virtual void SetAttribute(const nsString& aName, const nsString& aValue) = 0; + virtual void SetAttribute(nsIAtom* aAttribute, const nsString& aValue) = 0; + virtual void SetAttribute(nsIAtom* aAttribute, + const nsHTMLValue& aValue=nsHTMLValue::kNull) = 0; + + virtual void UnsetAttribute(nsIAtom* aAttribute) = 0; + + virtual nsContentAttr GetAttribute(const nsString& aName, + nsString& aResult) const = 0; + virtual nsContentAttr GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aValue) const = 0; + virtual PRInt32 GetAllAttributeNames(nsISupportsArray* aArray) const = 0; + virtual PRInt32 GetAttributeCount(void) const = 0; + + virtual void SetID(nsIAtom* aID) = 0; + virtual nsIAtom* GetID(void) const = 0; + virtual void SetClass(nsIAtom* aClass) = 0; // XXX this will have to change for CSS2 + virtual nsIAtom* GetClass(void) const = 0; // XXX this will have to change for CSS2 + + virtual nsIStyleRule* GetStyleRule(void) = 0; + + virtual void MapAttributesInto(nsIStyleContext* aContext, + nsIPresContext* aPresContext) = 0; + + /** + * Translate this piece of content to html. Note that this only + * translates this content object, not any children it might + * have. The caller is responsible for recursing down the + * hierarchy. + */ + // XXX add in output character set information so that we know how + // to encode non 7 bit characters + virtual void ToHTMLString(nsString& aResult) const = 0; + + virtual void ToHTML(FILE* out) const = 0; + + /** + * Used by the html content's delegate to create a frame + * for the content. + */ + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) = 0; +}; + +#endif /* nsIHTMLContent_h___ */ diff --git a/mozilla/layout/html/base/src/nsIHTMLFrameType.h b/mozilla/layout/html/base/src/nsIHTMLFrameType.h new file mode 100644 index 00000000000..c009fae04f0 --- /dev/null +++ b/mozilla/layout/html/base/src/nsIHTMLFrameType.h @@ -0,0 +1,41 @@ +/* -*- 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. + */ +#ifndef nsIHTMLFrameType_h___ +#define nsIHTMLFrameType_h___ + +#include "nsISupports.h" + +enum nsHTMLFrameType { + eHTMLFrame_Block, +}; + +// Interface for nsIHTMLFrameType +#define NS_IHTMLFRAMETYPE_IID \ +{ /* 0e2554e0-b2c8-11d1-9328-00805f8add32 */ \ + 0x0e2554e0, 0xb2c8, 0x11d1, \ + {0x93, 0x28, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +// IHTMLFrameType interface. Note that this interface is not an +// nsISupports interface and therefore you cannot queryinterface back +// to the original object. +class nsIHTMLFrameType { +public: + virtual nsHTMLFrameType GetFrameType() const = 0; +}; + +#endif /* nsIHTMLFrameType_h___ */ diff --git a/mozilla/layout/html/base/src/nsIImageMap.h b/mozilla/layout/html/base/src/nsIImageMap.h new file mode 100644 index 00000000000..58581ddcbb4 --- /dev/null +++ b/mozilla/layout/html/base/src/nsIImageMap.h @@ -0,0 +1,78 @@ +/* -*- 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. + */ +#ifndef nsIImageMap_h___ +#define nsIImageMap_h___ + +#include "nslayout.h" +#include "nsISupports.h" +#include "nsCoord.h" +class nsIAtom; +class nsIPresContext; +class nsIRenderingContext; +class nsIURL; +class nsString; + +/* db6ca200-d0a6-11d1-89b1-006008911b81 */ +#define NS_IIMAGEMAP_IID \ +{0xdb6ca200, 0xd0a6, 0x11d1, {0x89, 0xb1, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81}} + +class nsIImageMap : public nsISupports { +public: + NS_IMETHOD SetName(const nsString& aMapName) = 0; + + NS_IMETHOD GetName(nsString& aResult) = 0; + + NS_IMETHOD AddArea(const nsString& aBaseURL, + const nsString& aShape, + const nsString& aCoords, + const nsString& aHREF, + const nsString& aTarget, + const nsString& aAltText, + PRBool aSuppress) = 0; + + /** + * See if the given aX,aY pixel coordinates are in the image + * map. If they are then NS_OK is returned and aAbsURL, aTarget, + * aAltText, aSuppress are filled in with the values from the + * underlying area tag. If the coordinates are not in the map + * then NS_NOT_INSIDE is returned. + */ + NS_IMETHOD IsInside(nscoord aX, nscoord aY, + nsIURL* aDocURL, + nsString& aAbsURL, + nsString& aTarget, + nsString& aAltText, + PRBool* aSuppress) = 0; + + /** + * See if the given aX,aY pixel coordinates are in the image + * map. If they are then NS_OK is returned otherwise NS_NOT_INSIDE + * is returned. + */ + NS_IMETHOD IsInside(nscoord aX, nscoord aY) = 0; + + NS_IMETHOD Draw(nsIPresContext& aCX, nsIRenderingContext& aRC) = 0; +}; + +// XXX get an error space to alloc from +#define NS_NOT_INSIDE 1 + +extern NS_HTML nsresult NS_NewImageMap(nsIImageMap** aInstancePtrResult, + nsIAtom* aAtom); + +#endif /* nsIImageMap_h___ */ diff --git a/mozilla/layout/html/base/src/nsImageMap.cpp b/mozilla/layout/html/base/src/nsImageMap.cpp new file mode 100644 index 00000000000..3bca969fa62 --- /dev/null +++ b/mozilla/layout/html/base/src/nsImageMap.cpp @@ -0,0 +1,710 @@ +/* -*- 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 "nsIImageMap.h" +#include "nsString.h" +#include "nsVoidArray.h" +#include "nsCoord.h" +#include "nsIRenderingContext.h" +#include "nsIPresContext.h" +#include "nsIURL.h" + +#undef SCALE +#define SCALE(a,b) nscoord((a) * (b)) + +class Area { +public: + Area(const nsString& aBaseURL, const nsString& aHREF, + const nsString& aTarget, const nsString& aAltText, + PRBool aSuppress); + virtual ~Area(); + + void ParseCoords(const nsString& aSpec); + + virtual PRBool IsInside(nscoord x, nscoord y) = 0; + virtual void Draw(nsIPresContext& aCX, + nsIRenderingContext& aRC) = 0; + virtual void GetShapeName(nsString& aResult) = 0; + + void ToHTML(nsString& aResult); + + const nsString& GetBase() const { return mBase; } + const nsString& GetHREF() const { return mHREF; } + const nsString& GetTarget() const { return mTarget; } + const nsString& GetAltText() const { return mAltText; } + PRBool GetSuppress() const { return mSuppressFeedback; } + + nsString mBase; + nsString mHREF; + nsString mTarget; + nsString mAltText; + nscoord* mCoords; + PRInt32 mNumCoords; + PRBool mSuppressFeedback; +}; + +Area::Area(const nsString& aBaseURL, const nsString& aHREF, + const nsString& aTarget, const nsString& aAltText, + PRBool aSuppress) + : mBase(aBaseURL), mHREF(aHREF), mTarget(aTarget), mAltText(aAltText), + mSuppressFeedback(aSuppress) +{ + mCoords = nsnull; + mNumCoords = 0; +} + +Area::~Area() +{ + delete [] mCoords; +} + +// XXX move into nsCRT +#define XP_IS_SPACE(_ch) \ + (((_ch) == ' ') || ((_ch) == '\t') || ((_ch) == '\r') || ((_ch) == '\n')) + +#include +#define XP_ATOI(_s) ::atoi(_s) + +// XXX straight copy from laymap.c +static nscoord* lo_parse_coord_list(char *str, PRInt32* value_cnt) +{ + char *tptr; + char *n_str; + PRInt32 i, cnt; + PRInt32 *value_list; + + /* + * Nothing in an empty list + */ + *value_cnt = 0; + if ((str == NULL)||(*str == '\0')) + { + return((PRInt32 *)NULL); + } + + /* + * Skip beginning whitespace, all whitespace is empty list. + */ + n_str = str; + while (XP_IS_SPACE(*n_str)) + { + n_str++; + } + if (*n_str == '\0') + { + return((PRInt32 *)NULL); + } + + /* + * Make a pass where any two numbers separated by just whitespace + * are given a comma separator. Count entries while passing. + */ + cnt = 0; + while (*n_str != '\0') + { + PRBool has_comma; + + /* + * Skip to a separator + */ + tptr = n_str; + while ((!XP_IS_SPACE(*tptr))&&(*tptr != ',')&&(*tptr != '\0')) + { + tptr++; + } + n_str = tptr; + + /* + * If no more entries, break out here + */ + if (*n_str == '\0') + { + break; + } + + /* + * Skip to the end of the separator, noting if we have a + * comma. + */ + has_comma = PR_FALSE; + while ((XP_IS_SPACE(*tptr))||(*tptr == ',')) + { + if (*tptr == ',') + { + if (has_comma == PR_FALSE) + { + has_comma = PR_TRUE; + } + else + { + break; + } + } + tptr++; + } + /* + * If this was trailing whitespace we skipped, we are done. + */ + if ((*tptr == '\0')&&(has_comma == PR_FALSE)) + { + break; + } + /* + * Else if the separator is all whitespace, and this is not the + * end of the string, add a comma to the separator. + */ + else if (has_comma == PR_FALSE) + { + *n_str = ','; + } + + /* + * count the entry skipped. + */ + cnt++; + + n_str = tptr; + } + /* + * count the last entry in the list. + */ + cnt++; + + *value_cnt = cnt; + + /* + * Allocate space for the coordinate array. + */ + value_list = new nscoord[cnt]; + if (value_list == NULL) + { + return((PRInt32 *)NULL); + } + + /* + * Second pass to copy integer values into list. + */ + tptr = str; + for (i=0; i'); +} + +//---------------------------------------------------------------------- + +class DefaultArea : public Area { +public: + DefaultArea(const nsString& aBaseURL, const nsString& aHREF, + const nsString& aTarget, const nsString& aAltText, + PRBool aSuppress); + ~DefaultArea(); + + virtual PRBool IsInside(nscoord x, nscoord y); + virtual void Draw(nsIPresContext& aCX, + nsIRenderingContext& aRC); + virtual void GetShapeName(nsString& aResult); +}; + +DefaultArea::DefaultArea(const nsString& aBaseURL, const nsString& aHREF, + const nsString& aTarget, const nsString& aAltText, + PRBool aSuppress) + : Area(aBaseURL, aHREF, aTarget, aAltText, aSuppress) +{ +} + +DefaultArea::~DefaultArea() +{ +} + +PRBool DefaultArea::IsInside(nscoord x, nscoord y) +{ + return PR_TRUE; +} + +void DefaultArea::Draw(nsIPresContext& aCX, nsIRenderingContext& aRC) +{ +} + +void DefaultArea::GetShapeName(nsString& aResult) +{ + aResult.Append("default"); +} + +//---------------------------------------------------------------------- + +class RectArea : public Area { +public: + RectArea(const nsString& aBaseURL, const nsString& aHREF, + const nsString& aTarget, const nsString& aAltText, + PRBool aSuppress); + ~RectArea(); + + virtual PRBool IsInside(nscoord x, nscoord y); + virtual void Draw(nsIPresContext& aCX, + nsIRenderingContext& aRC); + virtual void GetShapeName(nsString& aResult); +}; + +RectArea::RectArea(const nsString& aBaseURL, const nsString& aHREF, + const nsString& aTarget, const nsString& aAltText, + PRBool aSuppress) + : Area(aBaseURL, aHREF, aTarget, aAltText, aSuppress) +{ +} + +RectArea::~RectArea() +{ +} + +PRBool RectArea::IsInside(nscoord x, nscoord y) +{ + if (mNumCoords >= 4) { // Note: > is for nav compatabilty + nscoord x1 = mCoords[0]; + nscoord y1 = mCoords[1]; + nscoord x2 = mCoords[2]; + nscoord y2 = mCoords[3]; + if ((x1 > x2)|| (y1 > y2)) { + // Can't be inside a screwed up rect + return PR_FALSE; + } + if ((x >= x1) && (x <= x2) && (y >= y1) && (y <= y2)) { + return PR_TRUE; + } + } + return PR_FALSE; +} + +void RectArea::Draw(nsIPresContext& aCX, nsIRenderingContext& aRC) +{ + if (mNumCoords >= 4) { + float p2t = aCX.GetPixelsToTwips(); + nscoord x1 = SCALE(p2t, mCoords[0]); + nscoord y1 = SCALE(p2t, mCoords[1]); + nscoord x2 = SCALE(p2t, mCoords[2]); + nscoord y2 = SCALE(p2t, mCoords[3]); + if ((x1 > x2)|| (y1 > y2)) { + return; + } + aRC.DrawRect(x1, y1, x2 - x1, y2 - y1); + } +} + +void RectArea::GetShapeName(nsString& aResult) +{ + aResult.Append("rect"); +} + +//---------------------------------------------------------------------- + +class PolyArea : public Area { +public: + PolyArea(const nsString& aBaseURL, const nsString& aHREF, + const nsString& aTarget, const nsString& aAltText, + PRBool aSuppress); + ~PolyArea(); + + virtual PRBool IsInside(nscoord x, nscoord y); + virtual void Draw(nsIPresContext& aCX, + nsIRenderingContext& aRC); + virtual void GetShapeName(nsString& aResult); +}; + +PolyArea::PolyArea(const nsString& aBaseURL, const nsString& aHREF, + const nsString& aTarget, const nsString& aAltText, + PRBool aSuppress) + : Area(aBaseURL, aHREF, aTarget, aAltText, aSuppress) +{ +} + +PolyArea::~PolyArea() +{ +} + +PRBool PolyArea::IsInside(nscoord x, nscoord y) +{ + if (mNumCoords >= 6) { + PRInt32 intersects = 0; + nscoord wherex = x; + nscoord wherey = y; + PRInt32 totalv = mNumCoords / 2; + PRInt32 totalc = totalv * 2; + nscoord xval = mCoords[totalc - 2]; + nscoord yval = mCoords[totalc - 1]; + PRInt32 end = totalc; + PRInt32 pointer = 1; + + if ((yval >= wherey) != (mCoords[pointer] >= wherey)) + if ((xval >= wherex) == (mCoords[0] >= wherex)) + intersects += (xval >= wherex) ? 1 : 0; + else + intersects += ((xval - (yval - wherey) * + (mCoords[0] - xval) / + (mCoords[pointer] - yval)) >= wherex) ? 1 : 0; + + // XXX I wonder what this is doing; this is a translation of ptinpoly.c + while (pointer < end) { + yval = mCoords[pointer]; + pointer += 2; + if (yval >= wherey) { + while((pointer < end) && (mCoords[pointer] >= wherey)) + pointer+=2; + if (pointer >= end) + break; + if ((mCoords[pointer-3] >= wherex) == + (mCoords[pointer-1] >= wherex)) { + intersects += (mCoords[pointer-3] >= wherex) ? 1 : 0; + } else { + intersects += + ((mCoords[pointer-3] - (mCoords[pointer-2] - wherey) * + (mCoords[pointer-1] - mCoords[pointer-3]) / + (mCoords[pointer] - mCoords[pointer - 2])) >= wherex) ? 1:0; + } + } else { + while((pointer < end) && (mCoords[pointer] < wherey)) + pointer+=2; + if (pointer >= end) + break; + if ((mCoords[pointer-3] >= wherex) == + (mCoords[pointer-1] >= wherex)) { + intersects += (mCoords[pointer-3] >= wherex) ? 1:0; + } else { + intersects += + ((mCoords[pointer-3] - (mCoords[pointer-2] - wherey) * + (mCoords[pointer-1] - mCoords[pointer-3]) / + (mCoords[pointer] - mCoords[pointer - 2])) >= wherex) ? 1:0; + } + } + } + if ((intersects & 1) != 0) { + return PR_TRUE; + } + } + return PR_FALSE; +} + +void PolyArea::Draw(nsIPresContext& aCX, nsIRenderingContext& aRC) +{ + if (mNumCoords >= 6) { + float p2t = aCX.GetPixelsToTwips(); + nscoord x0 = SCALE(p2t, mCoords[0]); + nscoord y0 = SCALE(p2t, mCoords[1]); + for (PRInt32 i = 2; i < mNumCoords; i += 2) { + nscoord x1 = SCALE(p2t, mCoords[i]); + nscoord y1 = SCALE(p2t, mCoords[i+1]); + aRC.DrawLine(x0, y0, x1, y1); + x0 = x1; + y0 = y1; + } + aRC.DrawLine(x0, y0, mCoords[0], mCoords[1]); + } +} + +void PolyArea::GetShapeName(nsString& aResult) +{ + aResult.Append("polygon"); +} + +//---------------------------------------------------------------------- + +class CircleArea : public Area { +public: + CircleArea(const nsString& aBaseURL, const nsString& aHREF, + const nsString& aTarget, const nsString& aAltText, + PRBool aSuppress); + ~CircleArea(); + + virtual PRBool IsInside(nscoord x, nscoord y); + virtual void Draw(nsIPresContext& aCX, + nsIRenderingContext& aRC); + virtual void GetShapeName(nsString& aResult); +}; + +CircleArea::CircleArea(const nsString& aBaseURL, const nsString& aHREF, + const nsString& aTarget, const nsString& aAltText, + PRBool aSuppress) + : Area(aBaseURL, aHREF, aTarget, aAltText, aSuppress) +{ +} + +CircleArea::~CircleArea() +{ +} + +PRBool CircleArea::IsInside(nscoord x, nscoord y) +{ + // Note: > is for nav compatabilty + if (mNumCoords >= 3) { + nscoord x1 = mCoords[0]; + nscoord y1 = mCoords[1]; + nscoord radius = mCoords[2]; + if (radius < 0) { + return PR_FALSE; + } + nscoord dx = x1 - x; + nscoord dy = y1 - y; + nscoord dist = (dx * dx) + (dy * dy); + if (dist <= (radius * radius)) { + return PR_TRUE; + } + } + return PR_FALSE; +} + +void CircleArea::Draw(nsIPresContext& aCX, nsIRenderingContext& aRC) +{ + if (mNumCoords >= 3) { + float p2t = aCX.GetPixelsToTwips(); + nscoord x1 = SCALE(p2t, mCoords[0]); + nscoord y1 = SCALE(p2t, mCoords[1]); + nscoord radius = SCALE(p2t, mCoords[2]); + if (radius < 0) { + return; + } + nscoord x = x1 - radius / 2; + nscoord y = y1 - radius / 2; + nscoord w = 2 * radius; + aRC.DrawEllipse(x, y, w, w); + } +} + +void CircleArea::GetShapeName(nsString& aResult) +{ + aResult.Append("circle"); +} + +//---------------------------------------------------------------------- + +static NS_DEFINE_IID(kIImageMapIID, NS_IIMAGEMAP_IID); + +class ImageMapImpl : public nsIImageMap { +public: + ImageMapImpl(nsIAtom* aTag); + ~ImageMapImpl(); + + NS_DECL_ISUPPORTS + + NS_IMETHOD SetName(const nsString& aMapName); + + NS_IMETHOD GetName(nsString& aResult); + + NS_IMETHOD AddArea(const nsString& aBaseURL, + const nsString& aShape, + const nsString& aCoords, + const nsString& aHREF, + const nsString& aTarget, + const nsString& aAltText, + PRBool aSuppress); + + NS_IMETHOD IsInside(nscoord aX, nscoord aY, + nsIURL* aDocURL, + nsString& aAbsURL, + nsString& aTarget, + nsString& aAltText, + PRBool* aSuppress); + + NS_IMETHOD IsInside(nscoord aX, nscoord aY); + + NS_IMETHOD Draw(nsIPresContext& aCX, nsIRenderingContext& aRC); + + nsString mName; + nsIAtom* mTag; + nsVoidArray mAreas; +}; + +ImageMapImpl::ImageMapImpl(nsIAtom* aTag) +{ + mTag = aTag; + NS_IF_ADDREF(aTag); +} + +ImageMapImpl::~ImageMapImpl() +{ + NS_IF_RELEASE(mTag); + PRInt32 i, n = mAreas.Count(); + for (i = 0; i < n; i++) { + Area* area = (Area*) mAreas.ElementAt(i); + delete area; + } +} + +NS_IMPL_ISUPPORTS(ImageMapImpl, kIImageMapIID); + +NS_IMETHODIMP ImageMapImpl::SetName(const nsString& aMapName) +{ + mName = aMapName; + return NS_OK; +} + +NS_IMETHODIMP ImageMapImpl::GetName(nsString& aResult) +{ + aResult = mName; + return NS_OK; +} + +NS_IMETHODIMP ImageMapImpl::AddArea(const nsString& aBaseURL, + const nsString& aShape, + const nsString& aCoords, + const nsString& aHREF, + const nsString& aTarget, + const nsString& aAltText, + PRBool aSuppress) +{ + Area* area; + if ((0 == aShape.Length()) || aShape.EqualsIgnoreCase("rect")) { + area = new RectArea(aBaseURL, aHREF, aTarget, aAltText, aSuppress); + } else if (aShape.EqualsIgnoreCase("poly") || + aShape.EqualsIgnoreCase("polygon")) { + area = new PolyArea(aBaseURL, aHREF, aTarget, aAltText, aSuppress); + } else if (aShape.EqualsIgnoreCase("circle")) { + area = new CircleArea(aBaseURL, aHREF, aTarget, aAltText, aSuppress); + } + else { + area = new DefaultArea(aBaseURL, aHREF, aTarget, aAltText, aSuppress); + } + area->ParseCoords(aCoords); + mAreas.AppendElement(area); + return NS_OK; +} + +NS_IMETHODIMP ImageMapImpl::IsInside(nscoord aX, nscoord aY, + nsIURL* aDocURL, + nsString& aAbsURL, + nsString& aTarget, + nsString& aAltText, + PRBool* aSuppress) +{ + PRInt32 i, n = mAreas.Count(); + for (i = 0; i < n; i++) { + Area* area = (Area*) mAreas.ElementAt(i); + if (area->IsInside(aX, aY)) { + NS_MakeAbsoluteURL(aDocURL, area->mBase, area->mHREF, aAbsURL); + aTarget = area->mTarget; + aAltText = area->mAltText; + *aSuppress = area->mSuppressFeedback; + return NS_OK; + } + } + return NS_NOT_INSIDE; +} + +NS_IMETHODIMP ImageMapImpl::IsInside(nscoord aX, nscoord aY) +{ + PRInt32 i, n = mAreas.Count(); + for (i = 0; i < n; i++) { + Area* area = (Area*) mAreas.ElementAt(i); + if (area->IsInside(aX, aY)) { + return NS_OK; + } + } + return NS_NOT_INSIDE; +} + +NS_IMETHODIMP ImageMapImpl::Draw(nsIPresContext& aCX, nsIRenderingContext& aRC) +{ + PRInt32 i, n = mAreas.Count(); + for (i = 0; i < n; i++) { + Area* area = (Area*) mAreas.ElementAt(i); + area->Draw(aCX, aRC); + } + return NS_OK; +} + +NS_HTML nsresult NS_NewImageMap(nsIImageMap** aInstancePtrResult, + nsIAtom* aTag) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + ImageMapImpl* it = new ImageMapImpl(aTag); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIImageMapIID, (void**) aInstancePtrResult); +} diff --git a/mozilla/layout/html/base/src/nsInlineFrame.cpp b/mozilla/layout/html/base/src/nsInlineFrame.cpp new file mode 100644 index 00000000000..c795cf6122e --- /dev/null +++ b/mozilla/layout/html/base/src/nsInlineFrame.cpp @@ -0,0 +1,1030 @@ +/* -*- 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 "nsInlineFrame.h" +#include "nsSize.h" +#include "nsIContent.h" +#include "nsIContentDelegate.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsIPresContext.h" +#include "nsIPresShell.h" +#include "nsCSSLayout.h" +#include "nsPlaceholderFrame.h" +#include "nsReflowCommand.h" + +// XXX To Do: +// 2. horizontal child margins +// 3. borders/padding and splitting +// 4. child relative positioning +// 5. absolutely positioned children +// 6. direction support +// 7. CSS line-height property + +#define DEFAULT_ASCENT_LEN 10 +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); +static NS_DEFINE_IID(kStyleFontSID, NS_STYLEFONT_SID); + +class nsInlineState +{ +public: + nsStyleFont* font; // style font + nsStyleMolecule* mol; // style molecule + nsSize availSize; // available space in which to reflow (starts as max size minus insets) + nsSize* maxElementSize; // maximum element size (may be null) + nscoord x; // running x-offset (starts at left inner edge) + const nscoord y; // y-offset (top inner edge) + nscoord maxAscent; // max child ascent + nscoord maxDescent; // max child descent + nscoord* ascents; // ascent information for each child + PRBool unconstrainedWidth; + PRBool unconstrainedHeight; + + // Constructor + nsInlineState(nsStyleFont* aStyleFont, + nsStyleMolecule* aStyleMolecule, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) + : x(aStyleMolecule->borderPadding.left), // determined by inner edge + y(aStyleMolecule->borderPadding.top) // determined by inner edge + { + font = aStyleFont; + mol = aStyleMolecule; + + unconstrainedWidth = PRBool(aMaxSize.width == NS_UNCONSTRAINEDSIZE); + unconstrainedHeight = PRBool(aMaxSize.height == NS_UNCONSTRAINEDSIZE); + + // If we're constrained adjust the available size so it excludes space + // needed for border/padding + availSize.width = aMaxSize.width; + if (PR_FALSE == unconstrainedWidth) { + availSize.width -= mol->borderPadding.left + mol->borderPadding.right; + } + availSize.height = aMaxSize.height; + if (PR_FALSE == unconstrainedHeight) { + availSize.height -= mol->borderPadding.top + mol->borderPadding.bottom; + } + + // Initialize max element size + maxElementSize = aMaxElementSize; + if (nsnull != maxElementSize) { + maxElementSize->SizeTo(0, 0); + } + + ascents = ascentBuf; + maxAscent = 0; + maxDescent = 0; + } + + void SetNumAscents(PRIntn aNumAscents) { + // We keep around ascent information so that we can vertically align + // children after we figure out how many children fit. + if (aNumAscents > DEFAULT_ASCENT_LEN) { + ascents = new nscoord[aNumAscents]; + } + } + + // Destructor + ~nsInlineState() { + if (ascents != ascentBuf) { + delete ascents; + } + } + +private: + nscoord ascentBuf[DEFAULT_ASCENT_LEN]; +}; + +///////////////////////////////////////////////////////////////////////////// +// + +nsresult nsInlineFrame::NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIFrame* it = new nsInlineFrame(aContent, aIndexInParent, aParent); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aInstancePtrResult = it; + return NS_OK; +} + +nsInlineFrame::nsInlineFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) + : nsHTMLContainerFrame(aContent, aIndexInParent, aParent) +{ + NS_PRECONDITION(!IsPseudoFrame(), "can not be a pseudo frame"); +} + +nsInlineFrame::~nsInlineFrame() +{ +} + +void nsInlineFrame::PlaceChild(nsIFrame* aChild, + PRInt32 aIndex, + nsInlineState& aState, + const nsReflowMetrics& aChildSize, + const nsSize* aChildMaxElementSize) +{ + // Set the child's rect + aChild->SetRect(nsRect(aState.x, aState.y, aChildSize.width, aChildSize.height)); + + // Adjust the running x-offset + aState.x += aChildSize.width; + + // Update the array of ascents and the max ascent and descent + aState.ascents[aIndex] = aChildSize.ascent; + if (aChildSize.ascent > aState.maxAscent) { + aState.maxAscent = aChildSize.ascent; + } + if (aChildSize.descent > aState.maxDescent) { + aState.maxDescent = aChildSize.descent; + } + + // If we're constrained then update the available width + if (!aState.unconstrainedWidth) { + aState.availSize.width -= aChildSize.width; + } + + // Update the maximum element size + if (nsnull != aChildMaxElementSize) { + if (aChildMaxElementSize->width > aState.maxElementSize->width) { + aState.maxElementSize->width = aChildMaxElementSize->width; + } + if (aChildMaxElementSize->height > aState.maxElementSize->height) { + aState.maxElementSize->height = aChildMaxElementSize->height; + } + } +} + +/** + * Reflow the frames we've already created + * + * @param aPresContext presentation context to use + * @param aState current inline state + * @return true if we successfully reflowed all the mapped children and false + * otherwise, e.g. we pushed children to the next in flow + */ +PRBool nsInlineFrame::ReflowMappedChildren(nsIPresContext* aPresContext, + nsInlineState& aState) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif + NS_PRECONDITION(nsnull != mFirstChild, "no children"); + + PRInt32 childCount = 0; + nsIFrame* prevKidFrame = nsnull; + + // Remember our original mLastContentIsComplete so that if we end up + // having to push children, we have the correct value to hand to + // PushChildren. + PRBool originalLastContentIsComplete = mLastContentIsComplete; + + nsSize kidMaxElementSize; + nsSize* pKidMaxElementSize = (nsnull != aState.maxElementSize) ? &kidMaxElementSize : nsnull; + PRBool result = PR_TRUE; + + for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; ) { + nsReflowMetrics kidSize; + ReflowStatus status; + + // Reflow the child into the available space + status = ReflowChild(kidFrame, aPresContext, kidSize, aState.availSize, + pKidMaxElementSize); + + // Did the child fit? + if ((kidSize.width > aState.availSize.width) && (kidFrame != mFirstChild)) { + // The child is too wide to fit in the available space, and it's + // not our first child + + // Since we are giving the next-in-flow our last child, we + // give it our original mLastContentIsComplete too (in case we + // are pushing into an empty next-in-flow) + PushChildren(kidFrame, prevKidFrame, originalLastContentIsComplete); + SetLastContentOffset(prevKidFrame); + + result = PR_FALSE; + break; + } + + // Place and size the child. We'll deal with vertical alignment when + // we're all done + PlaceChild(kidFrame, childCount, aState, kidSize, pKidMaxElementSize); + childCount++; + + // Remember where we just were in case we end up pushing children + prevKidFrame = kidFrame; + + // Is the child complete? + mLastContentIsComplete = PRBool(status == frComplete); + if (frNotComplete == status) { + // No, the child isn't complete + nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); + PRBool lastContentIsComplete = mLastContentIsComplete; + if (nsnull == kidNextInFlow) { + // The child doesn't have a next-in-flow so create a continuing + // frame. This hooks the child into the flow + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aPresContext, this); + NS_ASSERTION(nsnull != continuingFrame, "frame creation failed"); + + // Add the continuing frame to the sibling list + nsIFrame* nextSib = kidFrame->GetNextSibling(); + continuingFrame->SetNextSibling(nextSib); + kidFrame->SetNextSibling(continuingFrame); + if (nsnull == nextSib) { + // Assume that the continuation frame we just created is + // complete, for now. It will get reflowed by our + // next-in-flow (we are going to push it now) + lastContentIsComplete = PR_TRUE; + } + } + + // We've used up all of our available space so push the remaining + // children to the next-in-flow + nsIFrame* nextSibling = kidFrame->GetNextSibling(); + if (nsnull != nextSibling) { + PushChildren(nextSibling, kidFrame, lastContentIsComplete); + SetLastContentOffset(prevKidFrame); + } + result = PR_FALSE; + break; + } + + // Get the next child frame + kidFrame = kidFrame->GetNextSibling(); + + // XXX talk with troy about checking for available space here + } + + // Update the child count member data + mChildCount = childCount; + NS_POSTCONDITION(LengthOf(mFirstChild) == mChildCount, "bad child count"); + NS_POSTCONDITION(LastChild()->GetIndexInParent() == mLastContentOffset, "bad last content offset"); +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif + return result; +} + +/** + * Try and pull-up frames from our next-in-flow + * + * @param aPresContext presentation context to use + * @param aState current inline state + * @return true if we successfully pulled-up all the children and false + * otherwise, e.g. child didn't fit + */ +PRBool nsInlineFrame::PullUpChildren(nsIPresContext* aPresContext, + nsInlineState& aState) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif + nsInlineFrame* nextInFlow = (nsInlineFrame*)mNextInFlow; + nsSize kidMaxElementSize; + nsSize* pKidMaxElementSize = (nsnull != aState.maxElementSize) ? &kidMaxElementSize : nsnull; +#ifdef NS_DEBUG + PRInt32 kidIndex = NextChildOffset(); +#endif + nsIFrame* prevKidFrame = LastChild(); + + // This will hold the prevKidFrame's mLastContentIsComplete + // status. If we have to push the frame that follows prevKidFrame + // then this will become our mLastContentIsComplete state. Since + // prevKidFrame is initially our last frame, it's completion status + // is our mLastContentIsComplete value. + PRBool prevLastContentIsComplete = mLastContentIsComplete; + + PRBool result = PR_TRUE; + + while (nsnull != nextInFlow) { + nsReflowMetrics kidSize; + ReflowStatus status; + + // Get the next child + nsIFrame* kidFrame = nextInFlow->mFirstChild; + + // Any more child frames? + if (nsnull == kidFrame) { + // No. Any frames on its overflow list? + if (nsnull != nextInFlow->mOverflowList) { + // Move the overflow list to become the child list + NS_ABORT(); + nextInFlow->AppendChildren(nextInFlow->mOverflowList); + nextInFlow->mOverflowList = nsnull; + kidFrame = nextInFlow->mFirstChild; + } else { + // We've pulled up all the children, so move to the next-in-flow. + nextInFlow = (nsInlineFrame*)nextInFlow->GetNextInFlow(); + continue; + } + } + + // See if the child fits in the available space. If it fits or + // it's splittable then reflow it. The reason we can't just move + // it is that we still need ascent/descent information + if ((kidFrame->GetWidth() > aState.availSize.width) && + !kidFrame->IsSplittable()) { + result = PR_FALSE; + mLastContentIsComplete = prevLastContentIsComplete; + break; + } + status = ReflowChild(kidFrame, aPresContext, kidSize, aState.availSize, + pKidMaxElementSize); + + // Did the child fit? + if ((kidSize.width > aState.availSize.width) && (nsnull != mFirstChild)) { + // The child is too wide to fit in the available space, and it's + // not our first child + result = PR_FALSE; + mLastContentIsComplete = prevLastContentIsComplete; + break; + } + + // Place and size the child. We'll deal with vertical alignment when + // we're all done + PlaceChild(kidFrame, mChildCount, aState, kidSize, pKidMaxElementSize); + + // Remove the frame from its current parent + nextInFlow->mFirstChild = kidFrame->GetNextSibling(); + nextInFlow->mChildCount--; + // Update the next-in-flows first content offset + if (nsnull != nextInFlow->mFirstChild) { + nextInFlow->SetFirstContentOffset(nextInFlow->mFirstChild); + } + + // Link the frame into our list of children + kidFrame->SetGeometricParent(this); + if (nextInFlow == kidFrame->GetContentParent()) { + kidFrame->SetContentParent(this); + } + if (nsnull == prevKidFrame) { + mFirstChild = kidFrame; + SetFirstContentOffset(kidFrame); + } else { + prevKidFrame->SetNextSibling(kidFrame); + } + kidFrame->SetNextSibling(nsnull); + mChildCount++; + + // Remember where we just were in case we end up pushing children + prevKidFrame = kidFrame; + prevLastContentIsComplete = mLastContentIsComplete; + + // Is the child we just pulled up complete? + mLastContentIsComplete = PRBool(status == frComplete); + if (frNotComplete == status) { + // No the child isn't complete + nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); + if (nsnull == kidNextInFlow) { + // The child doesn't have a next-in-flow so create a + // continuing frame. The creation appends it to the flow and + // prepares it for reflow. + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aPresContext, this); + NS_ASSERTION(nsnull != continuingFrame, "frame creation failed"); + + // Add the continuing frame to our sibling list and then push + // it to the next-in-flow. This ensures the next-in-flow's + // content offsets and child count are set properly. Note that + // we can safely assume that the continuation is complete so + // we pass PR_TRUE into PushChidren in case our next-in-flow + // was just drained and now needs to know it's + // mLastContentIsComplete state. + kidFrame->SetNextSibling(continuingFrame); + + PushChildren(continuingFrame, kidFrame, PR_TRUE); + + // After we push the continuation frame we don't need to fuss + // with mLastContentIsComplete beause the continuation frame + // is no longer on *our* list. + } + + // If the child isn't complete then it means that we've used up + // all of our available space. + result = PR_FALSE; + break; + } + } + + // Update our last content offset + if (nsnull != prevKidFrame) { + NS_ASSERTION(LastChild() == prevKidFrame, "bad last child"); + SetLastContentOffset(prevKidFrame); + } + + // We need to make sure the first content offset is correct for any empty + // next-in-flow frames (frames where we pulled up all the child frames) + nextInFlow = (nsInlineFrame*)mNextInFlow; + if ((nsnull != nextInFlow) && (nsnull == nextInFlow->mFirstChild)) { + // We have at least one empty frame. Did we succesfully pull up all the + // child frames? + if (PR_FALSE == result) { + // No, so we need to adjust the first content offset of all the empty + // frames + AdjustOffsetOfEmptyNextInFlows(); +#ifdef NS_DEBUG + } else { + // Yes, we successfully pulled up all the child frames which means all + // the next-in-flows must be empty. Do a sanity check + while (nsnull != nextInFlow) { + NS_ASSERTION(nsnull == nextInFlow->mFirstChild, "non-empty next-in-flow"); + nextInFlow = (nsInlineFrame*)nextInFlow->GetNextInFlow(); + } +#endif + } + } + +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif + return result; +} + +/** + * Create new frames for content we haven't yet mapped + * + * @param aPresContext presentation context to use + * @param aState current inline state + * @return frComplete if all content has been mapped and frNotComplete + * if we should be continued + */ +nsIFrame::ReflowStatus +nsInlineFrame::ReflowUnmappedChildren(nsIPresContext* aPresContext, + nsInlineState& aState) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif + nsIFrame* kidPrevInFlow = nsnull; + ReflowStatus result = frNotComplete; + + // If we have no children and we have a prev-in-flow then we need to pick + // up where it left off. If we have children, e.g. we're being resized, then + // our content offset should already be set correctly... + if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) { + nsInlineFrame* prev = (nsInlineFrame*)mPrevInFlow; + NS_ASSERTION(prev->mLastContentOffset >= prev->mFirstContentOffset, "bad prevInFlow"); + + mFirstContentOffset = prev->NextChildOffset(); + if (!prev->mLastContentIsComplete) { + // Our prev-in-flow's last child is not complete + kidPrevInFlow = prev->LastChild(); + } + } + mLastContentIsComplete = PR_TRUE; + + // Place our children, one at a time until we are out of children + nsSize kidMaxElementSize; + nsSize* pKidMaxElementSize = (nsnull != aState.maxElementSize) ? &kidMaxElementSize : nsnull; + PRInt32 kidIndex = NextChildOffset(); + nsIFrame* prevKidFrame = LastChild(); + + for (;;) { + // Get the next content object + nsIContent* kid = mContent->ChildAt(kidIndex); + if (nsnull == kid) { + result = frComplete; + break; + } + + // Make sure we still have room left + if (aState.availSize.width <= 0) { + // Note: return status was set to frNotComplete above... + NS_RELEASE(kid); + break; + } + + // Resolve style for the child + nsIStyleContext* kidStyleContext = + aPresContext->ResolveStyleContextFor(kid, this); + + // Figure out how we should treat the child + nsIFrame* kidFrame; + nsStyleMolecule* kidMol = + (nsStyleMolecule*)kidStyleContext->GetData(kStyleMoleculeSID); + + if (kidMol->floats != NS_STYLE_FLOAT_NONE) { + PlaceholderFrame::NewFrame(&kidFrame, kid, kidIndex, this); + kidFrame->SetStyleContext(kidStyleContext); + + } else if (nsnull == kidPrevInFlow) { + nsIContentDelegate* kidDel; + switch (kidMol->display) { + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + if (kidIndex != mFirstContentOffset) { + // We don't allow block elements to be placed in us anywhere + // other than at our left margin. + NS_RELEASE(kidStyleContext); + NS_RELEASE(kid); + goto done; + } + // FALLTHROUGH + + case NS_STYLE_DISPLAY_INLINE: + kidDel = kid->GetDelegate(aPresContext); + kidFrame = kidDel->CreateFrame(aPresContext, kid, kidIndex, this); + NS_RELEASE(kidDel); + break; + + default: + NS_ASSERTION(nsnull == kidPrevInFlow, "bad prev in flow"); + nsFrame::NewFrame(&kidFrame, kid, kidIndex, this); + break; + } + kidFrame->SetStyleContext(kidStyleContext); + } else { + kidFrame = kidPrevInFlow->CreateContinuingFrame(aPresContext, this); + } + NS_RELEASE(kid); + NS_RELEASE(kidStyleContext); + + // Try to reflow the child into the available space. It might not + // fit or might need continuing. + nsReflowMetrics kidSize; + ReflowStatus status = ReflowChild(kidFrame,aPresContext, kidSize, + aState.availSize, pKidMaxElementSize); + + // Did the child fit? + if ((kidSize.width > aState.availSize.width) && (nsnull != mFirstChild)) { + // The child is too wide to fit in the available space, and it's + // not our first child. Add the frame to our overflow list + NS_ASSERTION(nsnull == mOverflowList, "bad overflow list"); + mOverflowList = kidFrame; + prevKidFrame->SetNextSibling(nsnull); + break; + } + + // Place and size the child. We'll deal with vertical alignment when + // we're all done + PlaceChild(kidFrame, mChildCount, aState, kidSize, pKidMaxElementSize); + + // Link child frame into the list of children + if (nsnull != prevKidFrame) { + prevKidFrame->SetNextSibling(kidFrame); + } else { + mFirstChild = kidFrame; // our first child + SetFirstContentOffset(kidFrame); + } + prevKidFrame = kidFrame; + mChildCount++; + kidIndex++; + + // Did the child complete? + if (frNotComplete == status) { + // If the child isn't complete then it means that we've used up + // all of our available space + mLastContentIsComplete = PR_FALSE; + break; + } + kidPrevInFlow = nsnull; + } + +done:; + // Update the content mapping + NS_ASSERTION(LastChild() == prevKidFrame, "bad last child"); + SetLastContentOffset(prevKidFrame); +#ifdef NS_DEBUG + PRInt32 len = LengthOf(mFirstChild); + NS_ASSERTION(len == mChildCount, "bad child count"); +#endif +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif + return result; +} + +nsIFrame::ReflowStatus +nsInlineFrame::ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ +#ifdef NS_DEBUG + PreReflowCheck(); +#endif +//XXX not now NS_PRECONDITION((aMaxSize.width > 0) && (aMaxSize.height > 0), "unexpected max size"); + + PRBool reflowMappedOK = PR_TRUE; + ReflowStatus status = frComplete; + + // Get the style molecule + nsStyleFont* styleFont = + (nsStyleFont*)mStyleContext->GetData(kStyleFontSID); + nsStyleMolecule* styleMolecule = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + + // Check for an overflow list + MoveOverflowToChildList(); + + // Initialize our reflow state. We must wait until after we've processed + // the overflow list, because our first content offset might change + nsInlineState state(styleFont, styleMolecule, aMaxSize, aMaxElementSize); + state.SetNumAscents(mContent->ChildCount() - mFirstContentOffset); + + // Reflow any existing frames + if (nsnull != mFirstChild) { + reflowMappedOK = ReflowMappedChildren(aPresContext, state); + + if (PR_FALSE == reflowMappedOK) { + status = frNotComplete; + } + } + + // Did we successfully relow our mapped children? + if (PR_TRUE == reflowMappedOK) { + // Any space left? + if (state.availSize.width <= 0) { + // No space left. Don't try to pull-up children or reflow unmapped + if (NextChildOffset() < mContent->ChildCount()) { + status = frNotComplete; + } + } else if (NextChildOffset() < mContent->ChildCount()) { + // Try and pull-up some children from a next-in-flow + if (PullUpChildren(aPresContext, state)) { + // If we still have unmapped children then create some new frames + if (NextChildOffset() < mContent->ChildCount()) { + status = ReflowUnmappedChildren(aPresContext, state); + } + } else { + // We were unable to pull-up all the existing frames from the next in flow + status = frNotComplete; + } + } + } + + const nsMargin& insets = styleMolecule->borderPadding; + + // Vertically align the children + nscoord lineHeight = + nsCSSLayout::VerticallyAlignChildren(aPresContext, this, styleFont, + insets.top, mFirstChild, mChildCount, + state.ascents, state.maxAscent); + + // XXX I don't think our return size properly accounts for the lineHeight + // (which may not == state.maxAscent + state.maxDescent) + // Return our size and our status + aDesiredSize.width = state.x + insets.right; + aDesiredSize.ascent = insets.top + state.maxAscent; + aDesiredSize.descent = state.maxDescent + insets.bottom; + aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; + +#ifdef NS_DEBUG + PostReflowCheck(status); +#endif + return status; +} + +///////////////////////////////////////////////////////////////////////////// + +PRIntn nsInlineFrame::GetSkipSides() const +{ + PRIntn skip = 0; + if (nsnull != mPrevInFlow) { + skip |= 1 << NS_SIDE_LEFT; + } + if (nsnull != mNextInFlow) { + skip |= 1 << NS_SIDE_RIGHT; + } + return skip; +} + +///////////////////////////////////////////////////////////////////////////// + +// Incremental reflow support + +void nsInlineFrame::GetReflowMetrics(nsIPresContext* aPresContext, + nsReflowMetrics& aMetrics) +{ + nscoord maxAscent = 0; + nscoord maxDescent = 0; + nsIFrame* kid = mFirstChild; + while (nsnull != kid) { + nsReflowMetrics kidMetrics; + kid->GetReflowMetrics(aPresContext, kidMetrics); + if (kidMetrics.ascent > maxAscent) maxAscent = kidMetrics.ascent; + if (kidMetrics.descent > maxDescent) maxDescent = kidMetrics.descent; + kid = kid->GetNextSibling(); + } + + // XXX what about border & padding + aMetrics.width = mRect.width; + aMetrics.height = mRect.height; + aMetrics.ascent = maxAscent; + aMetrics.descent = maxDescent; +} + +/** + * Setup aState to the state it would have had we just reflowed our + * children up to, but not including, aSkipChild. Return the index + * of aSkipChild in our list of children. + */ +PRIntn nsInlineFrame::RecoverState(nsIPresContext* aPresContext, + nsInlineState& aState, + nsIFrame* aSkipChild) +{ + // Get ascent & descent info for all the children up to but not + // including aSkipChild. Also compute the x coordinate for where + // aSkipChild will be place after it is reflowed. + PRIntn i = 0; + nsIFrame* kid = mFirstChild; + nscoord x = aState.x; + nscoord maxAscent = 0; + nscoord maxDescent = 0; + while (kid != aSkipChild) { + nsReflowMetrics kidMetrics; + kid->GetReflowMetrics(aPresContext, kidMetrics); + aState.ascents[i] = kidMetrics.ascent; + if (kidMetrics.ascent > maxAscent) maxAscent = kidMetrics.ascent; + if (kidMetrics.descent > maxDescent) maxDescent = kidMetrics.descent; + + // XXX Factor in left and right margins + x += kidMetrics.width; + + kid = kid->GetNextSibling(); + i++; + } + aState.maxAscent = maxAscent; + aState.maxDescent = maxDescent; + aState.x = x; + return (nsnull == aSkipChild) ? 0 : i; +} + +nsIFrame::ReflowStatus +nsInlineFrame::IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand) +{ + ReflowStatus status = frComplete; + +#if 0 + if (aReflowCommand.GetTarget() == this) { + // NOTE: target frame is first in flow even when reflow commands + // applies to some piece of content in any of the next-in-flows + nsInlineFrame* flow = this; + + switch (aReflowCommand.GetType()) { + case nsReflowCommand::rcContentAppended: + // Get to last-in-flow where the append is occuring + while (nsnull != flow->mNextInFlow) { + flow = flow->mNextInFlow; + } + status = flow->ReflowUnmappedChildren(...); + break; + + case nsReflowCommand::rcContentInserted: + // XXX where did the insertion point go? + + // Get to correct next-in-flow + // XXX this is more complicated when dealing with pseudo children + PRInt32 contentIndex = 0; + while (nsnull != flow->mNextInFlow) { + // XXX the last child we have may be continued into our + // next-in-flow which means that endIndex is wrong??? + PRInt32 endIndex = contentIndex + mChildCount; + if ((contentIndex <= aIndexInParent) && (aIndexInParent < endIndex)) { + break; + } + flow = flow->mNextInFlow; + contentIndex = endIndex; + } + + // Create frame and insert it into the sibling list at the right + // spot. Reflow it. Adjust position of siblings including + // pushing frames that don't fit. + flow->ReflowUnmappedChild(..., index information); + break; + + case nsReflowCommand::rcContentDeleted: + // XXX what about will-delete, did-delete? + + // Find the affected flow blocks and remove the child and any + // continuations it has from the flow. Every flow block except + // the first one will recieve a reflow command to cleanup after + // the first flow block does it's clean up. Except for the + // post-processing (impacting sibling frames) the code is + // generic across container types. + break; + + case nsReflowCommand::rcContentChanged: + // XXX The piece of content affected may change stylistically + // from inline to block. If it does and it's not our first kid + // then we just push it and let our next-in-flow reflow it. + + // Either: a) delete the old frame, create a new frame, reflow -or- + // b) ResizeReflow the affected child + + // If the reflow status is incomplete then the remaining + // children on the line get pushed; else only push children that + // don't fit. If no pushing occurs then maybe we can pullup a + // child; if we do then generate reflow commands for our + // next-in-flows to deal with a pull event. + break; + } + + } else { + // XXX Tuneup? if we save the child's continuation status and its + // current bounding rect and then pass the command down and it + // comes back with the same bounds in aDesiredSize and with the + // same continuation status then we are done, right? + + // Get the next frame that the reflow command is targeted at. + // This will be one of my children. + nsIFrame* nextInChain = aReflowCommand.GetNext(); + NS_ASSERTION(this == nextInChain->GetGeometricParent(), "bad reflow cmd"); + + // Recover the reflow state as if we had reflowed our children up + // to but not including the child that is next in the reflow chain + nsStyleMolecule* styleMolecule = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + nsInlineState state(styleMolecule, aMaxSize, nsnull); + state.SetNumAscents(mChildCount); + PRIntn nextIndex = RecoverState(aPresContext, state, nextInChain); + + // Save away the current location and size of the child which the + // reflow command is targeted towards. This isn't strictly + // necessary, but our child might tamper with it's x/y + // XXX bother? + nsRect oldBounds; + nextInChain->GetRect(oldBounds); + + // Now pass reflow command down to our child to handle + nsReflowMetrics kidMetrics; + status = aReflowCommand.Next(kidMetrics, aMaxSize, kid); + // XXX what do we do when the nextInChain's completion status changes? + // XXX if kid == LastChild() then mLastContentIsComplete needs updating + + // Update placement information for the impacted child frame and + // any other frames following the child frame. + if ((oldBounds.width == kidMetrics.width) && + (oldBounds.height == kidMetrics.height)) { + // The child didn't change as far as we can tell. Nobody needs + // to be moved. + + // XXX what about a child who's shape is the same but who's + // reflow status is frNotComplete? + + // Note: a child that used to be continued and is no longer + // continued and whose size is unchanged: we don't care because + // as far as we are concerned nothing happened to us. However, + // our next-in-flow might get torched (our parent will deal with + // that). + + // XXX figure out the right status to return + } else { + // Factor in ascent information from the updated child + state.ascents[nextIndex] = kidMetrics.ascent; + if (kidMetrics.ascent > state.maxAscent) { + state.maxAscent = kidMetrics.ascent; + } + if (kidMetrics.descent > state.maxDescent) { + state.maxDescent = kidMetrics.descent; + } + + // Update other children that are impacted by the change in + // nextInChain. In addition, re-apply vertical alignment and + // relative positioning to the children on the line. + status = AdjustChildren(aPresContext, aDesiredSize, aState, kid, + kidMetrics, status); + } + } +#endif + + return status; +} + + +// In order to execute the vertical alignment code after incremental +// reflow of the inline frame, we need to reposition any child frames +// that were relatively positioned back to their computed x origin. +// This should probably be done as a pre-alignment computation (and it +// can be avoided if there are no relatively positioned children). + +/** + * Adjust the position of all the children in this frame. + * + * The children after aKid in the list of children are slid over by + * dx. + * + * Once the x and y coordinates have been set, then the vertical + * alignment code is executed to place the children vertically and to + * compute the final height of our frame. + * + * If one of our children spills over the end then push it to the + * next-in-flow or to our overflow list. + */ +nsIFrame::ReflowStatus +nsInlineFrame::AdjustChildren(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + nsInlineState& aState, + nsIFrame* aKid, + nsReflowMetrics& aKidMetrics, + ReflowStatus aKidReflowStatus) +{ + nsStyleMolecule* mol = aState.mol; + nscoord xr = aState.availSize.width + mol->borderPadding.left; + nscoord remainingSpace = xr - aState.x; + nscoord x = aState.x; + + // Slide all of the children over following aKid + nsIFrame* kid = aKid; + nsRect r; + while (nsnull != kid) { + kid->GetRect(r); + if (r.x != x) { + kid->MoveTo(x, r.y); + } + x += r.width; + // XXX factor in left and right margins + kid = kid->GetNextSibling(); + } + + // Vertically align the children + const nsMargin& insets = mol->borderPadding; + nsCSSLayout::VerticallyAlignChildren(aPresContext, this, aState.font, + insets.top, mFirstChild, mChildCount, + aState.ascents, aState.maxAscent); + + // XXX relative position children, if any + + // XXX adjust mLastContentOffset if we push + // XXX if we push, generate a reflow command + + return frComplete; +} + +// My container has new content at the end of it. Create frames for +// the appended content and then generate an incremental reflow +// command for ourselves. +void nsInlineFrame::ContentAppended(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer) +{ + // Zip down to the end-of-flow + nsInlineFrame* flow = this; + for (;;) { + nsInlineFrame* next = (nsInlineFrame*) flow->GetNextInFlow(); + if (nsnull == next) { + break; + } + flow = next; + } + + // Get index of where the content has been appended + PRInt32 kidIndex = flow->NextChildOffset(); + PRInt32 startIndex = kidIndex; + nsIFrame* prevKidFrame = flow->LastChild(); + + // Create frames for each new child + for (;;) { + // Get the next content object + nsIContent* kid = mContent->ChildAt(kidIndex); + if (nsnull == kid) { + break; + } + + nsIContentDelegate* del = kid->GetDelegate(aPresContext); + nsIFrame* kidFrame = del->CreateFrame(aPresContext, kid, kidIndex, flow); + NS_RELEASE(del); + NS_RELEASE(kid); + + // Append kidFrame to the sibling list + prevKidFrame->SetNextSibling(kidFrame); + prevKidFrame = kidFrame; + kidIndex++; + } + flow->SetLastContentOffset(prevKidFrame); + + // Now generate a reflow command for flow + if (aContainer == mContent) { + nsReflowCommand* rc = + new nsReflowCommand(aPresContext, flow, nsReflowCommand::FrameAppended, + startIndex); + aShell->AppendReflowCommand(rc); + } +} diff --git a/mozilla/layout/html/base/src/nsLeafFrame.cpp b/mozilla/layout/html/base/src/nsLeafFrame.cpp new file mode 100644 index 00000000000..052f6bd8ea2 --- /dev/null +++ b/mozilla/layout/html/base/src/nsLeafFrame.cpp @@ -0,0 +1,117 @@ +/* -*- 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 "nsLeafFrame.h" +#include "nsIStyleContext.h" +#include "nsCSSRendering.h" + +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); +static NS_DEFINE_IID(kStyleColorSID, NS_STYLECOLOR_SID); + +nsLeafFrame::nsLeafFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsFrame(aContent, aIndexInParent, aParentFrame) +{ +} + +nsLeafFrame::~nsLeafFrame() +{ +} + +void nsLeafFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + nsStyleColor* myColor = + (nsStyleColor*)mStyleContext->GetData(kStyleColorSID); + nsStyleMolecule* myMol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this, + aDirtyRect, mRect, *myColor); + nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, + aDirtyRect, mRect, *myMol, 0); +} + +nsIFrame::ReflowStatus +nsLeafFrame::ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ + // XXX add in code to check for width/height being set via css + // and if set use them instead of calling GetDesiredSize. + + GetDesiredSize(aPresContext, aDesiredSize, aMaxSize); + AddBordersAndPadding(aPresContext, aDesiredSize); + if (nsnull != aMaxElementSize) { + aMaxElementSize->width = aDesiredSize.width; + aMaxElementSize->height = aDesiredSize.height; + } + return frComplete; +} + +nsIFrame::ReflowStatus +nsLeafFrame::IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand) +{ + // XXX Unless the reflow command is a style change, we should + // just return the current size, otherwise we should invoke + // GetDesiredSize + + // XXX add in code to check for width/height being set via css + // and if set use them instead of calling GetDesiredSize. + GetDesiredSize(aPresContext, aDesiredSize, aMaxSize); + AddBordersAndPadding(aPresContext, aDesiredSize); + + return frComplete; +} + +// XXX how should border&padding effect baseline alignment? +// => descent = borderPadding.bottom for example +void nsLeafFrame::AddBordersAndPadding(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize) +{ + nsStyleMolecule* mol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + aDesiredSize.width += mol->borderPadding.left + mol->borderPadding.right; + aDesiredSize.height += mol->borderPadding.top + mol->borderPadding.bottom; + aDesiredSize.ascent = aDesiredSize.height; + aDesiredSize.descent = 0; +} + +void nsLeafFrame::GetInnerArea(nsIPresContext* aPresContext, + nsRect& aInnerArea) const +{ + nsStyleMolecule* mol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + aInnerArea.x = mol->borderPadding.left; + aInnerArea.y = mol->borderPadding.top; + aInnerArea.width = mRect.width - + (mol->borderPadding.left + mol->borderPadding.right); + aInnerArea.height = mRect.height - + (mol->borderPadding.top + mol->borderPadding.bottom); +} + +nsIFrame* nsLeafFrame::CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent) +{ + NS_NOTREACHED("Attempt to split the unsplittable"); + return nsnull; +} diff --git a/mozilla/layout/html/base/src/nsLeafFrame.h b/mozilla/layout/html/base/src/nsLeafFrame.h new file mode 100644 index 00000000000..6798e154a77 --- /dev/null +++ b/mozilla/layout/html/base/src/nsLeafFrame.h @@ -0,0 +1,77 @@ +/* -*- 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. + */ +#ifndef nsLeafFrame_h___ +#define nsLeafFrame_h___ + +#include "nsFrame.h" + +/** + * Abstract class that provides simple fixed-size layout for leaf objects + * (e.g. images, form elements, etc.). Deriviations provide the implementation + * of the GetDesiredSize method. The rendering method knows how to render + * borders and backgrounds. + */ +class nsLeafFrame : public nsFrame { +public: + virtual void Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + virtual ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + + virtual ReflowStatus IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand); + + virtual nsIFrame* CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent); + +protected: + nsLeafFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + virtual ~nsLeafFrame(); + + /** + * Return the desired size of the frame. Note that this method + * doesn't need to deal with padding or borders (the caller will + * deal with it). In addition, the ascent will be set to the height + * and the descent will be set to zero. + */ + virtual void GetDesiredSize(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize) = 0; + + /** + * Get the inner rect of this frame. This takes the outer size (mRect) + * and subtracts off the borders and padding. + */ + void GetInnerArea(nsIPresContext* aPresContext, nsRect& aInnerArea) const; + + /** + * Subroutine to add in borders and padding + */ + void AddBordersAndPadding(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize); +}; + +#endif /* nsLeafFrame_h___ */ diff --git a/mozilla/layout/html/base/src/nsListItemFrame.cpp b/mozilla/layout/html/base/src/nsListItemFrame.cpp new file mode 100644 index 00000000000..2fcd66fa9f5 --- /dev/null +++ b/mozilla/layout/html/base/src/nsListItemFrame.cpp @@ -0,0 +1,670 @@ +/* -*- 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 "nsListItemFrame.h" +#include "nsIStyleContext.h" +#include "nsFrame.h" +#include "nsString.h" +#include "nsIRenderingContext.h" +#include "nsIPresContext.h" +#include "nsIFontMetrics.h" +#include "nsStyleConsts.h" +#include "nsUnitConversion.h" +#include "nsIContent.h" +#include "nsHTMLAtoms.h" +#include "nsHTMLValue.h" +#include "nsIHTMLContent.h" +#include "nsHTMLIIDs.h" +#include "nsIPresShell.h" +#include "prprf.h" + +// XXX TODO: +// 1. If container is RTL then place bullets on the right side +// 2. list-style-image +// 3. proper ascent alignment +// 4. number bullets correctly when dealing with
  • +// 5. size and render circle, square, disc bullets like nav4 does + +static NS_DEFINE_IID(kStyleFontSID, NS_STYLEFONT_SID); +static NS_DEFINE_IID(kStyleColorSID, NS_STYLECOLOR_SID); +static NS_DEFINE_IID(kStyleListSID, NS_STYLELIST_SID); + +/** + * A pseudo-frame class that reflows the list item bullet. + */ +class BulletFrame : public nsContainerFrame { +public: + BulletFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + virtual ~BulletFrame(); + + virtual void Paint(nsIPresContext &aCX, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + virtual ReflowStatus ResizeReflow(nsIPresContext* aCX, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + + virtual ReflowStatus IncrementalReflow(nsIPresContext* aCX, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand); + + void GetBulletSize(nsIPresContext* aCX, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize); + + PRInt32 GetListItemOrdinal(nsIPresContext* aCX, nsStyleList& aMol); + + void GetListItemText(nsIPresContext* aCX, nsString& aResult, + nsStyleList& aMol); + + PRPackedBool mOrdinalValid; + PRInt32 mOrdinal; +}; + +BulletFrame::BulletFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsContainerFrame(aContent, aIndexInParent, aParentFrame) +{ +} + +BulletFrame::~BulletFrame() +{ +} + +// XXX padding for around the bullet; should come from style system +#define PAD_DISC NS_POINTS_TO_TWIPS_INT(1) + +void BulletFrame::Paint(nsIPresContext& aCX, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + nsStyleFont* myFont = + (nsStyleFont*)mStyleContext->GetData(kStyleFontSID); + nsStyleColor* myColor = + (nsStyleColor*)mStyleContext->GetData(kStyleColorSID); + nsStyleList* myList = + (nsStyleList*)mStyleContext->GetData(kStyleListSID); + nsIFontMetrics* fm = aCX.GetMetricsFor(myFont->mFont); + + nscoord pad; + + nsAutoString text; + switch (myList->mListStyleType) { + case NS_STYLE_LIST_STYLE_NONE: + break; + + case NS_STYLE_LIST_STYLE_DISC: + case NS_STYLE_LIST_STYLE_CIRCLE: + case NS_STYLE_LIST_STYLE_SQUARE: + pad = PAD_DISC; + aRenderingContext.SetColor(myColor->mColor); + aRenderingContext.FillRect(pad, pad, mRect.width - (pad + pad), + mRect.height - (pad + pad));/* XXX */ + break; + + case NS_STYLE_LIST_STYLE_DECIMAL: + case NS_STYLE_LIST_STYLE_LOWER_ROMAN: + case NS_STYLE_LIST_STYLE_UPPER_ROMAN: + case NS_STYLE_LIST_STYLE_LOWER_ALPHA: + case NS_STYLE_LIST_STYLE_UPPER_ALPHA: + GetListItemText(&aCX, text, *myList); + aRenderingContext.SetColor(myColor->mColor); + aRenderingContext.SetFont(myFont->mFont); + aRenderingContext.DrawString(text, 0, 0, fm->GetWidth(text)); + break; + } + NS_RELEASE(fm); +} + +nsIFrame::ReflowStatus +BulletFrame::ResizeReflow(nsIPresContext* aCX, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ + GetBulletSize(aCX, aDesiredSize, aMaxSize); + if (nsnull != aMaxElementSize) { + aMaxElementSize->width = aDesiredSize.width; + aMaxElementSize->height = aDesiredSize.height; + } + + // This is done so that our containers VerifyTree code will work + // correctly. Otherwise it will think that the child that follows + // the bullet must be mapping the second content object instead of + // mapping the first content object. + mLastContentIsComplete = PR_FALSE; + + return frComplete; +} + +nsIFrame::ReflowStatus +BulletFrame::IncrementalReflow(nsIPresContext* aCX, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand) +{ + // XXX Unless the reflow command is a style change, we should + // just return the current size, otherwise we should invoke + // GetBulletSize + GetBulletSize(aCX, aDesiredSize, aMaxSize); + + return frComplete; +} + +PRInt32 BulletFrame::GetListItemOrdinal(nsIPresContext* aCX, + nsStyleList& aListStyle) +{ + if (mOrdinalValid) { + return mOrdinal; + } + + PRInt32 ordinal = 0; + + // Get block reflow state for the list container + nsListItemFrame* listItem = (nsListItemFrame*) mGeometricParent; + nsBlockReflowState* state = listItem->GetListContainerReflowState(aCX); + + // Try to get value directly from the list-item, if it specifies a + // value attribute. + nsHTMLValue value; + nsIHTMLContent* html = (nsIHTMLContent*) mContent; + if (eContentAttr_HasValue == html->GetAttribute(nsHTMLAtoms::value, value)) { + if (eHTMLUnit_Absolute == value.GetUnit()) { + ordinal = value.GetIntValue(); + if (nsnull != state) { + state->nextListOrdinal = ordinal + 1; + } + goto done; + } + } + + // Get ordinal from block reflow state + if (nsnull != state) { + ordinal = state->nextListOrdinal; + if (ordinal < 0) { + // This is the first list item and the list container doesn't + // have a "start" attribute. Get the starting ordinal value + // correctly set. + switch (aListStyle.mListStyleType) { + case NS_STYLE_LIST_STYLE_DECIMAL: + ordinal = 1; + break; + default: + ordinal = 0; + break; + } + } + state->nextListOrdinal = ordinal + 1; + } + + done: + mOrdinal = ordinal; + mOrdinalValid = PR_TRUE; + return ordinal; +} + +static const char* gLowerRomanCharsA = "ixcm"; +static const char* gUpperRomanCharsA = "IXCM"; +static const char* gLowerRomanCharsB = "vld?"; +static const char* gUpperRomanCharsB = "VLD?"; +static const char* gLowerAlphaChars = "abcdefghijklmnopqrstuvwxyz"; +static const char* gUpperAlphaChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +void +BulletFrame::GetListItemText(nsIPresContext* aCX, + nsString& result, + nsStyleList& aListStyle) +{ + PRInt32 ordinal = GetListItemOrdinal(aCX, aListStyle); + char cbuf[40]; + switch (aListStyle.mListStyleType) { + case NS_STYLE_LIST_STYLE_DECIMAL: + PR_snprintf(cbuf, sizeof(cbuf), "%ld", ordinal); + result.Append(cbuf); + break; + + case NS_STYLE_LIST_STYLE_LOWER_ROMAN: + case NS_STYLE_LIST_STYLE_UPPER_ROMAN: + { + // XXX deal with an ordinal of ZERO + nsAutoString addOn; + nsAutoString decStr; + decStr.Append(ordinal, 10); + const PRUnichar* dp = decStr.GetUnicode(); + const PRUnichar* end = dp + decStr.Length(); + + PRIntn len=decStr.Length(); + PRIntn romanPos=len; + PRIntn n; + PRBool negative=PRBool(ordinal<0); + + const char* achars; + const char* bchars; + if (aListStyle.mListStyleType == NS_STYLE_LIST_STYLE_LOWER_ROMAN) { + achars = gLowerRomanCharsA; + bchars = gLowerRomanCharsB; + } else { + achars = gUpperRomanCharsA; + bchars = gUpperRomanCharsB; + } + ordinal=(ordinal < 0) ? -ordinal : ordinal; + if (ordinal < 0) { + // XXX max negative int + break; + } + for (; dp < end; dp++) + { + romanPos--; + addOn.SetLength(0); + switch(*dp) + { + case '3': addOn.Append(achars[romanPos]); + case '2': addOn.Append(achars[romanPos]); + case '1': addOn.Append(achars[romanPos]); + break; + + case '4': + addOn.Append(achars[romanPos]); + + case '5': case '6': + case '7': case '8': + addOn.Append(bchars[romanPos]); + for(n=0;n<(*dp-'5');n++) { + addOn.Append(achars[romanPos]); + } + break; + case '9': + addOn.Append(achars[romanPos]); + addOn.Append(achars[romanPos+1]); + break; + default: + break; + } + result.Append(addOn); + } + } + break; + + case NS_STYLE_LIST_STYLE_LOWER_ALPHA: + case NS_STYLE_LIST_STYLE_UPPER_ALPHA: + { + PRInt32 anOffset = -1; + PRInt32 aBase = 26; + PRInt32 ndex=0; + PRInt32 root=1; + PRInt32 next=aBase; + PRInt32 expn=1; + const char* chars = + (aListStyle.mListStyleType == NS_STYLE_LIST_STYLE_LOWER_ALPHA) + ? gLowerAlphaChars : gUpperAlphaChars; + + // must be positive here... + ordinal = (ordinal < 0) ? -ordinal : ordinal; + if (ordinal < 0) { + // XXX max negative int + break; + } + while (next<=ordinal) // scale up in baseN; exceed current value. + { + root=next; + next*=aBase; + expn++; + } + + while(0!=(expn--)) + { + ndex = ((root<=ordinal) && (0!=root)) ? (ordinal/root): 0; + ordinal %= root; + if (root>1) + result.Append(chars[ndex+anOffset]); + else + result.Append(chars[ndex]); + root /= aBase; + } + } + break; + } + result.Append("."); +} + +void BulletFrame::GetBulletSize(nsIPresContext* aCX, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize) +{ + nsStyleList* myList = + (nsStyleList*)mStyleContext->GetData(kStyleListSID); + nsStyleFont* myFont = + (nsStyleFont*)mStyleContext->GetData(kStyleFontSID); + + nscoord pad; + + nsIFontMetrics* fm = aCX->GetMetricsFor(myFont->mFont); + nsAutoString text; + switch (myList->mListStyleType) { + case NS_STYLE_LIST_STYLE_NONE: + aDesiredSize.width = 0; + aDesiredSize.height = 0; + aDesiredSize.ascent = 0; + aDesiredSize.descent = 0; + break; + + case NS_STYLE_LIST_STYLE_DISC: + case NS_STYLE_LIST_STYLE_CIRCLE: + case NS_STYLE_LIST_STYLE_SQUARE: + /* XXX match navigator */ + pad = PAD_DISC; + aDesiredSize.width = pad + pad + fm->GetWidth('x'); + aDesiredSize.height = pad + pad + fm->GetWidth('x'); + aDesiredSize.ascent = pad + fm->GetWidth('x'); + aDesiredSize.descent = pad; + break; + + case NS_STYLE_LIST_STYLE_DECIMAL: + case NS_STYLE_LIST_STYLE_LOWER_ROMAN: + case NS_STYLE_LIST_STYLE_UPPER_ROMAN: + case NS_STYLE_LIST_STYLE_LOWER_ALPHA: + case NS_STYLE_LIST_STYLE_UPPER_ALPHA: + GetListItemText(aCX, text, *myList); + if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == myList->mListStylePosition) { + // Inside bullets need some extra width to get the padding + // between the list item and the content that follows. + pad = fm->GetHeight() / 2; // From old layout engine + } else { + // Outside bullets get there padding by placement not by sizing + pad = 0; + } + aDesiredSize.width = pad + fm->GetWidth(text); + aDesiredSize.height = fm->GetHeight(); + aDesiredSize.ascent = fm->GetMaxAscent(); + aDesiredSize.descent = fm->GetMaxDescent(); + break; + } + NS_RELEASE(fm); +} + +//---------------------------------------------------------------------- + +nsresult nsListItemFrame::NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIFrame* it = new nsListItemFrame(aContent, aIndexInParent, aParent); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aInstancePtrResult = it; + return NS_OK; +} + +nsListItemFrame::nsListItemFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) + : nsBlockFrame(aContent, aIndexInParent, aParent) +{ +} + +nsListItemFrame::~nsListItemFrame() +{ +} + +nsIFrame* nsListItemFrame::CreateBullet() +{ + // Create bullet. The bullet shares the same style context as + // ourselves. + nsIFrame* bullet = new BulletFrame(mContent, mIndexInParent, this); + bullet->SetStyleContext(mStyleContext); + return bullet; +} + +void nsListItemFrame::PlaceOutsideBullet(nsIFrame* aBullet, + nsIPresContext* aCX) +{ + nsSize maxSize(0, 0); + nsReflowMetrics bulletSize; + + // Size the bullet + ReflowChild(aBullet, aCX, bulletSize, maxSize, nsnull); + + // We can only back the bullet over so far XXX what does nav do with + // a big bullet in a blockquote? does the bullet leak out of the + // blockquote or what? + nscoord minX = -mRect.x; + + // Get bullet style (which is our style) + nsStyleFont* font = + (nsStyleFont*)mStyleContext->GetData(kStyleFontSID); + nsIFontMetrics* fm = aCX->GetMetricsFor(font->mFont); + nscoord kidAscent = fm->GetMaxAscent(); + nscoord dx = fm->GetHeight() / 2; // from old layout engine + NS_RELEASE(fm); + + // Find the bullet x,y + nscoord x = 0; + nscoord y = 0; +#if 0 + nsIFrame* firstKid = mFirstChild; + if (nsnull != firstKid) { + nsIContent* kidContent = firstKid->GetContent(); + nsIStyleContext* kidStyleContext = firstKid->GetStyleContext(aCX); + nsStyleFont* kidFont = + (nsStyleFont*)kidStyleContext->GetData(kStyleFontSID); + nsPoint origin; + firstKid->GetOrigin(origin); + // XXX this is wrong if the first kid was relative positioned! + x = origin.x; + y = origin.y; + // XXX This is an approximation. If the kid has borders and + // padding then this value will be wrong. If the kid is a + // container then margins may mess it up as well. + nsIFontMetrics* fm = aCX->GetMetricsFor(kidFont->mFont); + kidAscent = fm->GetMaxAscent(); + NS_RELEASE(fm); + + NS_RELEASE(kidStyleContext); + NS_RELEASE(kidContent); + } +#endif + + x = x - dx - bulletSize.width; +#if XXX + // XXX can't do this yet: 1. our mRect value is not right on the + // first reflow; 2. it's the wrong limiter: nav4 compares against + // the window min x. + if (x < minX) { + x = minX; + } +#endif + y = y + kidAscent - bulletSize.ascent; + + aBullet->SetRect(nsRect(x, y, bulletSize.width, bulletSize.height)); +} + +// Return the reflow state for the list container that contains this +// list item frame. There may be no list container (a dangling LI) +// therefore this may return nsnull. +nsBlockReflowState* +nsListItemFrame::GetListContainerReflowState(nsIPresContext* aCX) +{ + nsBlockReflowState* state = nsnull; + nsIFrame* parent = mGeometricParent; + while (nsnull != parent) { + nsIHTMLFrameType* ft; + nsresult status = parent->QueryInterface(kIHTMLFrameTypeIID, (void**) &ft); + if (NS_OK == status) { + nsHTMLFrameType type = ft->GetFrameType(); + if (eHTMLFrame_Block == type) { + // The parent is a block. See if its content object is a list + // container. Only UL, OL, MENU or DIR can be list containers. + // XXX need something more flexible, say style? + nsIContent* parentContent = parent->GetContent(); + nsIAtom* tag = parentContent->GetTag(); + NS_RELEASE(parentContent); + if ((tag == nsHTMLAtoms::ul) || (tag == nsHTMLAtoms::ol) || + (tag == nsHTMLAtoms::menu) || (tag == nsHTMLAtoms::dir)) { + NS_RELEASE(tag); + break; + } + NS_RELEASE(tag); + } + } + parent = parent->GetGeometricParent(); + } + if (nsnull != parent) { + nsIPresShell* shell = aCX->GetShell(); + state = (nsBlockReflowState*) shell->GetCachedData(parent); + NS_RELEASE(shell); + } + return state; +} + +/** + * The basic approach here is pretty simple: let our base class do all + * the hard work, and after it's done, get the bullet placed. We only + * have a bullet if we are not a continuation. + */ +// XXX we may need to grow to accomodate the bullet +// XXX check for compatability:
  • dah dah

    where is bullet? +nsIFrame::ReflowStatus +nsListItemFrame::ResizeReflow(nsIPresContext* aCX, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsSize* aMaxElementSize) +{ + PRBool insideBullet = PR_FALSE; + + // Get bullet style (which is our style) + nsStyleList* myList = + (nsStyleList*)mStyleContext->GetData(kStyleListSID); + if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == myList->mListStylePosition) { + insideBullet = PR_TRUE; + } + + nsIFrame* bullet = nsnull; + if (nsnull == mPrevInFlow) { + if (insideBullet) { + if (nsnull == mFirstChild) { + // Inside bullets get placed on the list immediately so that + // the regular reflow logic can place them. + bullet = CreateBullet(); + mFirstChild = bullet; + mChildCount++; + } else { + // We already have a first child. It's the bullet (check?) + // so we don't need to do anything here + } + } else { + if (nsnull == mFirstChild) { + // Create outside bullet the first time through + bullet = CreateBullet(); + } else { + // Pull bullet off list (we'll put it back later) + bullet = mFirstChild; + mFirstChild = bullet->GetNextSibling(); + mChildCount--; + } + } + } + + // Let base class do things first + nsBlockReflowState state; + SetupState(aCX, state, aMaxSize, aMaxElementSize, aSpaceManager); + state.firstChildIsInsideBullet = insideBullet; + ReflowStatus rv = DoResizeReflow(aCX, state, aDesiredRect); + + // Now place the bullet and put it at the head of the list of children + if (!insideBullet && (nsnull != bullet)) { + // XXX Change PlaceOutsideBullet to just size the bullet frame, then let + // the normal vertical alignment code run. The reason it's not + // implemented yet is that I don't have the ascent/descent + // information for the first line. + PlaceOutsideBullet(bullet, aCX); + bullet->SetNextSibling(mFirstChild); + mFirstChild = bullet; + mChildCount++; + if (nsnull == mLines) { + mLines = new PRInt32[1]; + mLines[0] = 1; + mNumLines = 1; + } else { + mLines[0]++; + } + } + return rv; +} + +// XXX we may need to grow to accomodate the bullet +nsIFrame::ReflowStatus +nsListItemFrame::IncrementalReflow(nsIPresContext* aCX, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsReflowCommand& aReflowCommand) +{ + return frComplete; +} + +nsIFrame* nsListItemFrame::CreateContinuingFrame(nsIPresContext* aCX, + nsIFrame* aParent) +{ + nsListItemFrame* cf = new nsListItemFrame(mContent, mIndexInParent, aParent); + PrepareContinuingFrame(aCX, aParent, cf); + return cf; +} + +// aDirtyRect is in our coordinate system +// child rect's are also in our coordinate system +void nsListItemFrame::PaintChildren(nsIPresContext& aCX, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + nsIFrame* kid = mFirstChild; + while (nsnull != kid) { + nsRect kidRect; + kid->GetRect(kidRect); + nsRect damageArea; + PRBool overlap = damageArea.IntersectRect(aDirtyRect, kidRect); + // Note the special check here for our first child. We do this + // because we sometimes position bullets (our first child) outside + // of our frame. + if (overlap || (kid == mFirstChild)) { + // Translate damage area into kid's coordinate system + nsRect kidDamageArea(damageArea.x - kidRect.x, damageArea.y - kidRect.y, + damageArea.width, damageArea.height); + aRenderingContext.PushState(); + aRenderingContext.Translate(kidRect.x, kidRect.y); + kid->Paint(aCX, aRenderingContext, kidDamageArea); + if (nsIFrame::GetShowFrameBorders()) { + aRenderingContext.SetColor(NS_RGB(255,0,0)); + aRenderingContext.DrawRect(0, 0, kidRect.width, kidRect.height); + } + aRenderingContext.PopState(); + } + kid = kid->GetNextSibling(); + } +} diff --git a/mozilla/layout/html/base/src/nsListItemFrame.h b/mozilla/layout/html/base/src/nsListItemFrame.h new file mode 100644 index 00000000000..7da487cfcf5 --- /dev/null +++ b/mozilla/layout/html/base/src/nsListItemFrame.h @@ -0,0 +1,70 @@ +/* -*- 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. + */ +#ifndef nsListItemFrame_h___ +#define nsListItemFrame_h___ + +#include "nsBlockFrame.h" + +class nsListItemFrame : public nsBlockFrame +{ +public: + static nsresult NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + virtual ReflowStatus ResizeReflow(nsIPresContext* aCX, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsSize* aMaxElementSize); + + virtual ReflowStatus IncrementalReflow(nsIPresContext* aCX, + nsISpaceManager* aSpaceManager, + const nsSize& aMaxSize, + nsRect& aDesiredRect, + nsReflowCommand& aReflowCommand); + + virtual nsIFrame* CreateContinuingFrame(nsIPresContext* aCX, + nsIFrame* aParent); + + /** + * Return the reflow state for the list container that contains this + * list item frame. There may be no list container (a dangling LI) + * therefore this may return nsnull. + */ + nsBlockReflowState* GetListContainerReflowState(nsIPresContext* aCX); + +protected: + nsListItemFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + virtual ~nsListItemFrame(); + + nsIFrame* CreateBullet(); + + virtual void PaintChildren(nsIPresContext& aCX, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + void PlaceOutsideBullet(nsIFrame* aBullet, + nsIPresContext* aCX); +}; + +#endif /* nsListItemFrame_h___ */ diff --git a/mozilla/layout/html/base/src/nsPageFrame.cpp b/mozilla/layout/html/base/src/nsPageFrame.cpp new file mode 100644 index 00000000000..858422d7f5c --- /dev/null +++ b/mozilla/layout/html/base/src/nsPageFrame.cpp @@ -0,0 +1,178 @@ +/* -*- 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 "nsPageFrame.h" +#include "nsIContent.h" +#include "nsIContentDelegate.h" +#include "nsIPresContext.h" +#include "nsIStyleContext.h" +#include "nsReflowCommand.h" +#include "nsIRenderingContext.h" + +PageFrame::PageFrame(nsIContent* aContent, nsIFrame* aParent) + : nsContainerFrame(aContent, aParent->GetIndexInParent(), aParent) +{ +} + +void PageFrame::CreateFirstChild(nsIPresContext* aPresContext) +{ + // Create a frame for our one and only content child + if (mContent->ChildCount() > 0) { + nsIContent* child = mContent->ChildAt(0); + + if (nsnull != child) { + // Create a frame + nsIContentDelegate* cd = child->GetDelegate(aPresContext); + if (nsnull != cd) { + mFirstChild = cd->CreateFrame(aPresContext, child, 0, this); + if (nsnull != mFirstChild) { + mChildCount = 1; + mLastContentOffset = mFirstContentOffset; + + // Resolve style and set the style context + nsIStyleContext* kidStyleContext = + aPresContext->ResolveStyleContextFor(child, this); + mFirstChild->SetStyleContext(kidStyleContext); + NS_RELEASE(kidStyleContext); + } + NS_RELEASE(cd); + } + NS_RELEASE(child); + } + } +} + +nsIFrame::ReflowStatus +PageFrame::ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ +#ifdef NS_DEBUG + PreReflowCheck(); +#endif + ReflowStatus result = frComplete; + + // Do we have any children? + if (nsnull == mFirstChild) { + if (nsnull == mPrevInFlow) { + // Create the first child frame + CreateFirstChild(aPresContext); + } else { + PageFrame* prevPage = (PageFrame*)mPrevInFlow; + + NS_ASSERTION(!prevPage->mLastContentIsComplete, "bad continuing page"); + nsIFrame* prevLastChild = prevPage->LastChild(); + + // Create a continuing child of the previous page's last child + mFirstChild = prevLastChild->CreateContinuingFrame(aPresContext, this); + mChildCount = 1; + mLastContentOffset = mFirstContentOffset; + } + } + + // Resize our frame allowing it only to be as big as we are + // XXX Pay attention to the page's border and padding... + if (nsnull != mFirstChild) { + // Get the child's desired size + result = ReflowChild(mFirstChild, aPresContext, aDesiredSize, aMaxSize, + aMaxElementSize); + mLastContentIsComplete = PRBool(result == frComplete); + + // Make sure the child is at least as tall as our max size (the containing window) + if (aDesiredSize.height < aMaxSize.height) { + aDesiredSize.height = aMaxSize.height; + } + + // Place and size the child + nsRect rect(0, 0, aDesiredSize.width, aDesiredSize.height); + mFirstChild->SetRect(rect); + + // Is the frame complete? + if (frComplete == result) { + NS_ASSERTION(nsnull == mFirstChild->GetNextInFlow(), "bad child flow list"); + } + } + + // Return our desired size + aDesiredSize.width = aMaxSize.width; + aDesiredSize.height = aMaxSize.height; + +#ifdef NS_DEBUG + PostReflowCheck(result); +#endif + return result; +} + +// XXX Do something sensible in page mode... +nsIFrame::ReflowStatus +PageFrame::IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand) +{ + // We don't expect the target of the reflow command to be page frame + NS_ASSERTION(aReflowCommand.GetTarget() != this, "page frame is reflow command target"); + + nsSize maxSize(aMaxSize.width, NS_UNCONSTRAINEDSIZE); + ReflowStatus status; + nsIFrame* child; + + // Dispatch the reflow command to our pseudo frame. Allow it to be as high + // as it wants + status = aReflowCommand.Next(aDesiredSize, maxSize, child); + + // Place and size the child. Make sure the child is at least as + // tall as our max size (the containing window) + if (nsnull != child) { + NS_ASSERTION(child == mFirstChild, "unexpected reflow command frame"); + if (aDesiredSize.height < aMaxSize.height) { + aDesiredSize.height = aMaxSize.height; + } + + nsRect rect(0, 0, aDesiredSize.width, aDesiredSize.height); + child->SetRect(rect); + } + + return status; +} + +nsIFrame* PageFrame::CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent) +{ + PageFrame* cf = new PageFrame(mContent, aParent); + PrepareContinuingFrame(aPresContext, aParent, cf); + return cf; +} + +void PageFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + nsContainerFrame::Paint(aPresContext, aRenderingContext, aDirtyRect); + + // For the time being paint a border around the page so we know + // where each page begins and ends + aRenderingContext.SetColor(NS_RGB(0, 0, 0)); + aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height); +} + +void PageFrame::ListTag(FILE* out) const +{ + fprintf(out, "*PAGE@%p", this); +} + diff --git a/mozilla/layout/html/base/src/nsPageFrame.h b/mozilla/layout/html/base/src/nsPageFrame.h new file mode 100644 index 00000000000..b3d8387c8f5 --- /dev/null +++ b/mozilla/layout/html/base/src/nsPageFrame.h @@ -0,0 +1,53 @@ +/* -*- 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. + */ +#ifndef nsPageFrame_h___ +#define nsPageFrame_h___ + +#include "nsHTMLContainerFrame.h" + +// Pseudo frame created by the root content frame +class PageFrame : public nsContainerFrame { +public: + PageFrame(nsIContent* aContent, nsIFrame* aParent); + + virtual ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + + virtual ReflowStatus IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand); + + virtual nsIFrame* CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent); + + virtual void Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + // Debugging + virtual void ListTag(FILE* out = stdout) const; + +protected: + void CreateFirstChild(nsIPresContext* aPresContext); +}; + +#endif /* nsPageFrame_h___ */ + diff --git a/mozilla/layout/html/base/src/nsPlaceholderFrame.cpp b/mozilla/layout/html/base/src/nsPlaceholderFrame.cpp new file mode 100644 index 00000000000..1028f477461 --- /dev/null +++ b/mozilla/layout/html/base/src/nsPlaceholderFrame.cpp @@ -0,0 +1,101 @@ +/* -*- 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 "nsPlaceholderFrame.h" +#include "nsIContent.h" +#include "nsIContentDelegate.h" +#include "nsIFloaterContainer.h" + +static NS_DEFINE_IID(kIFloaterContainerIID, NS_IFLOATERCONTAINER_IID); + +nsresult +PlaceholderFrame::NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIFrame* it = new PlaceholderFrame(aContent, aIndexInParent, aParent); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aInstancePtrResult = it; + return NS_OK; +} + +PlaceholderFrame::PlaceholderFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) + : nsFrame(aContent, aIndexInParent, aParent) +{ + mAnchoredItem = nsnull; +} + +PlaceholderFrame::~PlaceholderFrame() +{ +} + +nsIFrame::ReflowStatus +PlaceholderFrame::ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ + // Get the floater container in which we're inserted + nsIFloaterContainer* container = nsnull; + + for (nsIFrame* parent = mGeometricParent; parent; parent = parent->GetGeometricParent()) { + if (NS_OK == parent->QueryInterface(kIFloaterContainerIID, (void**)&container)) { + break; + } + } + NS_ASSERTION(nsnull != container, "no floater container"); + + // Have we created the anchored item yet? + if (nsnull == mAnchoredItem) { + // Create the anchored item + nsIContentDelegate* delegate = mContent->GetDelegate(aPresContext); + + mAnchoredItem = delegate->CreateFrame(aPresContext, mContent, mIndexInParent, + mGeometricParent); + NS_RELEASE(delegate); + + // Set the style context for the frame + mAnchoredItem->SetStyleContext(mStyleContext); + + // Resize reflow the anchored item into the available space + // XXX Check for complete? + mAnchoredItem->ResizeReflow(aPresContext, aDesiredSize, aMaxSize, nsnull); + mAnchoredItem->SizeTo(aDesiredSize.width, aDesiredSize.height); + + // Now notify our containing block that there's a new floater + container->AddFloater(aPresContext, mAnchoredItem, this); + } else { + container->PlaceFloater(aPresContext, mAnchoredItem, this); + } + + return nsFrame::ResizeReflow(aPresContext, aDesiredSize, aMaxSize, aMaxElementSize); +} + +void PlaceholderFrame::ListTag(FILE* out) const +{ + fputs("*placeholder", out); + fprintf(out, "(%d)@%p", mIndexInParent, this); +} diff --git a/mozilla/layout/html/base/src/nsPlaceholderFrame.h b/mozilla/layout/html/base/src/nsPlaceholderFrame.h new file mode 100644 index 00000000000..b3b87673539 --- /dev/null +++ b/mozilla/layout/html/base/src/nsPlaceholderFrame.h @@ -0,0 +1,57 @@ +/* -*- 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. + */ +#ifndef nsPlaceholderFrame_h___ +#define nsPlaceholderFrame_h___ + +#include "nsFrame.h" + +// Implementation of a frame that's used as a placeholder for an anchored item +class PlaceholderFrame : public nsFrame +{ +public: + /** + * Create a new placeholder frame + */ + static nsresult NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + // Returns the associated anchored item + nsIFrame* GetAnchoredItem() const {return mAnchoredItem;} + + // Resize reflow methods + virtual ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + virtual void ListTag(FILE* out = stdout) const; + +protected: + // Constructor. Takes as arguments the content object, the index in parent, + // and the Frame for the content parent + PlaceholderFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + virtual ~PlaceholderFrame(); + + nsIFrame* mAnchoredItem; +}; + +#endif /* nsPlaceholderFrame_h___ */ diff --git a/mozilla/layout/html/base/src/nsRootPart.cpp b/mozilla/layout/html/base/src/nsRootPart.cpp new file mode 100644 index 00000000000..955fb98cef9 --- /dev/null +++ b/mozilla/layout/html/base/src/nsRootPart.cpp @@ -0,0 +1,483 @@ +/* -*- 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 "nsHTMLParts.h" +#include "nsHTMLContainer.h" +#include "nsContainerFrame.h" +#include "nsIDocument.h" +#include "nsReflowCommand.h" +#include "nsIPresContext.h" +#include "nsIStyleContext.h" +#include "nsViewsCID.h" +#include "nsIView.h" +#include "nsIViewManager.h" +#include "nsIContentDelegate.h" +#include "nsIWidget.h" +#include "nsHTMLIIDs.h" +#include "nsPageFrame.h" +#include "nsIRenderingContext.h" +#include "nsIDeviceContext.h" +#include "nsGUIEvent.h" +#include "nsStyleConsts.h" +#include "nsIViewManager.h" + +class RootFrame : public nsContainerFrame { +public: + RootFrame(nsIContent* aContent); + + virtual ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + + virtual ReflowStatus IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand); + + virtual nsEventStatus HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent); +}; + +// Pseudo frame created by the root frame +class RootContentFrame : public nsContainerFrame { +public: + RootContentFrame(nsIContent* aContent, nsIFrame* aParent); + + virtual ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + + virtual ReflowStatus IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand); + + virtual void Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + +protected: + void CreateFirstChild(nsIPresContext* aPresContext); +}; + +//---------------------------------------------------------------------- + +RootFrame::RootFrame(nsIContent* aContent) + : nsContainerFrame(aContent, -1, nsnull) +{ +} + +nsIFrame::ReflowStatus RootFrame::ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ +#ifdef NS_DEBUG + PreReflowCheck(); +#endif + nsIFrame::ReflowStatus result = frComplete; + + // Do we have any children? + if (nsnull == mFirstChild) { + // No. Create a pseudo frame + mFirstChild = new RootContentFrame(mContent, this); + mChildCount = 1; + nsIStyleContext* style = aPresContext->ResolveStyleContextFor(mContent, this); + mFirstChild->SetStyleContext(style); + NS_RELEASE(style); + } + + // Resize the pseudo frame passing it our max size. It will choose whatever + // height its child frame wants... + if (nsnull != mFirstChild) { + nsReflowMetrics desiredSize; + result = ReflowChild(mFirstChild, aPresContext, desiredSize, aMaxSize, + aMaxElementSize); + + // Place and size the child + nsRect rect(0, 0, desiredSize.width, desiredSize.height); + mFirstChild->SetRect(rect); + } + mLastContentOffset = ((RootContentFrame*)mFirstChild)->GetLastContentOffset(); + + // Return the max size as our desired size + aDesiredSize.width = aMaxSize.width; + aDesiredSize.height = aMaxSize.height; + aDesiredSize.ascent = aMaxSize.height; + aDesiredSize.descent = 0; + +#ifdef NS_DEBUG + PostReflowCheck(result); +#endif + return result; +} + +nsIFrame::ReflowStatus +RootFrame::IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand) +{ + // We don't expect the target of the reflow command to be the root frame + NS_ASSERTION(aReflowCommand.GetTarget() != this, "root frame is reflow command target"); + + nsReflowMetrics desiredSize; + nsIFrame* child; + ReflowStatus status; + + // Dispatch the reflow command to our pseudo frame + status = aReflowCommand.Next(desiredSize, aMaxSize, child); + + // Place and size the child + if (nsnull != child) { + NS_ASSERTION(child == mFirstChild, "unexpected reflow command frame"); + + nsRect rect(0, 0, desiredSize.width, desiredSize.height); + child->SetRect(rect); + } + + // Return the max size as our desired size + aDesiredSize.width = aMaxSize.width; + aDesiredSize.height = aMaxSize.height; + aDesiredSize.ascent = aMaxSize.height; + aDesiredSize.descent = 0; + return status; +} + +nsEventStatus RootFrame::HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent) +{ + switch (aEvent->message) { + case NS_MOUSE_MOVE: + case NS_MOUSE_ENTER: + { + nsIFrame* target = this; + PRInt32 cursor = GetCursorAt(aPresContext, aEvent->point, &target); + if (cursor == NS_STYLE_CURSOR_INHERIT) { + cursor = NS_STYLE_CURSOR_DEFAULT; + } + nsCursor c; + switch (cursor) { + default: + case NS_STYLE_CURSOR_DEFAULT: + c = eCursor_standard; + break; + case NS_STYLE_CURSOR_HAND: + c = eCursor_hyperlink; + break; + case NS_STYLE_CURSOR_IBEAM: + c = eCursor_select; + break; + } + nsIWidget* window = target->GetWindow(); + window->SetCursor(c); + } + break; + } + + return nsEventStatus_eIgnore; +} + +//---------------------------------------------------------------------- + +RootContentFrame::RootContentFrame(nsIContent* aContent, nsIFrame* aParent) + : nsContainerFrame(aContent, aParent->GetIndexInParent(), aParent) +{ + // Create a view + nsIFrame* parent = GetParentWithView(); + nsIView* view; + + NS_ASSERTION(parent, "GetParentWithView failed"); + nsIView* parView = parent->GetView(); + NS_ASSERTION(parView, "no parent with view"); + + // Create a view + static NS_DEFINE_IID(kViewCID, NS_VIEW_CID); + static NS_DEFINE_IID(kIViewIID, NS_IVIEW_IID); + + nsresult result = NSRepository::CreateInstance(kViewCID, + nsnull, + kIViewIID, + (void **)&view); + if (NS_OK == result) { + nsIView* rootView = parView; + nsIViewManager* viewManager = rootView->GetViewManager(); + + // Initialize the view + NS_ASSERTION(nsnull != viewManager, "null view manager"); + + view->Init(viewManager, GetRect(), rootView); + viewManager->InsertChild(rootView, view, 0); + + NS_RELEASE(viewManager); + + // Remember our view + SetView(view); + NS_RELEASE(view); + } + NS_RELEASE(parView); +} + +void RootContentFrame::CreateFirstChild(nsIPresContext* aPresContext) +{ + // Are we paginated? + if (aPresContext->IsPaginated()) { + // Yes. Create the first page frame + mFirstChild = new PageFrame(mContent, this); + mChildCount = 1; + mLastContentOffset = mFirstContentOffset; + + } else { + // Create a frame for our one and only content child + if (mContent->ChildCount() > 0) { + nsIContent* child = mContent->ChildAt(0); + + if (nsnull != child) { + // Create a frame + nsIContentDelegate* cd = child->GetDelegate(aPresContext); + if (nsnull != cd) { + mFirstChild = cd->CreateFrame(aPresContext, child, 0, this); + if (nsnull != mFirstChild) { + mChildCount = 1; + mLastContentOffset = mFirstContentOffset; + + // Resolve style and set the style context + nsIStyleContext* kidStyleContext = + aPresContext->ResolveStyleContextFor(child, this); + mFirstChild->SetStyleContext(kidStyleContext); + NS_RELEASE(kidStyleContext); + } + NS_RELEASE(cd); + } + NS_RELEASE(child); + } + } + } +} + +// XXX Hack +#define PAGE_SPACING 100 + +nsIFrame::ReflowStatus +RootContentFrame::ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ +#ifdef NS_DEBUG + PreReflowCheck(); +#endif + nsIFrame::ReflowStatus result = frComplete; + + // Do we have any children? + if (nsnull == mFirstChild) { + // No, create the first child frame + CreateFirstChild(aPresContext); + } + + // Resize our frames + if (nsnull != mFirstChild) { + if (aPresContext->IsPaginated()) { + nscoord y = PAGE_SPACING; + nsReflowMetrics kidSize; + nsSize pageSize(aPresContext->GetPageWidth(), + aPresContext->GetPageHeight()); + + // Tile the pages vertically + for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; ) { + // Reflow the page + ReflowStatus status = ReflowChild(kidFrame, aPresContext, kidSize, + pageSize, aMaxElementSize); + + // Place and size the page. If the page is narrower than our max width then + // center it horizontally + nsIDeviceContext *dx = aPresContext->GetDeviceContext(); + PRInt32 extra = aMaxSize.width - kidSize.width - NS_TO_INT_ROUND(dx->GetScrollBarWidth()); + NS_RELEASE(dx); + kidFrame->SetRect(nsRect(extra > 0 ? extra / 2 : 0, y, kidSize.width, kidSize.height)); + y += kidSize.height; + + // Leave a slight gap between the pages + y += PAGE_SPACING; + + // Is the page complete? + nsIFrame* nextInFlow = kidFrame->GetNextInFlow(); + + if (frComplete == status) { + NS_ASSERTION(nsnull == kidFrame->GetNextInFlow(), "bad child flow list"); + } else if (nsnull == nextInFlow) { + // The page isn't complete and it doesn't have a next-in-flow so + // create a continuing page + nsIFrame* continuingPage = kidFrame->CreateContinuingFrame(aPresContext, this); + + // Add it to our child list + NS_ASSERTION(nsnull == kidFrame->GetNextSibling(), "unexpected sibling"); + kidFrame->SetNextSibling(continuingPage); + mChildCount++; + } + + // Get the next page + kidFrame = kidFrame->GetNextSibling(); + } + + // Return our desired size + aDesiredSize.width = aMaxSize.width; + aDesiredSize.height = y; + + } else { + // Allow the frame to be as wide as our max width, and as high + // as it wants to be. + nsSize maxSize(aMaxSize.width, NS_UNCONSTRAINEDSIZE); + + // Get the child's desired size. Our child's desired height is our + // desired size + result = ReflowChild(mFirstChild, aPresContext, aDesiredSize, maxSize, + aMaxElementSize); + NS_ASSERTION(frComplete == result, "bad status"); + + // Place and size the child. Make sure the child is at least as + // tall as our max size (the containing window) + if (aDesiredSize.height < aMaxSize.height) { + aDesiredSize.height = aMaxSize.height; + } + + // Place and size the child + nsRect rect(0, 0, aDesiredSize.width, aDesiredSize.height); + mFirstChild->SetRect(rect); + } + } + +#ifdef NS_DEBUG + PostReflowCheck(result); +#endif + return result; +} + +// XXX Do something sensible for page mode... +nsIFrame::ReflowStatus +RootContentFrame::IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand) +{ + // We don't expect the target of the reflow command to be the root + // content frame + NS_ASSERTION(aReflowCommand.GetTarget() != this, "root content frame is reflow command target"); + + nsSize maxSize(aMaxSize.width, NS_UNCONSTRAINEDSIZE); + ReflowStatus status; + nsIFrame* child; + + // Dispatch the reflow command to our pseudo frame. Allow it to be as high + // as it wants + status = aReflowCommand.Next(aDesiredSize, maxSize, child); + + // Place and size the child. Make sure the child is at least as + // tall as our max size (the containing window) + if (nsnull != child) { + NS_ASSERTION(child == mFirstChild, "unexpected reflow command frame"); + if (aDesiredSize.height < aMaxSize.height) { + aDesiredSize.height = aMaxSize.height; + } + + nsRect rect(0, 0, aDesiredSize.width, aDesiredSize.height); + child->SetRect(rect); + } + + return status; +} + +void RootContentFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + // If we're paginated then fill the dirty rect with white + if (aPresContext.IsPaginated()) { + // Cross hatching would be nicer... + aRenderingContext.SetColor(NS_RGB(255,255,255)); + aRenderingContext.FillRect(aDirtyRect); + } + + nsContainerFrame::Paint(aPresContext, aRenderingContext, aDirtyRect); +} + +//---------------------------------------------------------------------- + +class RootPart : public nsHTMLContainer { +public: + RootPart(nsIDocument* aDoc); + + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + +protected: + virtual ~RootPart(); +}; + +RootPart::RootPart(nsIDocument* aDoc) +{ + NS_PRECONDITION(nsnull != aDoc, "null ptr"); + mDocument = aDoc; + mTag = NS_NewAtom("HTML"); +} + +RootPart::~RootPart() +{ +} + +nsrefcnt RootPart::AddRef(void) +{ + return ++mRefCnt; +} + +nsrefcnt RootPart::Release(void) +{ + if (--mRefCnt == 0) { + delete this; + return 0; + } + return mRefCnt; +} + +nsIFrame* RootPart::CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + nsIFrame* rv = new RootFrame(this); + return rv; +} + +nsresult +NS_NewRootPart(nsIHTMLContent** aInstancePtrResult, + nsIDocument* aDocument) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIHTMLContent* root = new RootPart(aDocument); + if (nsnull == root) { + return NS_ERROR_OUT_OF_MEMORY; + } + aDocument->SetRootContent(root); + return root->QueryInterface(kIHTMLContentIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/layout/html/base/src/nsSpacerPart.cpp b/mozilla/layout/html/base/src/nsSpacerPart.cpp new file mode 100644 index 00000000000..00ae544c90e --- /dev/null +++ b/mozilla/layout/html/base/src/nsSpacerPart.cpp @@ -0,0 +1,307 @@ +/* -*- 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 "nsHTMLParts.h" +#include "nsHTMLTagContent.h" +#include "nsBlockFrame.h" +#include "nsHTMLIIDs.h" +#include "nsIPresContext.h" +#include "nsIPresShell.h" +#include "nsHTMLAtoms.h" +#if 0 +#include "nsStyleConsts.h" +#include "nsIHTMLAttributes.h" +#endif + +// Spacer type's +#define TYPE_WORD 0 // horizontal space +#define TYPE_LINE 1 // line-break + vertical space +#define TYPE_IMAGE 2 // acts like a sized image with nothing to see + +class SpacerFrame : public nsFrame +{ +public: + SpacerFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); +protected: + virtual ~SpacerFrame(); +}; + +class SpacerPart : public nsHTMLTagContent { +public: + SpacerPart(nsIAtom* aTag); + + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void SetAttribute(nsIAtom* aAttribute, const nsString& aValue); + + virtual nsContentAttr GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aValue) const; + + virtual nsContentAttr GetAttribute(const nsString& aName, + nsString& aResult) const; + + PRUint8 mType; + +protected: + virtual ~SpacerPart(); +}; + +//---------------------------------------------------------------------- + +SpacerFrame::SpacerFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsFrame(aContent, aIndexInParent, aParentFrame) +{ +} + +SpacerFrame::~SpacerFrame() +{ +} + +nsIFrame::ReflowStatus +SpacerFrame::ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ + // Get cached state for containing block frame + nsBlockReflowState* state = nsnull; + nsIFrame* parent = mGeometricParent; + while (nsnull != parent) { + nsIHTMLFrameType* ft; + nsresult status = parent->QueryInterface(kIHTMLFrameTypeIID, (void**) &ft); + if (NS_OK == status) { + nsHTMLFrameType type = ft->GetFrameType(); + if (eHTMLFrame_Block == type) { + break; + } + } + parent = parent->GetGeometricParent(); + } + if (nsnull != parent) { + nsIPresShell* shell = aPresContext->GetShell(); + state = (nsBlockReflowState*) shell->GetCachedData(parent); + NS_RELEASE(shell); + } + + // By default, we have no area + aDesiredSize.width = 0; + aDesiredSize.height = 0; + aDesiredSize.ascent = 0; + aDesiredSize.descent = 0; + + if (nsnull == state) { + // We don't do anything unless we are in a block container somewhere + return frComplete; + } + + nscoord width = 0; + nscoord height = 0; + SpacerPart* part = (SpacerPart*) mContent; + PRUint8 type = part->mType; + nsContentAttr ca; + if (type != TYPE_IMAGE) { + nsHTMLValue val; + ca = part->GetAttribute(nsHTMLAtoms::size, val); + if (eContentAttr_HasValue == ca) { + width = val.GetIntValue(); + } + } else { + nsHTMLValue val; + ca = part->GetAttribute(nsHTMLAtoms::width, val); + if (eContentAttr_HasValue == ca) { + if (eHTMLUnit_Absolute == val.GetUnit()) { + width = val.GetIntValue(); + } + else if (eHTMLUnit_Percent == val.GetUnit()) { + // XXX percent of what? + } + } + ca = part->GetAttribute(nsHTMLAtoms::height, val); + if (eContentAttr_HasValue == ca) { + if (eHTMLUnit_Absolute == val.GetUnit()) { + height = val.GetIntValue(); + } + else if (eHTMLUnit_Percent == val.GetUnit()) { + // XXX percent of what? + } + } + } + + float p2t = aPresContext->GetPixelsToTwips(); + switch (type) { + case TYPE_WORD: + if (0 != width) { + aDesiredSize.width = nscoord(width * p2t); + } + else { + // XXX navigator ignores spacers of size 0 and won't cause a word + // break; we need a keepWithPrevious flag to fix this bug + } + break; + + case TYPE_LINE: + if (0 != width) { + state->breakBeforeChild = PR_TRUE; + state->breakAfterChild = PR_TRUE; + aDesiredSize.height = nscoord(width * p2t); + aDesiredSize.ascent = aDesiredSize.height; + } + else { + // XXX navigator ignores spacers of size 0 and won't cause a word + // break; we need a keepWithPrevious flag to fix this bug + } + break; + + case TYPE_IMAGE: + aDesiredSize.width = nscoord(width * p2t); + aDesiredSize.height = nscoord(height * p2t); + aDesiredSize.ascent = aDesiredSize.height; + break; + } + + return frComplete; +} + +//---------------------------------------------------------------------- + +SpacerPart::SpacerPart(nsIAtom* aTag) + : nsHTMLTagContent(aTag) +{ +} + +SpacerPart::~SpacerPart() +{ +} + +nsIFrame* SpacerPart::CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + nsIFrame* rv = new SpacerFrame(this, aIndexInParent, aParentFrame); + return rv; +} + +void SpacerPart::SetAttribute(nsIAtom* aAttribute, const nsString& aValue) +{ + if (aAttribute == nsHTMLAtoms::type) { + PRUint8 type = TYPE_WORD; + if (aValue.EqualsIgnoreCase("line") || + aValue.EqualsIgnoreCase("vert") || + aValue.EqualsIgnoreCase("vertical")) { + type = TYPE_LINE; + } + else if (aValue.EqualsIgnoreCase("block")) { + type = TYPE_IMAGE; + } + mType = type; + } + else if (aAttribute == nsHTMLAtoms::size) { + nsHTMLValue val; + ParseValue(aValue, 0, val); + nsHTMLTagContent::SetAttribute(aAttribute, val); + } + else if (aAttribute == nsHTMLAtoms::align) { + nsHTMLValue val; + ParseAlignParam(aValue, val); + nsHTMLTagContent::SetAttribute(aAttribute, val); + } + else if ((aAttribute == nsHTMLAtoms::width) || + (aAttribute == nsHTMLAtoms::height)) { + nsHTMLValue val; + ParseValueOrPercent(aValue, val); + nsHTMLTagContent::SetAttribute(aAttribute, val); + } +} + +nsContentAttr SpacerPart::GetAttribute(const nsString& aName, + nsString& aResult) const +{ + aResult.SetLength(0); + nsIAtom* atom = NS_NewAtom(aName); + nsContentAttr ca = eContentAttr_NotThere; + nsHTMLValue value; + if (atom == nsHTMLAtoms::type) { + switch (mType) { + case TYPE_WORD: + break; + case TYPE_LINE: + aResult.Append("line"); + ca = eContentAttr_HasValue; + break; + case TYPE_IMAGE: + aResult.Append("block"); + ca = eContentAttr_HasValue; + break; + } + } + else if ((atom == nsHTMLAtoms::size) || + (atom == nsHTMLAtoms::width) || + (atom == nsHTMLAtoms::height)) { + if (eContentAttr_HasValue == nsHTMLTagContent::GetAttribute(atom, value)) { + ValueOrPercentToString(value, aResult); + ca = eContentAttr_HasValue; + } + } + else if (atom == nsHTMLAtoms::align) { + if (eContentAttr_HasValue == nsHTMLTagContent::GetAttribute(atom, value)) { + AlignParamToString(value, aResult); + ca = eContentAttr_HasValue; + } + } + NS_RELEASE(atom); + return ca; +} + +nsContentAttr SpacerPart::GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aValue) const +{ + aValue.Reset(); + if ((mType != TYPE_IMAGE) && + ((aAttribute == nsHTMLAtoms::width) || + (aAttribute == nsHTMLAtoms::height) || + (aAttribute == nsHTMLAtoms::align))) { + // Pretend that these attributes are not present when the spacer + // is not a block spacer. + return eContentAttr_NotThere; + } + return nsHTMLTagContent::GetAttribute(aAttribute, aValue); +} + +nsresult +NS_NewHTMLSpacer(nsIHTMLContent** aInstancePtrResult, nsIAtom* aTag) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIHTMLContent* it = new SpacerPart(aTag); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIHTMLContentIID, (void**) aInstancePtrResult); +} diff --git a/mozilla/layout/html/base/src/nsTextContent.cpp b/mozilla/layout/html/base/src/nsTextContent.cpp new file mode 100644 index 00000000000..182303c9be1 --- /dev/null +++ b/mozilla/layout/html/base/src/nsTextContent.cpp @@ -0,0 +1,1538 @@ +/* -*- 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 "nsHTMLParts.h" +#include "nsCRT.h" +#include "nsSplittableFrame.h" +#include "nsHTMLContent.h" +#include "nsString.h" +#include "nsIPresContext.h" +#include "nsStyleConsts.h" +#include "nsIStyleContext.h" +#include "nsCoord.h" +#include "nsIFontMetrics.h" +#include "nsIRenderingContext.h" +#include "nsHTMLIIDs.h" +#include "nsIPresShell.h" +#include "nsIView.h" +#include "nsIViewManager.h" +#include "nsITimerCallback.h" +#include "nsITimer.h" +#include "nsBlockFrame.h" +#include "prtime.h" +#include "prprf.h" +#include "nsIDOMText.h" + +#ifdef NS_DEBUG +#undef NOISY +#define NOISY_BLINK +#else +#undef NOISY +#undef NOISY_BLINK +#endif + +// XXX TODO: +// 0. tune justified text +// 1. add in a rendering method that can render justified text +// 2. text renderer should negotiate with rendering context/font +// metrics to see what it can handle; for example, if the renderer can +// automatically deal with underlining, strikethrough, justification, +// etc, then the text renderer should let the rc do the work; +// otherwise there should be XP fallback code here. + +// XXX Speedup ideas +// 1. justified text can use word width information during resize reflows +// 2. when we are doing an unconstrained reflow we know we are going to +// get reflowed again; collect up the word widths we are computing as we +// do this and then save them in the mWords; later on when we get reflowed +// again we can destroy them +// 3. when pulling up text get word width information from next-in-flow + +// XXX temporary +#define XP_IS_SPACE(_ch) \ + (((_ch) == ' ') || ((_ch) == '\t') || ((_ch) == '\n')) + +// XXX need more of this in nsIFontMetrics.GetWidth +#define CH_NBSP 160 + +// XXX use a PreTextFrame for pre-formatted text? + +#if 0 +static NS_DEFINE_IID(kITextContentIID, NS_ITEXTCONTENT_IID); +#endif +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); +static NS_DEFINE_IID(kStyleFontSID, NS_STYLEFONT_SID); +static NS_DEFINE_IID(kStyleColorSID, NS_STYLECOLOR_SID); +static NS_DEFINE_IID(kIScriptObjectOwner, NS_ISCRIPTOBJECTOWNER_IID); + +class TextFrame; + +class TextTimer : public nsITimerCallback { +public: + TextTimer(); + ~TextTimer(); + + NS_DECL_ISUPPORTS + + void AddFrame(TextFrame* aFrame); + + PRBool RemoveFrame(TextFrame* aFrame); + + PRInt32 FrameCount(); + + void Start(); + + void Stop(); + + virtual void Notify(nsITimer *timer); + + nsITimer* mTimer; + nsVoidArray mFrames; +}; + +class TextFrame : public nsSplittableFrame { +public: + TextFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + virtual ReflowStatus ResizeReflow(nsIPresContext* aCX, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + + virtual void GetReflowMetrics(nsIPresContext* aPresContext, + nsReflowMetrics& aMetrics); + + virtual void JustifyReflow(nsIPresContext* aCX, + nscoord aAvailableSpace); + + virtual PRInt32 GetCursorAt(nsIPresContext& aPresContext, + const nsPoint& aPoint, + nsIFrame** aFrame); + + virtual void List(FILE* out, PRInt32 aIndent) const; + +protected: + virtual ~TextFrame(); + + void PaintRegularText(nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nscoord dx, nscoord dy); + + void PaintJustifiedText(nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nscoord dx, nscoord dy); + + ReflowStatus ReflowPre(nsIPresContext* aCX, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize, + nsStyleFont& aFont, + PRInt32 aStartingOffset, + nsBlockReflowState* aState); + + ReflowStatus ReflowNormal(nsIPresContext* aCX, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize, + nsStyleFont& aFont, + nsStyleMolecule& aMol, + PRInt32 aStartingOffset, + nsBlockReflowState* aState); + +public: + PRInt32 mContentOffset; + PRInt32 mContentLength; + PRUint16 mFlags; + PRUint16 mColumn; + + // When this text frame is justified, this pointer is not null + // and points to data about each word/space in the text + PRUint32* mWords; +#ifdef DEBUG_JUSTIFY + PRInt32 mNumWords; +#endif +}; + +// Flag information used by rendering code. This information is +// computed by the ResizeReflow code. Remaining bits are used by the +// tab count. +#define TEXT_SKIP_LEADING_WS 0x1 +#define TEXT_HAS_MULTIBYTE 0x2 +#define TEXT_IS_PRE 0x4 +#define TEXT_BLINK_ON 0x8 + +#define TEXT_GET_TAB_COUNT(_mf) ((_mf) >> 4) +#define TEXT_SET_TAB_COUNT(_mf,_tabs) (_mf) = (_mf) | ((_tabs)<< 4) + +// mWords bit definitions +#define WORD_IS_WORD 0x80000000L +#define WORD_IS_SPACE 0x00000000L +#define WORD_LENGTH_MASK 0x000000FFL +#define WORD_LENGTH_SHIFT 0 +#define WORD_WIDTH_MASK 0x7FFFFF00L +#define WORD_WIDTH_SHIFT 8 +#define MAX_WORD_LENGTH 256 +#define MAX_WORD_WIDTH 0x7FFFFFL + +#define GET_WORD_LENGTH(_wi) \ + ((PRIntn) (((_wi) & WORD_LENGTH_MASK)/* >> WORD_LENGTH_SHIFT*/)) +#define GET_WORD_WIDTH(_wi) \ + ((nscoord) ((PRUint32(_wi) & WORD_WIDTH_MASK) >> WORD_WIDTH_SHIFT)) + +class Text : public nsHTMLContent, public nsIDOMText { +public: + Text(const PRUnichar* aText, PRInt32 aLength); + + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(void); + NS_IMETHOD_(nsrefcnt) Release(void); + +#if 0 + virtual PRInt32 GetLength(); + virtual void GetText(nsStringBuf* aBuf, PRInt32 aOffset, PRInt32 aCount); +#endif + + virtual void List(FILE* out, PRInt32 aIndent) const; + + virtual void ToHTMLString(nsString& aBuf) const; + + virtual nsIFrame* CreateFrame(nsIPresContext* aCX, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + // nsIScriptObjectOwner interface + virtual nsresult GetScriptObject(JSContext *aContext, void** aScriptObject); + + // nsIDOMText interface + virtual nsresult GetNodeType(PRInt32 *aType); + virtual nsresult GetParentNode(nsIDOMNode **aNode); + virtual nsresult GetChildNodes(nsIDOMNodeIterator **aIterator); + virtual nsresult HasChildNodes(); + virtual nsresult GetFirstChild(nsIDOMNode **aNode); + virtual nsresult GetPreviousSibling(nsIDOMNode **aNode); + virtual nsresult GetNextSibling(nsIDOMNode **aNode); + virtual nsresult InsertBefore(nsIDOMNode *newChild, nsIDOMNode *refChild); + virtual nsresult ReplaceChild(nsIDOMNode *newChild, + nsIDOMNode *oldChild); + virtual nsresult RemoveChild(nsIDOMNode *oldChild); + virtual nsresult GetData(nsString &aString); + virtual nsresult SetData(nsString &aString); + virtual nsresult Append(nsString &aData); + virtual nsresult Insert(int offset, nsString &aData); + virtual nsresult Delete(int offset, int count); + virtual nsresult Replace(int offset, int count, nsString &aData); + virtual nsresult Splice(nsIDOMElement *element, int offset, int count); + + void ToCString(nsString& aBuf, PRInt32 aOffset, PRInt32 aLen) const; + + PRUnichar* mText; + PRInt32 mLength; + +protected: + Text(); + virtual ~Text(); +}; + +//---------------------------------------------------------------------- + +static PRBool gBlinkTextOff; +static TextTimer* gTextBlinker; +#ifdef NOISY_BLINK +static PRTime gLastTick; +#endif + +TextTimer::TextTimer() +{ + NS_INIT_REFCNT(); + mTimer = nsnull; +} + +TextTimer::~TextTimer() +{ + Stop(); +} + +void TextTimer::Start() +{ + nsresult rv = NS_NewTimer(&mTimer); + if (NS_OK == rv) { + mTimer->Init(this, 750); + } +} + +void TextTimer::Stop() +{ + NS_IF_RELEASE(mTimer); +} + +static NS_DEFINE_IID(kITimerCallbackIID, NS_ITIMERCALLBACK_IID); +NS_IMPL_ISUPPORTS(TextTimer, kITimerCallbackIID); + +void TextTimer::AddFrame(TextFrame* aFrame) { + mFrames.AppendElement(aFrame); + if (1 == mFrames.Count()) { + Start(); + } +printf("%d blinking frames [add %p]\n", mFrames.Count(), aFrame); +} + +PRBool TextTimer::RemoveFrame(TextFrame* aFrame) { + PRBool rv = mFrames.RemoveElement(aFrame); + if (0 == mFrames.Count()) { + Stop(); + } +printf("%d blinking frames [remove %p] [%s]\n", + mFrames.Count(), aFrame, rv ? "true" : "FALSE"); + return rv; +} + +PRInt32 TextTimer::FrameCount() { + return mFrames.Count(); +} + +void TextTimer::Notify(nsITimer *timer) +{ + // Toggle blink state bit so that text code knows whether or not to + // render. All text code shares the same flag so that they all blink + // in unison. + gBlinkTextOff = PRBool(!gBlinkTextOff); + + // XXX hack to get auto-repeating timers; restart before doing + // expensive work so that time between ticks is more even + Stop(); + Start(); + +#ifdef NOISY_BLINK + PRTime now = PR_Now(); + char buf[50]; + PRTime delta; + LL_SUB(delta, now, gLastTick); + gLastTick = now; + PR_snprintf(buf, sizeof(buf), "%lldusec", delta); + printf("%s\n", buf); +#endif + + PRInt32 i, n = mFrames.Count(); + for (i = 0; i < n; i++) { + TextFrame* text = (TextFrame*) mFrames.ElementAt(i); + + // Determine damaged area and tell view manager to redraw it + nsPoint offset; + nsRect bounds; + text->GetRect(bounds); + nsIView* view = text->GetOffsetFromView(offset); + nsIViewManager* vm = view->GetViewManager(); + bounds.x = offset.x; + bounds.y = offset.y; + vm->UpdateView(view, &bounds, 0); + NS_RELEASE(vm); + NS_RELEASE(view); + } +} + +//---------------------------------------------------------------------- + +TextFrame::TextFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsSplittableFrame(aContent, aIndexInParent, aParentFrame) +{ + if (nsnull == gTextBlinker) { + // Create text timer the first time out + gTextBlinker = new TextTimer(); + } + NS_ADDREF(gTextBlinker); +} + +TextFrame::~TextFrame() +{ + if (0 != (mFlags & TEXT_BLINK_ON)) { + NS_ASSERTION(nsnull != gTextBlinker, "corrupted blinker"); + gTextBlinker->RemoveFrame(this); + } + if (0 == gTextBlinker->Release()) { + // Release text timer when the last text frame is gone + gTextBlinker = nsnull; + } + if (nsnull != mWords) { + delete mWords; + } +} + +PRInt32 TextFrame::GetCursorAt(nsIPresContext& aPresContext, + const nsPoint& aPoint, + nsIFrame** aFrame) +{ + nsStyleMolecule* mol = (nsStyleMolecule*) + mStyleContext->GetData(kStyleMoleculeSID); + if (mol->cursor != NS_STYLE_CURSOR_INHERIT) { + // If this container has a particular cursor, use it, otherwise + // let the child decide. + *aFrame = this; + } + return (PRInt32) mol->cursor; +} + +// XXX it would be nice to use a method pointer here, but I don't want +// to pay for the storage. + +void TextFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + if ((0 != (mFlags & TEXT_BLINK_ON)) && gBlinkTextOff) { + return; + } + + // Get style data + nsStyleColor* color = + (nsStyleColor*)mStyleContext->GetData(kStyleColorSID); + nsStyleFont* font = + (nsStyleFont*)mStyleContext->GetData(kStyleFontSID); + + // Set font and color + aRenderingContext.SetColor(color->mColor); + aRenderingContext.SetFont(font->mFont); + + if (nsnull != mWords) { + PaintJustifiedText(aRenderingContext, aDirtyRect, 0, 0); + if (font->mThreeD) { + nscoord onePixel = nscoord(1.0f * aPresContext.GetPixelsToTwips()); + aRenderingContext.SetColor(color->mBackgroundColor); + PaintJustifiedText(aRenderingContext, aDirtyRect, onePixel, onePixel); + } + return; + } + PaintRegularText(aRenderingContext, aDirtyRect, 0, 0); + if (font->mThreeD) { + nscoord onePixel = nscoord(1.0f * aPresContext.GetPixelsToTwips()); + aRenderingContext.SetColor(color->mBackgroundColor); + PaintRegularText(aRenderingContext, aDirtyRect, onePixel, onePixel); + } +} + +void TextFrame::PaintRegularText(nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nscoord dx, nscoord dy) +{ + // Skip leading space if necessary + Text* txt = (Text*) mContent; + const PRUnichar* cp = txt->mText + mContentOffset; + const PRUnichar* end = cp + mContentLength; + if ((mFlags & TEXT_SKIP_LEADING_WS) != 0) { + while (cp < end) { + PRUnichar ch = *cp++; + if (!XP_IS_SPACE(ch)) { + cp--; + break; + } + } + } + + if ((mFlags & TEXT_IS_PRE) != 0) { + if ((mFlags & TEXT_HAS_MULTIBYTE) != 0) { + // XXX to be written + } else { + PRIntn tabs = TEXT_GET_TAB_COUNT(mFlags); + + // Make a copy of the text we are to render, translating tabs + // into whitespace. + char buf[100]; + char* s = buf; + char* s0 = s; + PRInt32 maxLen = (end - cp) + 8*tabs; + if (maxLen > sizeof(buf)) { + s0 = s = new char[maxLen]; + } + + // Translate tabs into whitespace; translate other whitespace into + // spaces. + PRIntn col = (PRIntn) mColumn; + while (cp < end) { + PRUint8 ch = (PRUint8) *cp++; + if (XP_IS_SPACE(ch)) { + if (ch == '\t') { + PRIntn spaces = 8 - (col & 7); + col += spaces; + while (--spaces >= 0) { + *s++ = ' '; + } + continue; + } else { + *s++ = ' '; + } + } else if (ch == CH_NBSP) { + *s++ = ' '; + } else { + *s++ = ch; + } + col++; + } + + // Strip trailing whitespace + if (s != s0) { + if (s[-1] == ' ') { + s--; + } + } + + // Render the text + aRenderingContext.DrawString(s0, s - s0, dx, dy, mRect.width); + + if (s0 != buf) { + delete s0; + } + } + } else { + if ((mFlags & TEXT_HAS_MULTIBYTE) != 0) { + // XXX to be written + } else { + // Make a copy of the text we are to render, compressing out + // whitespace; translating whitespace to literal spaces; + // eliminating trailing whitespace. + char buf[100]; + char* s = buf; + char* s0 = s; + PRInt32 maxLen = end - cp; + if (maxLen > sizeof(buf)) { + s0 = s = new char[maxLen]; + } + + // Compress down the whitespace + while (cp < end) { + PRUint8 ch = (PRUint8) *cp++; + if (XP_IS_SPACE(ch)) { + while (cp < end) { + ch = (PRUint8) *cp++; + if (!XP_IS_SPACE(ch)) { + cp--; + break; + } + } + *s++ = ' '; + } else { + *s++ = ch; + } + } + + // Strip trailing whitespace + if (s != s0) { + if (s[-1] == ' ') { + s--; + } + } + + // Render the text + aRenderingContext.DrawString(s0, s - s0, dx, dy, mRect.width); + + if (s0 != buf) { + delete s0; + } + } + } +} + +void TextFrame::PaintJustifiedText(nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nscoord dx, nscoord dy) +{ + Text* txt = (Text*) mContent; + const PRUnichar* cp = txt->mText + mContentOffset; + const PRUnichar* end = cp + mContentLength; + + // Get a word buffer that's big enough to hold all of the text in + // case all of the text happens to be a word (not possible given how + // the justification workds, but it's the fastest check that gets us + // a big enough buffer). We only do this if we aren't going to use + // multibyte rendering. + char buf[100]; + char* s0 = buf; + if ((mFlags & TEXT_HAS_MULTIBYTE) == 0) { + PRInt32 maxLen = end - cp; + if (maxLen > sizeof(buf)) { + s0 = new char[maxLen]; + } + } + + // XXX justified text doesn't render underlines (etc) over spaces + // while regular text does...fix this? + PRUint32* wp = mWords; + PRInt32 total = mContentLength; + nscoord x = dx; +#ifdef DEBUG_JUSTIFY + PRIntn numWords = mNumWords; +#endif + while (total != 0) { +#ifdef DEBUG_JUSTIFY + NS_ASSERTION(numWords > 0, "bad word data"); +#endif + PRUint32 wordInfo = *wp++; + nscoord wordWidth = GET_WORD_WIDTH(wordInfo); + PRIntn wordLen = GET_WORD_LENGTH(wordInfo); + if (wordInfo & WORD_IS_WORD) { + if (mFlags & TEXT_HAS_MULTIBYTE) { + aRenderingContext.DrawString(cp, wordLen, x, dy, mRect.width); + cp += wordLen; + } else { + char* s = s0; + char* es = s + wordLen; + while (s < es) { + PRUint8 ch = (PRUint8) *cp++; + *s++ = ch; + } + aRenderingContext.DrawString(s0, s - s0, x, dy, mRect.width); + } + } else { + // skip over space characters in text array + cp += wordLen; + } + x += wordWidth; + total -= wordLen; +#ifdef DEBUG_JUSTIFY + --numWords; + NS_ASSERTION(total >= 0, "bad word data"); +#endif + } + + if (s0 != buf) { + delete s0; + } +} + +void TextFrame::GetReflowMetrics(nsIPresContext* aCX, + nsReflowMetrics& aMetrics) +{ + aMetrics.width = mRect.width; + aMetrics.height = mRect.height; + + nsStyleFont* font = + (nsStyleFont*)mStyleContext->GetData(kStyleFontSID); + nsIFontMetrics* fm = aCX->GetMetricsFor(font->mFont); + aMetrics.ascent = fm->GetMaxAscent(); + aMetrics.descent = fm->GetMaxDescent(); + NS_RELEASE(fm); +} + +nsIFrame::ReflowStatus +TextFrame::ResizeReflow(nsIPresContext* aCX, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ +#ifdef NOISY + ListTag(stdout); + printf(": resize reflow into %g,%g\n", + NS_TWIPS_TO_POINTS_FLOAT(aMaxSize.width), + NS_TWIPS_TO_POINTS_FLOAT(aMaxSize.height)); +#endif + + // Wipe out old justification information since it's going to change + if (nsnull != mWords) { + delete mWords; + mWords = nsnull; + } +#ifdef DEBUG_JUSTIFY + mNumWords = 0; +#endif + + // Get starting offset into the content + PRInt32 startingOffset = 0; + if (nsnull != mPrevInFlow) { + TextFrame* prev = (TextFrame*) mPrevInFlow; + startingOffset = prev->mContentOffset + prev->mContentLength; + } + + // Get cached state for containing block frame + nsBlockReflowState* state = nsnull; + nsIFrame* parent = mGeometricParent; + while (nsnull != parent) { + nsIHTMLFrameType* ft; + nsresult status = parent->QueryInterface(kIHTMLFrameTypeIID, (void**) &ft); + if (NS_OK == status) { + nsHTMLFrameType type = ft->GetFrameType(); + if (eHTMLFrame_Block == type) { + break; + } + } + parent = parent->GetGeometricParent(); + } + if (nsnull != parent) { + nsIPresShell* shell = aCX->GetShell(); + state = (nsBlockReflowState*) shell->GetCachedData(parent); + NS_RELEASE(shell); + } + + nsStyleFont* font = + (nsStyleFont*)mStyleContext->GetData(kStyleFontSID); + + // Initialize mFlags (without destroying the TEXT_BLINK_ON bit) bits + // that are filled in by the reflow routines. + mFlags &= TEXT_BLINK_ON; + if (font->mFont.decorations & NS_STYLE_TEXT_DECORATION_BLINK) { + if (0 == (mFlags & TEXT_BLINK_ON)) { + mFlags |= TEXT_BLINK_ON; + gTextBlinker->AddFrame(this); + } + } + + nsStyleMolecule* mol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + + ReflowStatus status; + if (NS_STYLE_WHITESPACE_PRE == mol->whiteSpace) { + // Use a specialized routine for pre-formatted text + status = ReflowPre(aCX, aDesiredSize, aMaxSize, + aMaxElementSize, *font, startingOffset, state); + } else { + // Use normal wrapping routine for non-pre text (this includes + // text that is not wrapping) + status = ReflowNormal(aCX, aDesiredSize, aMaxSize, + aMaxElementSize, *font, *mol, startingOffset, state); + } + +#ifdef NOISY + ListTag(stdout); + printf(": reflow %scomplete [flags=%x]\n", + ((status == frComplete) ? "" : "not "), mFlags); +#endif + return status; +} + +// Reflow normal text (stuff that doesn't have to deal with horizontal +// tabs). Normal text reflow may or may not wrap depending on the +// "whiteSpace" style property. +nsIFrame::ReflowStatus +TextFrame::ReflowNormal(nsIPresContext* aCX, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize, + nsStyleFont& aFont, + nsStyleMolecule& aMol, + PRInt32 aStartingOffset, + nsBlockReflowState* aState) +{ + Text* txt = (Text*) mContent; + const PRUnichar* cp = txt->mText + aStartingOffset; + const PRUnichar* end = cp + txt->mLength - aStartingOffset; + const PRUnichar* cpStart = cp; + mContentOffset = aStartingOffset; + + nsIFontMetrics* fm = aCX->GetMetricsFor(aFont.mFont); + PRInt32 spaceWidth = fm->GetWidth(' '); + PRBool atLeftMargin = PR_TRUE; + PRBool wrapping = PR_TRUE; + if (NS_STYLE_WHITESPACE_NORMAL != aMol.whiteSpace) { + wrapping = PR_FALSE; + } + + // Set whitespace skip flag + PRBool skipWhitespace = PR_FALSE; + if (nsnull != aState) { + if (!aState->allowLeadingWhitespace) { + skipWhitespace = PR_TRUE; + mFlags |= TEXT_SKIP_LEADING_WS; + } + } + + // Try to fit as much of the text as possible. Note that if we are + // at the left margin then the first word always fits. In addition, + // we compute the size of the largest word that we contain. If we + // end up containing nothing (because there isn't enough space for + // the first word) then we still compute the size of that first + // non-fitting word. + + // XXX XP_IS_SPACE must not return true for the unicode   character + // XXX what about &zwj and it's cousins? + nscoord x = 0; + nscoord maxWidth = aMaxSize.width; + nscoord width = 0; + nscoord maxWordWidth = 0; + const PRUnichar* lastWordEnd = cpStart; + PRBool hasMultibyte = PR_FALSE; + PRBool endsInWhitespace = PR_FALSE; + while (cp < end) { + PRUnichar ch = *cp++; + PRBool isWhitespace; + if (XP_IS_SPACE(ch)) { + // Compress whitespace down to a single whitespace + while (cp < end) { + ch = *cp; + if (XP_IS_SPACE(ch)) { + cp++; + continue; + } + break; + } + if (skipWhitespace) { + skipWhitespace = PR_FALSE; + continue; + } + width = spaceWidth; + isWhitespace = PR_TRUE; + } else { + // The character is not a space character. Find the end of the + // word and then measure it. + if (ch >= 256) { + hasMultibyte = PR_TRUE; + } + const PRUnichar* wordStart = cp - 1; + while (cp < end) { + ch = *cp; + if (ch >= 256) { + hasMultibyte = PR_TRUE; + } + if (!XP_IS_SPACE(ch)) { + cp++; + continue; + } + break; + } + width = fm->GetWidth(wordStart, PRUint32(cp - wordStart)); + skipWhitespace = PR_FALSE; + isWhitespace = PR_FALSE; + } + + // Now that we have the end of the word or whitespace, see if it + // will fit. + if (!atLeftMargin && wrapping && (x + width > maxWidth)) { + // The word/whitespace will not fit. + cp = lastWordEnd; + if (x == 0) { + // Nothing fit at all. In this case, we still may want to know + // the maxWordWidth so compute it right now. + maxWordWidth = width; + } + break; + } + + // The word fits. Add it to the run of text. + x += width; + if (width > maxWordWidth) { + maxWordWidth = width; + } + atLeftMargin = PR_FALSE; + lastWordEnd = cp; + width = 0; + endsInWhitespace = isWhitespace; + } + if (hasMultibyte) { + mFlags |= TEXT_HAS_MULTIBYTE; + } + + if (nsnull != aState) { + if (0 == width) { + // Since we collapsed into nothingness (all our whitespace + // is ignored) leave the aState->allowLeadingWhitespace + // flag alone since it doesn't want leading whitespace + } else { + aState->allowLeadingWhitespace = !endsInWhitespace; + } + } + + // Now we know our content length + mContentLength = lastWordEnd - cpStart; + if (0 == mContentLength) { + if (cp == end) { + // The entire chunk of text was whitespace that we skipped over. + aDesiredSize.width = 0; + aDesiredSize.height = 0; + aDesiredSize.ascent = 0; + aDesiredSize.descent = 0; + mContentLength = end - cpStart; + if (nsnull != aMaxElementSize) { + aMaxElementSize->width = 0; + aMaxElementSize->height = 0; + } + NS_RELEASE(fm); + return frComplete; + } + } + + // Set desired size to the computed size + aDesiredSize.width = x; + aDesiredSize.height = fm->GetHeight(); + aDesiredSize.ascent = fm->GetMaxAscent(); + aDesiredSize.descent = fm->GetMaxDescent(); + if (nsnull != aMaxElementSize) { + aMaxElementSize->width = maxWordWidth; + aMaxElementSize->height = fm->GetHeight(); + } + NS_RELEASE(fm); + return (cp == end) ? frComplete : frNotComplete; +} + +nsIFrame::ReflowStatus +TextFrame::ReflowPre(nsIPresContext* aCX, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize, + nsStyleFont& aFont, + PRInt32 aStartingOffset, + nsBlockReflowState* aState) +{ + Text* txt = (Text*) mContent; + const PRUnichar* cp = txt->mText + aStartingOffset; + const PRUnichar* cpStart = cp; + const PRUnichar* end = cp + txt->mLength - aStartingOffset; + + mFlags |= TEXT_IS_PRE; + nsIFontMetrics* fm = aCX->GetMetricsFor(aFont.mFont); + const PRInt32* widths = fm->GetWidths(); + PRInt32 width = 0; + PRBool hasMultibyte = PR_FALSE; + PRUint16 tabs = 0; + PRIntn col = 0; + if (nsnull != aState) { + col = aState->column; + } + mColumn = (PRUint16) col; + nscoord spaceWidth = widths[' ']; + while (cp < end) { + PRUnichar ch = *cp++; + if (ch == '\n') { + if (nsnull != aState) { + aState->breakAfterChild = PR_TRUE; + } + break; + } + if (ch == '\t') { + // Advance to next tab stop + PRIntn spaces = 8 - (col & 7); + width += spaces * spaceWidth; + col += spaces; + tabs++; + continue; + } + if (ch == CH_NBSP) { + width += spaceWidth; + col++; + continue; + } + if (ch < 256) { + width += widths[ch]; + } else { + widths += fm->GetWidth(ch); + hasMultibyte = PR_TRUE; + } + col++; + } + if (nsnull != aState) { + aState->column = col; + } + if (hasMultibyte) { + mFlags |= TEXT_HAS_MULTIBYTE; + } + TEXT_SET_TAB_COUNT(mFlags, tabs); + + mContentOffset = aStartingOffset; + mContentLength = cp - cpStart; + aDesiredSize.width = width; + aDesiredSize.height = fm->GetHeight(); + aDesiredSize.ascent = fm->GetMaxAscent(); + aDesiredSize.descent = fm->GetMaxDescent(); + if (nsnull != aMaxElementSize) { + aMaxElementSize->width = aDesiredSize.width; + aMaxElementSize->height = aDesiredSize.height; + } + NS_RELEASE(fm); + return (cp == end) ? frComplete : frNotComplete; +} + +#define NUM_WORDS 20 + +void TextFrame::JustifyReflow(nsIPresContext* aCX, nscoord aAvailableSpace) +{ + if (mFlags & TEXT_IS_PRE) { + // no way + return; + } + + nsStyleFont* font = + (nsStyleFont*)mStyleContext->GetData(kStyleFontSID); + nsIFontMetrics* fm = aCX->GetMetricsFor(font->mFont); + PRInt32 spaceWidth = fm->GetWidth(' '); + + PRUint32 words[NUM_WORDS]; + PRUint32* wp0 = words; + PRIntn maxWords = NUM_WORDS; + + PRBool skipWhitespace = PRBool((mFlags & TEXT_SKIP_LEADING_WS) != 0); + + // Count the number of spaces and words in the text we are going to + // justify. Also measure each word in the text and skip over leading + // space and compress down whitespace. + Text* txt = (Text*) mContent; + const PRUnichar* cp = txt->mText + mContentOffset; + const PRUnichar* cpStart = cp; + const PRUnichar* end = cp + mContentLength; + PRUint32* wp = wp0; + PRUint32* wpend = wp0 + maxWords; + PRIntn spaceCount = 0; + PRIntn total = 0; + while (cp < end) { + if (wp == wpend) { + // Make space for more words + PRUint32 numWords = wp - wp0; + maxWords = maxWords * 2; + PRUint32* newwp0 = new PRUint32[maxWords]; + if (nsnull == newwp0) { + goto bail; + } + nsCRT::memcpy(newwp0, wp0, sizeof(PRUint32) * numWords); + if (wp0 != words) { + delete wp0; + } + wp0 = newwp0; + wp = wp0 + numWords; + wpend = wp0 + maxWords; + } + + PRUint32 wordInfo; + PRUint32 wordLen; + nscoord wordWidth; + const PRUnichar* wordStart = cp; + PRUnichar ch = *cp++; + if (XP_IS_SPACE(ch)) { + // Compress whitespace down to a single whitespace + while (cp < end) { + ch = *cp; + if (XP_IS_SPACE(ch)) { + cp++; + continue; + } + break; + } + // Use wordWidth as a flag for spaces to indicate which spaces + // we give zero space to and which we don't. + if (skipWhitespace) { + wordWidth = 0; + } else { + wordWidth = spaceWidth; + spaceCount++; + } + wordInfo = WORD_IS_SPACE; + wordLen = cp - wordStart; + } else { + while (cp < end) { + ch = *cp; + if (!XP_IS_SPACE(ch)) { + cp++; + continue; + } + break; + } + wordLen = cp - wordStart; + wordWidth = fm->GetWidth(wordStart, wordLen); + skipWhitespace = PR_FALSE; + wordInfo = WORD_IS_WORD; + } + if ((wordWidth > MAX_WORD_WIDTH) || (wordLen > MAX_WORD_LENGTH)) { + // We can't fit the information about this word into our + // bitfield. Bail. + goto bail; + } + wordInfo = wordInfo | + (wordLen << WORD_LENGTH_SHIFT) | + (wordWidth << WORD_WIDTH_SHIFT); + *wp++ = wordInfo; + total += wordLen; + } + NS_ASSERTION(total == mContentLength, "bad total"); + + // Now that we know where all the words and spaces are, and we have + // measured the words, divy up the aAvailableSpace to each of the + // spaces. + if (spaceCount != 0) { + /* + * See if the last word is a space. If it is, don't count it as a space + * and give it's space to the available space. + */ + PRUint32 wordInfo = wp[-1]; + if ((wordInfo & WORD_IS_WORD) == 0) { + if (--spaceCount == 0) { + // Never mind: the one and only space was at the end. Harumph. + goto bail; + } + aAvailableSpace += spaceWidth; + // Update wordInfo to have a zero width for the trailing space + wp[-1] = WORD_IS_SPACE | (wordInfo & WORD_LENGTH_MASK); + } + nscoord add = aAvailableSpace / spaceCount; + if (add == 0) { + add = 1; + } + PRIntn numWords = wp - wp0; + mWords = new PRUint32[numWords]; + if (nsnull == mWords) { + goto bail; + } + wp = wp0; + PRUint32* tp = mWords; + PRUint32* tpend = tp + numWords; + total = 0; +#ifdef DEBUG_JUSTIFY + mNumWords = numWords; +#endif + while (--numWords >= 0) { + wordInfo = *wp++; + if (wordInfo & WORD_IS_WORD) { + // We already know about the word + *tp++ = wordInfo; + total += GET_WORD_LENGTH(wordInfo); + continue; + } else { + nscoord spaceWidth = GET_WORD_WIDTH(wordInfo); + if (spaceWidth == 0) { + // This is leading space that doesn't count + *tp++ = wordInfo; + total += GET_WORD_LENGTH(wordInfo); + continue; + } + // This is a space that gets some of the available space + if (add > aAvailableSpace) { + add = aAvailableSpace; + } + spaceWidth += add; + aAvailableSpace -= add; + if (aAvailableSpace == 0) { + // We used it all up already so stop adding + add = 0; + } + if (--spaceCount == 0) { + // Give the last space the remaining available space + spaceWidth += aAvailableSpace; + aAvailableSpace = 0; + } + if (spaceWidth > MAX_WORD_WIDTH) { + // Sad but true; leave it be. Maybe the next word can use it + *tp++ = wordInfo; + total += GET_WORD_LENGTH(wordInfo); + continue; + } + wordInfo = (wordInfo & ~WORD_WIDTH_MASK) | + (spaceWidth << WORD_WIDTH_SHIFT); + *tp++ = wordInfo; + total += GET_WORD_LENGTH(wordInfo); + } + } + NS_ASSERTION(aAvailableSpace == 0, "bad divy up"); + NS_ASSERTION(tp == tpend, "bad tp"); + NS_ASSERTION(total == mContentLength, "bad total"); + } + +bail: + if (wp0 != words) { + delete wp0; + } + NS_RELEASE(fm); +} +#undef NUM_WORDS + +void TextFrame::List(FILE* out, PRInt32 aIndent) const +{ + PRInt32 i; + for (i = aIndent; --i >= 0; ) fputs(" ", out); + fprintf(out, "Text(%d)@%p[%d,%d] ", + mIndexInParent, this, + mContentOffset, mContentOffset+mContentLength-1); + out << mRect; + aIndent++; + + for (i = aIndent; --i >= 0; ) fputs(" ", out); + Text* txt = (Text*) mContent; + nsAutoString tmp; + txt->ToCString(tmp, mContentOffset, mContentLength); + fputs("\"", out); + fputs(tmp, out); + fputs("\"\n", out); + + aIndent--; + for (i = aIndent; --i >= 0; ) fputs(" ", out); + fputs(">\n", out); + +#ifdef NOISY + if (nsnull != mWords) { + for (i = aIndent; --i >= 0; ) fputs(" ", out); + fputs(" @words ", out); + PRUint32* wp = mWords; + PRInt32 total = mContentLength; + while (total != 0) { + PRUint32 wordInfo = *wp++; + nscoord wordWidth = GET_WORD_WIDTH(wordInfo); + PRIntn wordLen = GET_WORD_LENGTH(wordInfo); + fprintf(out, "%c-%d-%d ", + ((wordInfo & WORD_IS_WORD) ? 'w' : 's'), + wordWidth, wordLen); + total -= wordLen; + NS_ASSERTION(total >= 0, "bad word data"); + } + fputs("\n", out); + } +#endif +} + +//---------------------------------------------------------------------- +static NS_DEFINE_IID(kIDOMTextIID, NS_IDOMTEXT_IID); +static NS_DEFINE_IID(kIDOMNodeIID, NS_IDOMNODE_IID); + + +Text::Text(const PRUnichar* aText, PRInt32 aLength) +{ + if (0 == aLength) { + aLength = nsCRT::strlen(aText); + } + mLength = aLength; + mText = new PRUnichar[aLength]; + nsCRT::memcpy(mText, aText, aLength * sizeof(PRUnichar)); +} + +Text::Text() +{ + mText = nsnull; + mLength = 0; +} + +Text::~Text() +{ + if (nsnull != mText) { + delete mText; + mText = nsnull; + } + mLength = 0; +} + +nsresult Text::QueryInterface(const nsIID& aIID, void** aInstancePtr) +{ + NS_PRECONDITION(nsnull != aInstancePtr, "null pointer"); + + if (nsnull == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + + if (aIID.Equals(kIDOMTextIID)) { + *aInstancePtr = (void*)(nsIDOMText*)this; + nsHTMLContent::AddRef(); + return NS_OK; + } + if (aIID.Equals(kIDOMNodeIID)) { + *aInstancePtr = (void*)(nsIDOMNode*)(nsIDOMText*)this; + nsHTMLContent::AddRef(); + return NS_OK; + } + + return nsHTMLContent::QueryInterface(aIID, aInstancePtr); +} + +nsrefcnt Text::AddRef(void) +{ + return nsHTMLContent::AddRef(); +} + +nsrefcnt Text::Release(void) +{ + return nsHTMLContent::Release(); +} + +void Text::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out); + fputs("Text", out); + ListAttributes(out); + fprintf(out, " RefCnt=%d<\"", mRefCnt); + + nsAutoString tmp; + ToCString(tmp, 0, mLength); + fputs(tmp, out); + + fputs("\">\n", out); +} + +void Text::ToHTMLString(nsString& aBuf) const +{ + aBuf.SetLength(0); + aBuf.Append(mText, mLength); +} + +void Text::ToCString(nsString& aBuf, PRInt32 aOffset, PRInt32 aLen) const +{ + PRUnichar* cp = mText + aOffset; + PRUnichar* end = cp + aLen; + while (cp < end) { + PRUnichar ch = *cp++; + if (ch == '\r') { + aBuf.Append("\\r"); + } else if (ch == '\n') { + aBuf.Append("\\n"); + } else if (ch == '\t') { + aBuf.Append("\\t"); + } else if ((ch < ' ') || (ch >= 127)) { + aBuf.Append("\\0"); + aBuf.Append((PRInt32)ch, 8); + } else { + aBuf.Append(ch); + } + } +} + +#if 0 +// From nsITextContent; might want this later +PRInt32 Text::GetLength() +{ + return mLength; +} + +void Text::GetText(nsString& aBuf, PRInt32 aOffset, PRInt32 aCount) +{ + aBuf.SetLength(0); + if ((PRUint32(aOffset) >= PRUint32(mLength)) || + (aCount <= 0)) { + return; + } + if (aOffset + aCount > mLength) { + aCount = mLength - aOffset; + } + aBuf.Append(mText + aOffset, aCount); +} +#endif + +nsIFrame* Text::CreateFrame(nsIPresContext* aCX, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + nsIFrame* rv = new TextFrame(this, aIndexInParent, aParentFrame); + return rv; +} + +nsresult Text::GetScriptObject(JSContext *aContext, void** aScriptObject) +{ + nsresult res = NS_OK; + if (nsnull == mScriptObject) { + *aScriptObject = nsnull; + if (nsnull != mParent) { + nsIScriptObjectOwner *parent; + if (NS_OK == mParent->QueryInterface(kIScriptObjectOwner, (void**)&parent)) { + parent->GetScriptObject(aContext, aScriptObject); + NS_RELEASE(parent); + } + } + res = NS_NewScriptText(aContext, this, (JSObject*)*aScriptObject, (JSObject**)&mScriptObject); + } + *aScriptObject = mScriptObject; + return res; +} + +// +// nsIDOMText interface +// +nsresult Text::GetNodeType(PRInt32 *aType) +{ + *aType = nsHTMLContent::TEXT; + return NS_OK; +} + +nsresult Text::GetParentNode(nsIDOMNode **aNode) +{ + return nsHTMLContent::GetParentNode(aNode); +} + +nsresult Text::GetChildNodes(nsIDOMNodeIterator **aIterator) +{ + return nsHTMLContent::GetChildNodes(aIterator); +} + +nsresult Text::HasChildNodes() +{ + return nsHTMLContent::HasChildNodes(); +} + +nsresult Text::GetFirstChild(nsIDOMNode **aNode) +{ + return nsHTMLContent::GetFirstChild(aNode); +} + +nsresult Text::GetPreviousSibling(nsIDOMNode **aNode) +{ + return nsHTMLContent::GetPreviousSibling(aNode); +} + +nsresult Text::GetNextSibling(nsIDOMNode **aNode) +{ + return nsHTMLContent::GetNextSibling(aNode); +} + +nsresult Text::InsertBefore(nsIDOMNode *newChild, nsIDOMNode *refChild) +{ + return nsHTMLContent::InsertBefore(newChild, refChild); +} + +nsresult Text::ReplaceChild(nsIDOMNode *newChild, nsIDOMNode *oldChild) +{ + return nsHTMLContent::ReplaceChild(newChild, oldChild); +} + +nsresult Text::RemoveChild(nsIDOMNode *oldChild) +{ + return nsHTMLContent::RemoveChild(oldChild); +} + +nsresult Text::GetData(nsString &aString) +{ + if (nsnull != mText) { + aString = mText; + } + + return NS_OK; +} + +nsresult Text::SetData(nsString &aString) +{ + if (mText) delete[] mText; + + mLength = aString.Length(); + mText = aString.ToNewUnicode(); + return NS_OK; +} + +nsresult Text::Append(nsString &aData) +{ + PRUint32 length = aData.Length(); + PRUnichar *text = new PRUnichar[mLength + length]; + nsCRT::memcpy(text, mText, mLength * sizeof(PRUnichar)); + nsCRT::memcpy(text + mLength * sizeof(PRUnichar), aData.GetUnicode(), length * sizeof(PRUnichar)); + + if (mText) delete[] mText; + mLength += length; + mText = text; + + return NS_OK; +} + +nsresult Text::Insert(int offset, nsString &aData) +{ + if (offset < mLength) { + PRInt32 length = aData.Length(); + PRUnichar *text = new PRUnichar[mLength + length]; + PRUnichar *data = aData.GetUnicode(); + PRInt32 i; + + for (i = 0; i < offset; i++) { + *(text++) = *(mText++); + } + for (i = 0; i < length; i++) { + *(text++) = *(data++); + } + for (i = 0; i < mLength - offset; i++) { + *(text++) = *(mText++); + } + + if (mText) delete[] (mText - mLength); + mLength += length; + mText = text - mLength; + } + + return NS_OK; +} + +nsresult Text::Delete(int offset, int count) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult Text::Replace(int offset, int count, nsString &aData) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult Text::Splice(nsIDOMElement *element, int offset, int count) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult +NS_NewHTMLText(nsIHTMLContent** aInstancePtrResult, + const PRUnichar* us, PRInt32 uslen) +{ + nsIHTMLContent* it = new Text(us, uslen); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIHTMLContentIID, (void **) aInstancePtrResult); +} + +nsresult +NS_NewHTMLText(nsIHTMLContent** aInstancePtrResult, + nsIArena* aArena, const PRUnichar* us, PRInt32 uslen) +{ + nsIHTMLContent* it = new(aArena) Text(us, uslen); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIHTMLContentIID, (void **) aInstancePtrResult); +} + +//---------------------------------------------------------------------- + +class SharedText : public Text { +public: + SharedText(PRUnichar* aText, PRInt32 aLength); + +protected: + virtual ~SharedText(); +}; + +SharedText::SharedText(PRUnichar* aText, PRInt32 aLength) + : Text() +{ + if (0 == aLength) { + aLength = nsCRT::strlen(aText); + } + mText = aText; + mLength = aLength; +} + +SharedText::~SharedText() +{ + mText = nsnull; +} + +nsresult +NS_NewSharedHTMLText(nsIHTMLContent** aInstancePtrResult, + PRUnichar* us, PRInt32 uslen) +{ + nsIHTMLContent* it = new SharedText(us, uslen); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIHTMLContentIID, (void **) aInstancePtrResult); +} + +nsresult +NS_NewSharedHTMLText(nsIHTMLContent** aInstancePtrResult, + nsIArena* aArena, PRUnichar* us, PRInt32 uslen) +{ + nsIHTMLContent* it = new(aArena) SharedText(us, uslen); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIHTMLContentIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/layout/html/base/src/nsWBRPart.cpp b/mozilla/layout/html/base/src/nsWBRPart.cpp new file mode 100644 index 00000000000..9aaf833f41f --- /dev/null +++ b/mozilla/layout/html/base/src/nsWBRPart.cpp @@ -0,0 +1,68 @@ +/* -*- 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 "nsHTMLParts.h" +#include "nsHTMLTagContent.h" +#include "nsFrame.h" +#include "nsHTMLIIDs.h" + +class WBRPart : public nsHTMLTagContent { +public: + WBRPart(nsIAtom* aTag); + + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + +protected: + virtual ~WBRPart(); +}; + +WBRPart::WBRPart(nsIAtom* aTag) + : nsHTMLTagContent(aTag) +{ +} + +WBRPart::~WBRPart() +{ +} + +nsIFrame* WBRPart::CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + nsIFrame* frame; + nsresult rv = nsFrame::NewFrame(&frame, this, aIndexInParent, aParentFrame); + if (NS_OK == rv) { + return frame; + } + return nsnull; +} + +nsresult +NS_NewHTMLWordBreak(nsIHTMLContent** aInstancePtrResult, nsIAtom* aTag) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIHTMLContent* it = new WBRPart(aTag); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIHTMLContentIID, (void**) aInstancePtrResult); +} diff --git a/mozilla/layout/html/document/Makefile b/mozilla/layout/html/document/Makefile new file mode 100644 index 00000000000..b0ff7c06fd4 --- /dev/null +++ b/mozilla/layout/html/document/Makefile @@ -0,0 +1,24 @@ +#!gmake +# +# 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. + +DEPTH = ../../.. + +DIRS = src + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/layout/html/document/makefile.win b/mozilla/layout/html/document/makefile.win new file mode 100644 index 00000000000..d4bfe31b9cf --- /dev/null +++ b/mozilla/layout/html/document/makefile.win @@ -0,0 +1,23 @@ +#!nmake +# +# 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. + +DEPTH=..\..\.. +IGNORE_MANIFEST=1 + +DIRS=src + +include <$(DEPTH)\config\rules.mak> diff --git a/mozilla/layout/html/document/src/Makefile b/mozilla/layout/html/document/src/Makefile new file mode 100644 index 00000000000..71032b4bc1b --- /dev/null +++ b/mozilla/layout/html/document/src/Makefile @@ -0,0 +1,45 @@ +#!gmake +# +# 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. + +DEPTH=../../../.. + +include $(DEPTH)/config/config.mk + +LIBRARY_NAME = raptorhtmldoc_s + +LCFLAGS = -D_IMPL_NS_HTML + +INCLUDES += \ + -I../../base/src \ + -I../../forms/src \ + -I../../style/src \ + -I../../table/src \ + -I../../dom \ + $(NULL) + +# Note the sophisticated alphabetical ordering :-| +CPPSRCS = \ + nsHTMLContentSink.cpp \ + nsHTMLDocument.cpp \ + $(NULL) + +MODULE = raptor + +REQUIRES = xpcom raptor dom + +include $(DEPTH)/config/rules.mk + diff --git a/mozilla/layout/html/document/src/makefile.win b/mozilla/layout/html/document/src/makefile.win new file mode 100644 index 00000000000..56aa1493898 --- /dev/null +++ b/mozilla/layout/html/document/src/makefile.win @@ -0,0 +1,52 @@ +#!nmake +# +# 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. + +DEPTH=..\..\..\.. +IGNORE_MANIFEST=1 + +LIBRARY_NAME=raptorhtmldoc_s +MODULE=raptor +REQUIRES=xpcom raptor + +DEFINES=-D_IMPL_NS_HTML -I..\..\base\src -I..\..\forms\src \ + -I..\..\style\src -I..\..\table\src -I$(PUBLIC)\dom + +CPPSRCS=nsHTMLContentSink.cpp nsHTMLDocument.cpp + +CPP_OBJS=.\$(OBJDIR)\nsHTMLContentSink.obj \ + .\$(OBJDIR)\nsHTMLDocument.obj + +EXPORTS = \ + nsIHTMLDocument.h \ + $(NULL) + +LINCS=-I$(XPDIST)\public\xpcom -I$(XPDIST)\public\raptor + +LCFLAGS = \ + $(LCFLAGS) \ + $(DEFINES) \ + $(NULL) + +include <$(DEPTH)\config\rules.mak> + +libs:: $(LIBRARY) + $(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib + $(MAKE_INSTALL) ua.css $(DIST)\bin\res + +clobber:: + rm -f $(DIST)\lib\$(LIBRARY_NAME).lib + rm -f $(DIST)\bin\res\ua.css diff --git a/mozilla/layout/html/document/src/nsHTMLContentSink.cpp b/mozilla/layout/html/document/src/nsHTMLContentSink.cpp new file mode 100644 index 00000000000..77b8ae042d8 --- /dev/null +++ b/mozilla/layout/html/document/src/nsHTMLContentSink.cpp @@ -0,0 +1,1054 @@ +/* -*- 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 "nsIHTMLContentSink.h" +#include "nsIStyleSheet.h" +#include "nsIUnicharInputStream.h" +#include "nsIHTMLContent.h" +#include "nsIURL.h" +#include "nsHTMLDocument.h" +#include "nsIPresShell.h" +#include "nsIPresContext.h" +#include "nsHTMLTokens.h" +#include "nsCRT.h" +#include "prtime.h" +#include "prlog.h" + +#include "nsHTMLParts.h" +#include "nsTablePart.h" +#include "nsTableRow.h" +#include "nsTableCell.h" + +#include "nsHTMLForms.h" +#include "nsIFormManager.h" +#include "nsIImageMap.h" + +// XXX attribute values have entities in them - use the parsers expander! + +// XXX Go through a factory for this one +#include "nsICSSParser.h" + +#ifdef NS_DEBUG + +static PRInt32 gLogLevel = 0; + +#define NOISY_SINK_TRACE(_msg,_node) \ +{ \ + char buf[200]; \ + (_node).GetText().ToCString(buf, sizeof(buf)); \ + if (gLogLevel >= PR_LOG_WARNING) { \ + PR_LogPrint("%s; [%s]", _msg, buf); \ + } \ +} + +#define REALLY_NOISY_SINK_TRACE(_msg,_node) \ +{ \ + char buf[200]; \ + (_node).GetText().ToCString(buf, sizeof(buf)); \ + if (gLogLevel >= PR_LOG_DEBUG) { \ + PR_LogPrint("%s; [%s]", _msg, buf); \ + } \ +} + +#else /* !NOISY_SINK */ + +#define NOISY_SINK_TRACE(_a,_node) +#define REALLY_NOISY_SINK_TRACE(_a,_node) + +#endif /* NOISY_SINK */ + +//---------------------------------------------------------------------- + +static NS_DEFINE_IID(kIHTMLContentSinkIID, NS_IHTMLCONTENTSINK_IID); + +class HTMLContentSink : public nsIHTMLContentSink { +public: + + NS_DECL_ISUPPORTS + + HTMLContentSink(); + ~HTMLContentSink(); + + void* operator new(size_t size) { + void* rv = ::operator new(size); + nsCRT::zero(rv, size); + return (void*) rv; + } + + nsresult Init(nsIDocument* aDoc, nsIURL* aURL); + nsIHTMLContent* GetCurrentContainer(eHTMLTags* aType); + + virtual PRBool SetTitle(const nsString& aValue); + + // Called when Opening or closing the main HTML container + virtual PRBool OpenHTML(const nsIParserNode& aNode); + virtual PRBool CloseHTML(const nsIParserNode& aNode); + + // Called when Opening or closing the main HEAD container + virtual PRBool OpenHead(const nsIParserNode& aNode); + virtual PRBool CloseHead(const nsIParserNode& aNode); + + // Called when Opening or closing the main BODY container + virtual PRBool OpenBody(const nsIParserNode& aNode); + virtual PRBool CloseBody(const nsIParserNode& aNode); + + // Called when Opening or closing FORM containers + virtual PRBool OpenForm(const nsIParserNode& aNode); + virtual PRBool CloseForm(const nsIParserNode& aNode); + + // Called when Opening or closing the main FRAMESET container + virtual PRBool OpenFrameset(const nsIParserNode& aNode); + virtual PRBool CloseFrameset(const nsIParserNode& aNode); + + // Called when Opening or closing a general container + // This includes: OL,UL,DIR,SPAN,TABLE,H[1..6],etc. + // Until proven otherwise, I also plan to toss STYLE, + // FORMS, FRAME, SCRIPT, etc. here too! + virtual PRBool OpenContainer(const nsIParserNode& aNode); + virtual PRBool CloseContainer(const nsIParserNode& aNode); + virtual PRBool CloseTopmostContainer(); + + // Called for text, comments and so on... + virtual PRBool AddLeaf(const nsIParserNode& aNode); + +protected: + + void StartLayout(); + + void ReflowNewContent(); + + //---------------------------------------------------------------------- + // Leaf tag handler routines that translate a leaf tag into a + // content object, processing all of the tag attributes. + + nsresult ProcessAREATag(const nsIParserNode& aNode); + nsresult ProcessBASETag(const nsIParserNode& aNode); + nsresult ProcessSTYLETag(const nsIParserNode& aNode); + + nsresult ProcessBRTag(nsIHTMLContent** aInstancePtrResult, + const nsIParserNode& aNode); + nsresult ProcessHRTag(nsIHTMLContent** aInstancePtrResult, + const nsIParserNode& aNode); + nsresult ProcessINPUTTag(nsIHTMLContent** aInstancePtrResult, + const nsIParserNode& aNode); + nsresult ProcessIMGTag(nsIHTMLContent** aInstancePtrResult, + const nsIParserNode& aNode); + nsresult ProcessSPACERTag(nsIHTMLContent** aInstancePtrResult, + const nsIParserNode& aNode); + nsresult ProcessWBRTag(nsIHTMLContent** aInstancePtrResult, + const nsIParserNode& aNode); + + //---------------------------------------------------------------------- + + void GetAttributeValueAt(const nsIParserNode& aNode, + PRInt32 aIndex, + nsString& aResult); + + nsresult AddAttributes(const nsIParserNode& aNode, + nsIHTMLContent* aInstancePtrResult); + + nsresult LoadStyleSheet(nsIURL* aURL, + nsIUnicharInputStream* aUIN); + + nsIDocument* mDocument; + nsIURL* mDocumentURL; + + eHTMLTags mNodeStack[100];/* XXX */ + nsIHTMLContent* mContainerStack[100];/* XXX */ + PRInt32 mStackPos; + nsString* mTitle; + nsString mBaseHREF; + nsString mBaseTarget; + nsIStyleSheet* mStyleSheet; + nsIFormManager* mCurrentForm; + nsIImageMap* mCurrentMap; + + nsIHTMLContent* mRoot; + nsIHTMLContent* mBody; + + PRTime mLastUpdateTime; + PRTime mUpdateDelta; + PRBool mLayoutStarted; +}; + +// Note: operator new zeros our memory +HTMLContentSink::HTMLContentSink() +{ +#if 0 + if (nsnull == gSinkLog) { + gSinkLog = PR_NewLogModule("HTMLContentSink"); + } +#endif + + // Set the first update delta to be 50ms + LL_I2L(mUpdateDelta, PR_USEC_PER_MSEC * 50); +} + +HTMLContentSink::~HTMLContentSink() +{ + NS_IF_RELEASE(mBody); + NS_IF_RELEASE(mRoot); + NS_IF_RELEASE(mDocumentURL); + NS_IF_RELEASE(mStyleSheet); + NS_IF_RELEASE(mCurrentForm); + NS_IF_RELEASE(mCurrentMap); + if (nsnull != mTitle) { + delete mTitle; + } +} + +nsresult HTMLContentSink::Init(nsIDocument* aDoc, nsIURL* aDocURL) +{ + mDocument = aDoc; + NS_IF_ADDREF(aDoc); + + mDocumentURL = aDocURL; + NS_IF_ADDREF(aDocURL); + + // Make root part + nsresult rv = NS_NewRootPart(&mRoot, aDoc); + if (NS_OK == rv) { + } + + return rv; +} + +NS_IMPL_ISUPPORTS(HTMLContentSink,kIHTMLContentSinkIID) + +PRBool HTMLContentSink::OpenHTML(const nsIParserNode& aNode) +{ + NOISY_SINK_TRACE("OpenHTML", aNode) + NS_PRECONDITION(0 == mStackPos, "bad stack pos"); + + mNodeStack[0] = (eHTMLTags)aNode.GetNodeType(); + mContainerStack[0] = mRoot; + mStackPos = 1; + + return PR_TRUE; +} + +PRBool HTMLContentSink::CloseHTML(const nsIParserNode& aNode) +{ + NOISY_SINK_TRACE("CloseHTML", aNode) + + NS_ASSERTION(mStackPos > 0, "bad bad"); + mNodeStack[--mStackPos] = eHTMLTag_unknown; + + PRInt32 i, ns = mDocument->GetNumberOfShells(); + for (i = 0; i < ns; i++) { + nsIPresShell* shell = mDocument->GetShellAt(i); + if (nsnull != shell) { + shell->BeginObservingDocument(); + NS_RELEASE(shell); + } + } + NS_IF_RELEASE(mCurrentForm); + + return PR_TRUE; +} + +PRBool HTMLContentSink::OpenHead(const nsIParserNode& aNode) +{ + NOISY_SINK_TRACE("OpenHead", aNode) + + mNodeStack[mStackPos++] = (eHTMLTags)aNode.GetNodeType(); + return PR_TRUE; +} + +PRBool HTMLContentSink::CloseHead(const nsIParserNode& aNode) +{ + NOISY_SINK_TRACE("CloseHead", aNode) + + NS_ASSERTION(mStackPos > 0, "bad bad"); + mNodeStack[--mStackPos] = eHTMLTag_unknown; + return PR_TRUE; +} + +PRBool HTMLContentSink::SetTitle(const nsString& aValue) +{ + if (nsnull == mTitle) { + mTitle = new nsString(aValue); + } + else { + *mTitle = aValue; + } + mTitle->CompressWhitespace(PR_TRUE, PR_TRUE); + ((nsHTMLDocument*)mDocument)->SetTitle(*mTitle); + return PR_TRUE; +} + +PRBool HTMLContentSink::OpenBody(const nsIParserNode& aNode) +{ + NOISY_SINK_TRACE("OpenBody", aNode) + + PRBool startLayout = PR_FALSE; + if (nsnull == mBody) { + nsIAtom* atom = NS_NewAtom("BODY"); + nsresult rv = NS_NewBodyPart(&mBody, atom); + if (NS_OK == rv) { + mRoot->AppendChild(mBody); + startLayout = PR_TRUE; + } + NS_RELEASE(atom); + } + + mNodeStack[mStackPos] = (eHTMLTags)aNode.GetNodeType(); + mContainerStack[mStackPos] = mBody; + mStackPos++; + + // Add attributes to the body content object, but only if it's really a body + // tag that is triggering the OpenBody. + if (aNode.GetText().EqualsIgnoreCase("body")) { + AddAttributes(aNode, mBody); + // XXX If the body already existed and has been reflowed somewhat + // then we need to trigger a style change + } + + if (startLayout) { + // XXX This has to be done now that the body is in because we + // don't know how to handle a content-appended reflow if the + // root has no children + StartLayout(); + } + + return PR_TRUE; +} + +PRBool HTMLContentSink::CloseBody(const nsIParserNode& aNode) +{ + NOISY_SINK_TRACE("CloseBody", aNode) + + NS_ASSERTION(mStackPos > 0, "bad bad"); + mNodeStack[--mStackPos] = eHTMLTag_unknown; + + // Reflow any lingering content + ReflowNewContent(); + + return PR_TRUE; +} + + +PRBool HTMLContentSink::OpenForm(const nsIParserNode& aNode) +{ + NOISY_SINK_TRACE("OpenForm", aNode) + + // Close out previous form if it's there + if (nsnull != mCurrentForm) { + NS_RELEASE(mCurrentForm); + mCurrentForm = nsnull; + } + + // Create new form + nsAutoString tmp(aNode.GetText()); + tmp.ToUpperCase(); + nsIAtom* atom = NS_NewAtom(tmp); + nsresult rv = NS_NewHTMLForm(&mCurrentForm, atom); + NS_RELEASE(atom); + + if (NS_OK == rv) { + // Add tag attributes to the form + nsAutoString k, v; + PRInt32 ac = aNode.GetAttributeCount(); + for (PRInt32 i = 0; i < ac; i++) { + // Get upper-cased key + const nsString& key = aNode.GetKeyAt(i); + k.SetLength(0); + k.Append(key); + k.ToUpperCase(); + + // Get value and remove mandatory quotes + GetAttributeValueAt(aNode, i, v); + mCurrentForm->SetAttribute(k, v); + } + } + + return PR_TRUE; +} + +PRBool HTMLContentSink::CloseForm(const nsIParserNode& aNode) +{ + NOISY_SINK_TRACE("CloseForm", aNode) + + if (nsnull != mCurrentForm) { + NS_RELEASE(mCurrentForm); + mCurrentForm = nsnull; + } + return PR_TRUE; +} + +PRBool HTMLContentSink::OpenFrameset(const nsIParserNode& aNode) +{ + NOISY_SINK_TRACE("OpenFrameset", aNode) + + mNodeStack[mStackPos++] = (eHTMLTags)aNode.GetNodeType(); + return PR_TRUE; +} + +PRBool HTMLContentSink::CloseFrameset(const nsIParserNode& aNode) +{ + NOISY_SINK_TRACE("CloseFrameset", aNode) + + mNodeStack[--mStackPos] = eHTMLTag_unknown; + return PR_TRUE; +} + +PRBool HTMLContentSink::OpenContainer(const nsIParserNode& aNode) +{ + NOISY_SINK_TRACE("OpenContainer", aNode) + + nsAutoString tmp(aNode.GetText()); + tmp.ToUpperCase(); + nsIAtom* atom = NS_NewAtom(tmp); + + nsresult rv; + nsIHTMLContent* container = nsnull; + if (aNode.GetTokenType() == eToken_start) { + switch (aNode.GetNodeType()) { + case eHTMLTag_map: + NS_IF_RELEASE(mCurrentMap); + rv = NS_NewImageMap(&mCurrentMap, atom); + if (NS_OK == rv) { + // Look for name attribute and set the map name + PRInt32 ac = aNode.GetAttributeCount(); + for (PRInt32 i = 0; i < ac; i++) { + const nsString& key = aNode.GetKeyAt(i); + if (key.EqualsIgnoreCase("name")) { + nsAutoString name; + GetAttributeValueAt(aNode, i, name); + name.StripWhitespace(); // XXX leading, trailing, interior non=-space ws is removed + mCurrentMap->SetName(name); + } + } + // Add the map to the document + ((nsHTMLDocument*)mDocument)->AddImageMap(mCurrentMap); + } + return PR_TRUE; + + case eHTMLTag_table: + rv = NS_NewTablePart(&container, atom); + break; + + case eHTMLTag_caption: + rv = NS_NewTableCaptionPart(&container, atom); + break; + + case eHTMLTag_tr: + rv = NS_NewTableRowPart(&container, atom); + break; + + case eHTMLTag_tbody: + case eHTMLTag_thead: + case eHTMLTag_tfoot: + rv = NS_NewTableRowGroupPart(&container, atom); + break; + + case eHTMLTag_colgroup: + rv = NS_NewTableColGroupPart(&container, atom); + break; + + case eHTMLTag_col: + rv = NS_NewTableColPart(&container, atom); + break; + + case eHTMLTag_td: + case eHTMLTag_th: + rv = NS_NewTableCellPart(&container, atom); + break; + + default: + rv = NS_NewHTMLContainer(&container, atom); + break; + } + } + + // XXX for now assume that if it's a container, it's a simple container + mNodeStack[mStackPos] = (eHTMLTags) aNode.GetNodeType(); + mContainerStack[mStackPos] = container; + + if (nsnull != container) { + container->SetDocument(mDocument); + rv = AddAttributes(aNode, container); + mStackPos++; + } + + NS_RELEASE(atom); + return PR_TRUE; +} + +PRBool HTMLContentSink::CloseContainer(const nsIParserNode& aNode) +{ + NOISY_SINK_TRACE("CloseContainer", aNode) + + switch (aNode.GetNodeType()) { + case eHTMLTag_map: + NS_IF_RELEASE(mCurrentMap); + return PR_TRUE; + } + + // XXX we could assert things about the top tag name == aNode.getText + if (0 == mStackPos) { + // Can't pop empty stack + return PR_TRUE; + } + + --mStackPos; + nsIHTMLContent* container = mContainerStack[mStackPos]; + mNodeStack[mStackPos] = eHTMLTag_unknown; + mContainerStack[mStackPos] = nsnull; + + if (nsnull != container) { + // Now that this container is complete, append it to it's parent + eHTMLTags parentType; + nsIHTMLContent* parent = GetCurrentContainer(&parentType); + container->Compact(); + + if(parent) { + parent->AppendChild(container); + if (parent == mBody) { + // We just closed a child of the body off. Trigger a + // content-appended reflow if enough time has elapsed + PRTime now = PR_Now(); + if (now - mLastUpdateTime >= mUpdateDelta) { + mLastUpdateTime = now; + mUpdateDelta += mUpdateDelta; + ReflowNewContent(); + } + } + } + NS_RELEASE(container); + } + return PR_TRUE; +} + +void HTMLContentSink::StartLayout() +{ + if (!mLayoutStarted) { + PRInt32 i, ns = mDocument->GetNumberOfShells(); + for (i = 0; i < ns; i++) { + nsIPresShell* shell = mDocument->GetShellAt(i); + if (nsnull != shell) { + nsIPresContext* cx = shell->GetPresContext(); + nsRect r = cx->GetVisibleArea(); + shell->ResizeReflow(r.width, r.height); + NS_RELEASE(cx); + NS_RELEASE(shell); + } + } + mLayoutStarted = PR_TRUE; + } +} + +void HTMLContentSink::ReflowNewContent() +{ + printf("reflow body\n"); + + // Trigger reflows in each of the presentation shells + PRInt32 i, ns = mDocument->GetNumberOfShells(); + for (i = 0; i < ns; i++) { + nsIPresShell* shell = mDocument->GetShellAt(i); + if (nsnull != shell) { + shell->ContentAppended(mBody); + NS_RELEASE(shell); + } + } +} + +PRBool HTMLContentSink::CloseTopmostContainer() +{ + return PR_TRUE; +} + +nsIHTMLContent* HTMLContentSink::GetCurrentContainer(eHTMLTags* aType) +{ + nsIHTMLContent* parent; + if (mStackPos <= 2) { // assume HTML and BODY are on the stack + parent = mBody; + *aType = eHTMLTag_body; + } else { + parent = mContainerStack[mStackPos - 1]; + *aType = mNodeStack[mStackPos - 1]; + } + return parent; +} + +//---------------------------------------------------------------------- + +// Leaf tag handling code + +PRBool HTMLContentSink::AddLeaf(const nsIParserNode& aNode) +{ + REALLY_NOISY_SINK_TRACE("AddLeaf", aNode) + + // Check for nodes that require special handling + switch (aNode.GetNodeType()) { + case eHTMLTag_style: + ProcessSTYLETag(aNode); + return PR_TRUE; + + case eHTMLTag_script: + return PR_TRUE; + + case eHTMLTag_area: + ProcessAREATag(aNode); + return PR_TRUE; + } + + eHTMLTags parentType; + nsIHTMLContent* parent = GetCurrentContainer(&parentType); + + switch (parentType) { + case eHTMLTag_table: + case eHTMLTag_tr: + // XXX Discard leaf content (those annoying \n's really) in + // table's or table rows + return PR_TRUE; + } + + nsresult rv = NS_OK; + nsIHTMLContent* leaf = nsnull; + switch (aNode.GetTokenType()) { + case eToken_start: + switch (aNode.GetNodeType()) { + case eHTMLTag_br: + rv = ProcessBRTag(&leaf, aNode); + break; + case eHTMLTag_hr: + rv = ProcessHRTag(&leaf, aNode); + break; + case eHTMLTag_input: + rv = ProcessINPUTTag(&leaf, aNode); + break; + case eHTMLTag_img: + rv = ProcessIMGTag(&leaf, aNode); + break; + case eHTMLTag_spacer: + rv = ProcessSPACERTag(&leaf, aNode); + break; + } + break; + + case eToken_text: + case eToken_whitespace: + { + nsAutoString tmp; + tmp.Append(aNode.GetText()); + rv = NS_NewHTMLText(&leaf, tmp.GetUnicode(), tmp.Length()); + } + break; + + // XXX ick + case eToken_newline: + { + nsAutoString tmp; + tmp.Append('\n'); + rv = NS_NewHTMLText(&leaf, tmp.GetUnicode(), tmp.Length()); + } + break; + + case eToken_entity: + { + nsAutoString tmp; + PRInt32 unicode = aNode.TranslateToUnicode(); + if (unicode < 0) { + tmp.Append(aNode.GetText()); + } else { + tmp.Append(PRUnichar(unicode)); + } + rv = NS_NewHTMLText(&leaf, tmp.GetUnicode(), tmp.Length()); + } + break; + + case eToken_skippedcontent: + break; + } + + if (NS_OK == rv) { + if (nsnull != leaf) { + if (nsnull != parent) { + parent->AppendChild(leaf); + } else { + // XXX drop stuff on the floor that doesn't have a container! + // Bad parser! + } + } + } + NS_IF_RELEASE(leaf); + + return PR_TRUE; +} + +void HTMLContentSink::GetAttributeValueAt(const nsIParserNode& aNode, + PRInt32 aIndex, + nsString& aResult) +{ + // Copy value + const nsString& value = aNode.GetValueAt(aIndex); + aResult.Truncate(); + aResult.Append(value); + + // strip quotes if present + PRUnichar first = aResult.First(); + if ((first == '"') || (first == '\'')) { + if (aResult.Last() == first) { + aResult.Cut(0, 1); + PRInt32 pos = aResult.Length() - 1; + if (pos >= 0) { + aResult.Cut(pos, 1); + } + } else { + // Mismatched quotes - leave them in + } + } +} + +nsresult HTMLContentSink::AddAttributes(const nsIParserNode& aNode, + nsIHTMLContent* aInstancePtrResult) +{ + nsIContent* content = (nsIContent*) aInstancePtrResult; + + // Add tag attributes to the content attributes + nsAutoString k, v; + PRInt32 ac = aNode.GetAttributeCount(); + for (PRInt32 i = 0; i < ac; i++) { + // Get upper-cased key + const nsString& key = aNode.GetKeyAt(i); + k.Truncate(); + k.Append(key); + k.ToUpperCase(); + + // Get value and remove mandatory quotes + GetAttributeValueAt(aNode, i, v); + + content->SetAttribute(k, v); + } + + return NS_OK; +} + +nsresult HTMLContentSink::ProcessAREATag(const nsIParserNode& aNode) +{ + if (nsnull != mCurrentMap) { + nsAutoString shape, coords, href, target(mBaseTarget), alt; + PRInt32 ac = aNode.GetAttributeCount(); + PRBool suppress = PR_FALSE; + for (PRInt32 i = 0; i < ac; i++) { + // Get upper-cased key + const nsString& key = aNode.GetKeyAt(i); + if (key.EqualsIgnoreCase("shape")) { + GetAttributeValueAt(aNode, i, shape); + } + else if (key.EqualsIgnoreCase("coords")) { + GetAttributeValueAt(aNode, i, coords); + } + else if (key.EqualsIgnoreCase("href")) { + GetAttributeValueAt(aNode, i, href); + href.StripWhitespace(); + } + else if (key.EqualsIgnoreCase("target")) { + GetAttributeValueAt(aNode, i, target); + } + else if (key.EqualsIgnoreCase("alt")) { + GetAttributeValueAt(aNode, i, alt); + } + else if (key.EqualsIgnoreCase("suppress")) { + suppress = PR_TRUE; + } + } + mCurrentMap->AddArea(mBaseHREF, shape, coords, href, target, alt, + suppress); + } + return NS_OK; +} + +nsresult HTMLContentSink::ProcessBASETag(const nsIParserNode& aNode) +{ + PRInt32 ac = aNode.GetAttributeCount(); + for (PRInt32 i = 0; i < ac; i++) { + const nsString& key = aNode.GetKeyAt(i); + if (key.EqualsIgnoreCase("href")) { + const nsString& href = aNode.GetValueAt(i); + if (href.Length() > 0) { + mBaseHREF = href; + } + } else if (key.EqualsIgnoreCase("target")) { + + const nsString& target= aNode.GetValueAt(i); + if (target.Length() > 0) { + mBaseTarget = target; + } + } + } + return NS_OK; +} + +nsresult HTMLContentSink::ProcessBRTag(nsIHTMLContent** aInstancePtrResult, + const nsIParserNode& aNode) +{ + nsresult rv = NS_OK; + nsAutoString tmp(aNode.GetText()); + tmp.ToUpperCase(); + nsIAtom* atom = NS_NewAtom(tmp); + rv = NS_NewHTMLBreak(aInstancePtrResult, atom); + if (NS_OK == rv) { + rv = AddAttributes(aNode, *aInstancePtrResult); + } + NS_RELEASE(atom); + return rv; +} + +nsresult HTMLContentSink::ProcessHRTag(nsIHTMLContent** aInstancePtrResult, + const nsIParserNode& aNode) +{ + nsresult rv = NS_OK; + nsAutoString tmp(aNode.GetText()); + tmp.ToUpperCase(); + nsIAtom* atom = NS_NewAtom(tmp); + rv = NS_NewHRulePart(aInstancePtrResult, atom); + if (NS_OK == rv) { + rv = AddAttributes(aNode, *aInstancePtrResult); + } + NS_RELEASE(atom); + return rv; +} + +nsresult HTMLContentSink::ProcessIMGTag(nsIHTMLContent** aInstancePtrResult, + const nsIParserNode& aNode) +{ + nsAutoString tmp(aNode.GetText()); + tmp.ToUpperCase(); + nsIAtom* atom = NS_NewAtom(tmp); + nsresult rv = NS_NewHTMLImage(aInstancePtrResult, atom); + if (NS_OK == rv) { + rv = AddAttributes(aNode, *aInstancePtrResult); + // XXX get base url to image + } + NS_RELEASE(atom); + return rv; +} + +nsresult HTMLContentSink::ProcessSPACERTag(nsIHTMLContent** aInstancePtrResult, + const nsIParserNode& aNode) +{ + nsAutoString tmp(aNode.GetText()); + tmp.ToUpperCase(); + nsIAtom* atom = NS_NewAtom(tmp); + nsresult rv = NS_NewHTMLSpacer(aInstancePtrResult, atom); + if (NS_OK == rv) { + rv = AddAttributes(aNode, *aInstancePtrResult); + } + NS_RELEASE(atom); + return rv; +} + +// 3 ways to load a style sheet: inline, style src=, link tag + // XXX What does nav do if we have SRC= and some style data inline? +nsresult HTMLContentSink::ProcessSTYLETag(const nsIParserNode& aNode) +{ + nsresult rv = NS_OK; + PRInt32 i, ac = aNode.GetAttributeCount(); + + nsString* src = nsnull; + for (i = 0; i < ac; i++) { + const nsString& key = aNode.GetKeyAt(i); + if (key.EqualsIgnoreCase("src")) { + src = new nsString(aNode.GetValueAt(i)); + } + } + + // The skipped content contains the inline style data + const nsString& content = aNode.GetSkippedContent(); + + nsIURL* url = nsnull; + nsIUnicharInputStream* uin = nsnull; + if (nsnull == src) { + // Create a string to hold the data and wrap it up in a unicode + // input stream. + rv = NS_NewStringUnicharInputStream(&uin, new nsString(content)); + if (NS_OK != rv) { + return rv; + } + + // Use the document's url since the style data came from there + url = mDocumentURL; + NS_IF_ADDREF(url); + } else { + // src with immediate style data doesn't add up + // XXX what does nav do? + char* spec = src->ToNewCString(); + rv = NS_NewURL(&url, nsnull, spec); + delete spec; + delete src; + if (NS_OK != rv) { + return rv; + } + PRInt32 ec; + nsIInputStream* iin = url->Open(&ec); + if (nsnull == iin) { + NS_RELEASE(url); + return (nsresult) ec;/* XXX fix url->Open */ + } + rv = NS_NewConverterStream(&uin, nsnull, iin); + NS_RELEASE(iin); + if (NS_OK != rv) { + NS_RELEASE(url); + return rv; + } + } + + // Now that we have a url and a unicode input stream, parse the + // style sheet. + rv = LoadStyleSheet(url, uin); + NS_RELEASE(uin); + NS_RELEASE(url); + + return rv; +} + +nsresult HTMLContentSink::LoadStyleSheet(nsIURL* aURL, + nsIUnicharInputStream* aUIN) +{ + /* XXX use repository */ + nsICSSParser* parser; + nsresult rv = NS_NewCSSParser(&parser); + if (NS_OK == rv) { + PRInt32 ec; + if (nsnull != mStyleSheet) { + parser->SetStyleSheet(mStyleSheet); + // XXX we do probably need to trigger a style change reflow + // when we are finished if this is adding data to the same sheet + } + nsIStyleSheet* sheet = parser->Parse(&ec, aUIN, mDocumentURL); + if (nsnull != sheet) { + if (nsnull == mStyleSheet) { + // Add in the sheet the first time; if we update the sheet + // with new data (mutliple style tags in the same document) + // then the sheet will be updated by the css parser and + // therefore we don't need to add it to the document) + mDocument->AddStyleSheet(sheet); + mStyleSheet = sheet; + } + rv = NS_OK; + } else { + rv = NS_ERROR_OUT_OF_MEMORY;/* XXX */ + } + NS_RELEASE(parser); + } + return rv; +} + + +nsresult HTMLContentSink::ProcessINPUTTag(nsIHTMLContent** aInstancePtrResult, + const nsIParserNode& aNode) +{ + nsAutoString tmp(aNode.GetText()); + tmp.ToUpperCase(); + nsIAtom* atom = NS_NewAtom(tmp); + + nsresult rv = NS_ERROR_NOT_INITIALIZED; + + // Find type attribute and then create the appropriate form element + PRInt32 ac = aNode.GetAttributeCount(); + for (PRInt32 i = 0; i < ac; i++) { + const nsString& key = aNode.GetKeyAt(i); + if (key.EqualsIgnoreCase("type")) { + const nsString& val= aNode.GetValueAt(i); + if (val.EqualsIgnoreCase("submit")) { + rv = NS_NewHTMLInputSubmit(aInstancePtrResult, atom, mCurrentForm); + } + else if (val.EqualsIgnoreCase("reset")) { + rv = NS_NewHTMLInputReset(aInstancePtrResult, atom, mCurrentForm); + } + else if (val.EqualsIgnoreCase("button")) { + rv = NS_NewHTMLInputButton(aInstancePtrResult, atom, mCurrentForm); + } + else if (val.EqualsIgnoreCase("checkbox")) { + rv = NS_NewHTMLInputCheckbox(aInstancePtrResult, atom, mCurrentForm); + } + else if (val.EqualsIgnoreCase("file")) { + rv = NS_NewHTMLInputFile(aInstancePtrResult, atom, mCurrentForm); + } + else if (val.EqualsIgnoreCase("hidden")) { + rv = NS_NewHTMLInputHidden(aInstancePtrResult, atom, mCurrentForm); + } + else if (val.EqualsIgnoreCase("image")) { + rv = NS_NewHTMLInputImage(aInstancePtrResult, atom, mCurrentForm); + } + else if (val.EqualsIgnoreCase("password")) { + rv = NS_NewHTMLInputPassword(aInstancePtrResult, atom, mCurrentForm); + } + else if (val.EqualsIgnoreCase("radio")) { + rv = NS_NewHTMLInputRadio(aInstancePtrResult, atom, mCurrentForm); + } + else if (val.EqualsIgnoreCase("text")) { + rv = NS_NewHTMLInputText(aInstancePtrResult, atom, mCurrentForm); + } + else { + rv = NS_NewHTMLInputSubmit(aInstancePtrResult, atom, mCurrentForm); + } + break; + } + } + + if (NS_ERROR_NOT_INITIALIZED == rv) { + // Create textfield when no type is specified + rv = NS_NewHTMLInputText(aInstancePtrResult, atom, mCurrentForm); + } + + if ((NS_OK == rv) && (nsnull != *aInstancePtrResult)) { + // Add remaining attributes from the tag + rv = AddAttributes(aNode, *aInstancePtrResult); + } + + NS_RELEASE(atom); + return rv; +} + +nsresult HTMLContentSink::ProcessWBRTag(nsIHTMLContent** aInstancePtrResult, + const nsIParserNode& aNode) +{ + nsAutoString tmp(aNode.GetText()); + tmp.ToUpperCase(); + nsIAtom* atom = NS_NewAtom(tmp); + nsresult rv = NS_NewHTMLWordBreak(aInstancePtrResult, atom); + if (NS_OK == rv) { + rv = AddAttributes(aNode, *aInstancePtrResult); + } + NS_RELEASE(atom); + return rv; +} + +//---------------------------------------------------------------------- + +nsresult NS_NewHTMLContentSink(nsIHTMLContentSink** aInstancePtrResult, + nsIDocument* aDoc, + nsIURL* aURL) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + HTMLContentSink* it = new HTMLContentSink(); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + nsresult rv = it->Init(aDoc, aURL); + if (NS_OK != rv) { + delete it; + return rv; + } + return it->QueryInterface(kIHTMLContentSinkIID, (void **)aInstancePtrResult); +} diff --git a/mozilla/layout/html/document/src/nsHTMLDocument.cpp b/mozilla/layout/html/document/src/nsHTMLDocument.cpp new file mode 100644 index 00000000000..0beeedc38f6 --- /dev/null +++ b/mozilla/layout/html/document/src/nsHTMLDocument.cpp @@ -0,0 +1,280 @@ +/* -*- 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 "nsHTMLDocument.h" +#include "nsIParser.h" +#include "nsIHTMLContentSink.h" +#include "nsHTMLParts.h" +#include "nsIHTMLStyleSheet.h" +#include "nsIStyleSet.h" +#include "nsIDocumentObserver.h" +#include "nsHTMLAtoms.h" +#include "nsIPresShell.h" +#include "nsIPresContext.h" +#include "nsIImageMap.h" + +static NS_DEFINE_IID(kIDocumentIID, NS_IDOCUMENT_IID); +static NS_DEFINE_IID(kIHTMLDocumentIID, NS_IHTMLDOCUMENT_IID); + +NS_LAYOUT nsresult +NS_NewHTMLDocument(nsIDocument** aInstancePtrResult) +{ + nsHTMLDocument* doc = new nsHTMLDocument(); + return doc->QueryInterface(kIDocumentIID, (void**) aInstancePtrResult); +} + +nsHTMLDocument::nsHTMLDocument() + : nsDocument(), + mAttrStyleSheet(nsnull) +{ + nsHTMLAtoms::AddrefAtoms(); +} + +nsHTMLDocument::~nsHTMLDocument() +{ + NS_IF_RELEASE(mAttrStyleSheet); + nsHTMLAtoms::ReleaseAtoms(); +} + +NS_IMETHODIMP nsHTMLDocument::QueryInterface(REFNSIID aIID, + void** aInstancePtr) +{ + NS_PRECONDITION(nsnull != aInstancePtr, "null ptr"); + if (nsnull == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kIHTMLDocumentIID)) { + AddRef(); + *aInstancePtr = (void**) &mIHTMLDocument; + return NS_OK; + } + return nsDocument::QueryInterface(aIID, aInstancePtr); +} + +void nsHTMLDocument::LoadURL(nsIURL* aURL) +{ + NS_IF_RELEASE(mAttrStyleSheet); + NS_IF_RELEASE(mDocumentURL); + if (nsnull != mDocumentTitle) { + delete mDocumentTitle; + mDocumentTitle = nsnull; + } + + mDocumentURL = aURL; + NS_ADDREF(aURL); + + nsIParser* parser; + nsresult rv = NS_NewHTMLParser(&parser); + if (NS_OK == rv) { + nsIHTMLContentSink* sink; + rv = NS_NewHTMLContentSink(&sink, this, aURL); + if (NS_OK == rv) { + if (NS_OK == NS_NewHTMLStyleSheet(&mAttrStyleSheet, aURL)) { + AddStyleSheet(mAttrStyleSheet); // tell the world about our new style sheet + } + + parser->SetContentSink(sink); + parser->Parse(aURL); + NS_RELEASE(sink); + } + NS_RELEASE(parser); + } + //XXX return NS_OK; +} + +static NS_DEFINE_IID(kIDocumentObserverIID, NS_IDOCUMENTOBSERVER_IID); + +NS_IMETHODIMP nsHTMLDocument::SetTitle(const nsString& aTitle) +{ + if (nsnull == mDocumentTitle) { + mDocumentTitle = new nsString(aTitle); + } + else { + *mDocumentTitle = aTitle; + } + + // Pass on title to observers + PRInt32 i, n = mObservers.Count(); + for (i = 0; i < n; i++) { + nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; + observer->SetTitle(*mDocumentTitle); + } + + // Pass on to any interested containers + n = mPresShells.Count(); + for (i = 0; i < n; i++) { + nsIPresShell* shell = (nsIPresShell*) mPresShells.ElementAt(i); + nsIPresContext* cx = shell->GetPresContext(); + nsISupports* container; + if (NS_OK == cx->GetContainer(&container)) { + if (nsnull != container) { + nsIDocumentObserver* docob; + if (NS_OK == container->QueryInterface(kIDocumentObserverIID, + (void**) &docob)) { + docob->SetTitle(aTitle); + NS_RELEASE(docob); + } + NS_RELEASE(container); + } + } + NS_RELEASE(cx); + } + + return NS_OK; +} + +NS_IMETHODIMP nsHTMLDocument::AddImageMap(nsIImageMap* aMap) +{ + NS_PRECONDITION(nsnull != aMap, "null ptr"); + if (nsnull == aMap) { + return NS_ERROR_NULL_POINTER; + } + if (mImageMaps.AppendElement(aMap)) { + NS_ADDREF(aMap); + return NS_OK; + } + return NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP nsHTMLDocument::GetImageMap(const nsString& aMapName, + nsIImageMap** aResult) +{ + NS_PRECONDITION(nsnull != aResult, "null ptr"); + if (nsnull == aResult) { + return NS_ERROR_NULL_POINTER; + } + + nsAutoString name; + PRInt32 i, n = mImageMaps.Count(); + for (i = 0; i < n; i++) { + nsIImageMap* map = (nsIImageMap*) mImageMaps.ElementAt(i); + if (NS_OK == map->GetName(name)) { + if (name.EqualsIgnoreCase(aMapName)) { + *aResult = map; + NS_ADDREF(map); + return NS_OK; + } + } + } + + return 1;/* XXX NS_NOT_FOUND */ +} + +void nsHTMLDocument::AddStyleSheetToSet(nsIStyleSheet* aSheet, nsIStyleSet* aSet) +{ + if ((nsnull != mAttrStyleSheet) && (aSheet != mAttrStyleSheet)) { + aSet->InsertDocStyleSheetBefore(aSheet, mAttrStyleSheet); + } + else { + aSet->AppendDocStyleSheet(aSheet); + } +} + +//---------------------------------------------------------------------- + +// Aggregation class to give nsHTMLDocument the nsIHTMLDocument interface + +#define GET_OUTER() \ + ((nsHTMLDocument*) ((char*)this - nsHTMLDocument::GetOuterOffset())) + +nsHTMLDocument::AggIHTMLDocument::AggIHTMLDocument() { + NS_INIT_REFCNT(); +} + +nsHTMLDocument::AggIHTMLDocument::~AggIHTMLDocument() { } + +NS_IMETHODIMP_(nsrefcnt) nsHTMLDocument::AggIHTMLDocument::AddRef() { + return GET_OUTER()->AddRef(); +} + +NS_IMETHODIMP_(nsrefcnt) nsHTMLDocument::AggIHTMLDocument::Release() { + return GET_OUTER()->Release(); +} + +NS_IMETHODIMP nsHTMLDocument::AggIHTMLDocument::QueryInterface(REFNSIID aIID, + void** aInstancePtr) +{ + return GET_OUTER()->QueryInterface(aIID, aInstancePtr); +} + +NS_IMETHODIMP nsHTMLDocument::AggIHTMLDocument::SetTitle(const nsString& aTitle) { + return GET_OUTER()->SetTitle(aTitle); +} + +NS_IMETHODIMP nsHTMLDocument::AggIHTMLDocument::AddImageMap(nsIImageMap* aMap) { + return GET_OUTER()->AddImageMap(aMap); +} + +NS_IMETHODIMP nsHTMLDocument::AggIHTMLDocument::GetImageMap(const nsString& aMapName, + nsIImageMap** aResult) { + return GET_OUTER()->GetImageMap(aMapName, aResult); +} + +//---------------------------------------------------------------------- + +#ifdef NS_DEBUG + +NS_LAYOUT void +NS_HackAppendContent(nsIDocument* aDoc) +{ + ((nsHTMLDocument*)aDoc)->HackAppendContent(); +} + +#include "nsIHTMLContent.h" +#include "nsIAtom.h" + +static const char* kBigParagraph = +"This is some text. It will be word wrapped because our container will " +"word wrap us. It will also be baseline aligned because our container " +"will do that too. "; + +#define NUM_BIG_TEXTS 114 + +nsresult nsHTMLDocument::HackAppendSimpleSpan(nsIContent* aContainer, + const char* aTag, + const char* aText) +{ + nsIHTMLContent* span; + nsIHTMLContent* text; + nsIAtom* atom = NS_NewAtom(aTag); + nsresult rv = NS_NewHTMLContainer(&span, atom); + if (NS_OK == rv) { + nsAutoString tmp; + for (PRIntn i = 0; i < NUM_BIG_TEXTS; i++) { + tmp.Append(aText); + } + rv = NS_NewHTMLText(&text, tmp.GetUnicode(), tmp.Length()); + if (NS_OK == rv) { + span->AppendChild(text); + NS_RELEASE(text); + } + aContainer->AppendChild(span); + NS_RELEASE(span); + } + NS_RELEASE(atom); + return rv; +} + +void nsHTMLDocument::HackAppendContent() +{ + nsIContent* body = mRootContent->ChildAt(0); + HackAppendSimpleSpan(body, "P", kBigParagraph); + NS_RELEASE(body); +} +#endif + + diff --git a/mozilla/layout/html/document/src/nsHTMLDocument.h b/mozilla/layout/html/document/src/nsHTMLDocument.h new file mode 100644 index 00000000000..2e1fc1e04d0 --- /dev/null +++ b/mozilla/layout/html/document/src/nsHTMLDocument.h @@ -0,0 +1,76 @@ +/* -*- 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. + */ +#ifndef nsHTMLDocument_h___ +#define nsHTMLDocument_h___ + +#include "nsDocument.h" +#include "nsIHTMLDocument.h" + +class nsIHTMLStyleSheet; + +class nsHTMLDocument : public nsDocument { +public: + nsHTMLDocument(); + virtual ~nsHTMLDocument(); + + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); + + virtual void LoadURL(nsIURL* aURL); + + NS_IMETHOD SetTitle(const nsString& aTitle); + + NS_IMETHOD AddImageMap(nsIImageMap* aMap); + + NS_IMETHOD GetImageMap(const nsString& aMapName, nsIImageMap** aResult); + + static PRInt32 GetOuterOffset() { + return offsetof(nsHTMLDocument,mIHTMLDocument); + } + +protected: + virtual void AddStyleSheetToSet(nsIStyleSheet* aSheet, nsIStyleSet* aSet); + +#ifdef NS_DEBUG +public: + void HackAppendContent(); + +protected: + nsresult HackAppendSimpleSpan(nsIContent* aContainer, const char* aTag, + const char* aText); +#endif + + class AggIHTMLDocument : public nsIHTMLDocument { + public: + AggIHTMLDocument(); + ~AggIHTMLDocument(); + + NS_DECL_ISUPPORTS + + NS_IMETHOD SetTitle(const nsString& aTitle); + + NS_IMETHOD AddImageMap(nsIImageMap* aMap); + + NS_IMETHOD GetImageMap(const nsString& aMapName, nsIImageMap** aResult); + }; + + AggIHTMLDocument mIHTMLDocument; + nsIHTMLStyleSheet* mAttrStyleSheet; + nsVoidArray mImageMaps; +}; + +#endif /* nsHTMLDocument_h___ */ diff --git a/mozilla/layout/html/document/src/nsIHTMLDocument.h b/mozilla/layout/html/document/src/nsIHTMLDocument.h new file mode 100644 index 00000000000..b6d9cd8a6b1 --- /dev/null +++ b/mozilla/layout/html/document/src/nsIHTMLDocument.h @@ -0,0 +1,41 @@ +/* -*- 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. + */ +#ifndef nsIHTMLDocument_h___ +#define nsIHTMLDocument_h___ + +#include "nsISupports.h" +class nsIImageMap; +class nsString; + +/* b2a848b0-d0a9-11d1-89b1-006008911b81 */ +#define NS_IHTMLDOCUMENT_IID \ +{0xb2a848b0, 0xd0a9, 0x11d1, {0x89, 0xb1, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81}} + +/** + * HTML document extensions to nsIDocument. + */ +class nsIHTMLDocument : public nsISupports { +public: + NS_IMETHOD SetTitle(const nsString& aTitle) = 0; + + NS_IMETHOD AddImageMap(nsIImageMap* aMap) = 0; + + NS_IMETHOD GetImageMap(const nsString& aMapName, nsIImageMap** aResult) = 0; +}; + +#endif /* nsIHTMLDocument_h___ */ diff --git a/mozilla/layout/html/document/src/ua.css b/mozilla/layout/html/document/src/ua.css new file mode 100644 index 00000000000..2f44c42e563 --- /dev/null +++ b/mozilla/layout/html/document/src/ua.css @@ -0,0 +1,286 @@ +/* + * 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. + */ + +// It's probably cheaper to have a single rule per tag than to have to +// merge rules + +// XXX I'm starting to believe that this portion of the style sheet +// comes from the PresentationContext. + +// XXX temporary hack +IMPLICITP { + display: block; + margin-top: 0pt; + margin-bottom: 2pt; +} + +BODY { + font-family: "Times Roman", serif; + font-style: normal; + font-variant: normal; + font-weight: normal; + font-size: 10pt; + line-height: 1.1; + background: rgb(255,255,255); +// background: rgb(192,192,192); + color: black; + margin: 10px; + display: block; +} + +// XXX Use this! +FRAMESET { + font-family: "Times Roman", serif; + font-style: normal; + font-variant: normal; + font-weight: normal; + font-size: medium; + background: rgb(192,192,192); + color: black; + margin: 0px; + display: block; +} + +// XXX Used when PagePreview'ing +PAGE { + margin: 10px; + background: white; + border: black solid 1px; + display: block; +} + +//---------------------------------------------------------------------- + +// This part of the ua.css is junk taken from the css1 spec and used as +// a temporary style sheet. + +UL, OL, DL { display: block; } +DT, DD { display: block; } +LI { display: list-item; } +IMG { display: inline; } +SPACER { display: inline; } +WBR { display: inline; } + +// Default list-style-type styles. +// The Navigator 3.0 rule is: +// Zeroth-level: small disc. (Needs to be handled by parser.) +// First level: disc +// second level: circle +// third and higher levels: square. +// +// These style rules assume that MENU and DIR have been mapped to UL. + +UL { + list-style-type: disc; +} + +OL UL, UL UL { + list-style-type: circle; +} + +UL UL UL, UL OL UL, OL UL UL, OL OL UL { + list-style-type: square; +} + +OL { + list-style-type: decimal; +} + +UL, OL { + padding-left: 40px; /* nav4's value */ +} + +DT { margin-bottom: 0 } +DD { margin-top: 0; margin-left: .25in; } + +A:link { color: blue; text-decoration: underline } +A:visited { color: purple; text-decoration: underline } +A:active { color: lime; text-decoration: underline } +A:out-of-date { color: red; text-decoration: underline } + +A:link IMG { border: 2px solid blue; text-decoration: underline } +A:visited IMG { border: 2px solid purple; text-decoration: underline } +A:active IMG { border: 2px solid lime; text-decoration: underline } +A:out-of-date IMG { border: 2px solid red; text-decoration: underline } + +IMG { border-style: solid; border-color: blue; } +//INPUT { border-style: solid; border-color: blue; } + +//---------------------------------------------------------------------- +// The real stuff + +HR { + display: block; + height: 3px; + margin-top: 5px; + margin-bottom: 5px; +} + +BR { + display: block; +} + +// Block tags +ADDRESS { + display: block; + font-style: italic; +} +BLOCKQUOTE { + display: block; + margin-left: .25in; + margin-right: .25in; +} +CENTER { + display: block; + text-align: center; +} +DIV { + display: block; +} +H1 { + display: block; + font-size: 22pt; + font-weight: bold; + margin-top: 2pt; + margin-bottom: 2pt; +} +H2 { + display: block; + font-size: 16pt; + font-weight: bold; + margin-top: 2pt; + margin-bottom: 2pt; +} +H3 { + display: block; + font-size: 13pt; + font-weight: bold; + margin-top: 2pt; + margin-bottom: 2pt; +} +H4 { + display: block; + font-size: 12pt; + font-weight: bold; + margin-top: 2pt; + margin-bottom: 2pt; +} +H5 { + display: block; + font-size: 9pt; + font-weight: bold; + margin-top: 2pt; + margin-bottom: 2pt; +} +H6 { + display: block; + font-size: 8pt; + font-weight: bold; + margin-top: 2pt; + margin-bottom: 2pt; +} +LISTING { + display: block; + font-family: monospace; + font-size: small; + white-space: pre; +} +NOBR { + display: inline; + white-space: pre; // XXX approximation? +} +P { + display: block; + margin-top: 2pt; + margin-bottom: 2pt; +} +PLAINTEXT, XMP, PRE { + display: block; // Note: need before and after breaks + font-family: monospace; + white-space: pre; +} + +// Table tags +TABLE { + border-style: outset; + border-color: #C0C0C0; + cell-spacing: 4px; +} +TD { + vertical-align: middle; + border-style: inset; + border-color: #C0C0C0; +} +TH { + vertical-align: middle; + text-align: center; + font-weight: bold; + border-style: inset; + border-color: #C0C0C0; +} +// XXX Special rule to eliminate margin around for nav4 compatability +// XXX This isn't good enough because we only want the margin eliminated +// around the first paragraph! +/*TD P, TH P { + margin-top: 0; + margin-bottom: 0; +}*/ + +// Span tags +B, STRONG { + display: inline; + font-weight: bolder; +} +I, CITE, EM, VAR { + display: inline; + font-style: italic; +} +TT, CODE, KBD, SAMP { + display: inline; + font-family: monospace; +} +U { + display: inline; + text-decoration: underline; +} +S, STRIKE { + display: inline; + text-decoration: line-through; +} +BLINK { + display: inline; + text-decoration: blink; +} +BIG { + display: inline; + font-size: larger; +} +SMALL { + display: inline; + font-size: smaller; +} +DFN, SPAN { + display: inline; +} +SUB { + display: inline; + vertical-align: sub; +} +SUP { + display: inline; + vertical-align: super; +} diff --git a/mozilla/layout/html/forms/Makefile b/mozilla/layout/html/forms/Makefile new file mode 100644 index 00000000000..c650dc9b7ab --- /dev/null +++ b/mozilla/layout/html/forms/Makefile @@ -0,0 +1,24 @@ +#!gmake +# +# 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. + +DEPTH = ../../.. + +DIRS = public src + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/layout/html/forms/makefile.win b/mozilla/layout/html/forms/makefile.win new file mode 100644 index 00000000000..c9c67f325a1 --- /dev/null +++ b/mozilla/layout/html/forms/makefile.win @@ -0,0 +1,23 @@ +#!nmake +# +# 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. + +DEPTH=..\..\.. +IGNORE_MANIFEST=1 + +DIRS=public src + +include <$(DEPTH)\config\rules.mak> diff --git a/mozilla/layout/html/forms/public/Makefile b/mozilla/layout/html/forms/public/Makefile new file mode 100644 index 00000000000..07635497a87 --- /dev/null +++ b/mozilla/layout/html/forms/public/Makefile @@ -0,0 +1,29 @@ +#!gmake +# +# 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. + +DEPTH=../../../.. + +EXPORTS = \ + nsIFormControl.h \ + nsIFormManager.h \ + $(NULL) + +MODULE = raptor + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/layout/html/forms/public/makefile.win b/mozilla/layout/html/forms/public/makefile.win new file mode 100644 index 00000000000..7508fed5452 --- /dev/null +++ b/mozilla/layout/html/forms/public/makefile.win @@ -0,0 +1,26 @@ +#!nmake +# +# 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. + +DEPTH=..\..\..\.. +IGNORE_MANIFEST=1 + +EXPORTS=nsIFormControl.h nsIFormManager.h + +MODULE=raptor + +include <$(DEPTH)\config\rules.mak> + diff --git a/mozilla/layout/html/forms/public/nsIFormControl.h b/mozilla/layout/html/forms/public/nsIFormControl.h new file mode 100644 index 00000000000..88a24de8f0e --- /dev/null +++ b/mozilla/layout/html/forms/public/nsIFormControl.h @@ -0,0 +1,46 @@ +/* -*- 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. + */ +#ifndef nsIFormControl_h___ +#define nsIFormControl_h___ + +#include "nsISupports.h" +class nsIFormManager; + +#define NS_IFORMCONTROL_IID \ +{ 0x282ff440, 0xcd7e, 0x11d1, \ + {0x89, 0xad, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } + +class nsIFormControl : public nsISupports { +public: + virtual PRBool GetName(nsString& aResult) = 0; + + virtual PRInt32 GetMaxNumValues() = 0; + + virtual PRBool GetValues(PRInt32 aMaxNumValues, PRInt32& aNumValues, + nsString* aValues) = 0; + + virtual void Reset() = 0; + + virtual nsIFormManager* GetFormManager() const = 0; + + virtual void SetFormManager(nsIFormManager* aFormMan, PRBool aDecrementRef = PR_TRUE) = 0; + + virtual nsrefcnt GetRefCount() const = 0; +}; + +#endif /* nsIFormControl_h___ */ diff --git a/mozilla/layout/html/forms/public/nsIFormManager.h b/mozilla/layout/html/forms/public/nsIFormManager.h new file mode 100644 index 00000000000..667356316f5 --- /dev/null +++ b/mozilla/layout/html/forms/public/nsIFormManager.h @@ -0,0 +1,70 @@ +/* -*- 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. + */ +#ifndef nsIFormManager_h___ +#define nsIFormManager_h___ + +#include "nsISupports.h" +class nsIFormControl; + +// IID for the nsIFormManager interface +#define NS_IFORMMANAGER_IID \ +{ 0x592daa01, 0xcb23, 0x11d1, \ + { 0x80, 0x2d, 0x0, 0x60, 0x8, 0x15, 0xa7, 0x91 } } + +/** + * Abstract form manager interface. Form managers are responsible for + * the management of form controls. This includes gathering of data + * for form submission; resetting form controls to their initial state + * and other programmatic control during form processing. + */ +class nsIFormManager : public nsISupports { +public: + // callback for reset button controls. + virtual void OnReset() = 0; + + // callback for text and textarea controls. If there is a single + // text/textarea and a return is entered, then this is equavalent to + // a submit. + virtual void OnReturn() = 0; + + // callback for submit button controls. + virtual void OnSubmit() = 0; + + // callback for tabs on controls that can gain focus. This will + // eventually need to be handled at the document level to support + // the tabindex attribute. + virtual void OnTab() = 0; + + virtual PRInt32 GetFormControlCount() const = 0; + + virtual nsIFormControl* GetFormControlAt(PRInt32 aIndex) const = 0; + + virtual PRBool AddFormControl(nsIFormControl* aFormControl) = 0; + + virtual PRBool RemoveFormControl(nsIFormControl* aFormControl, + PRBool aChildIsRef = PR_TRUE) = 0; + + virtual void SetAttribute(const nsString& aName, const nsString& aValue) = 0; + + virtual PRBool GetAttribute(const nsString& aName, + nsString& aResult) const = 0; + + virtual nsrefcnt GetRefCount() const = 0; +}; + +#endif /* nsIFormManager_h___ */ diff --git a/mozilla/layout/html/forms/src/Makefile b/mozilla/layout/html/forms/src/Makefile new file mode 100644 index 00000000000..682ef1fe3eb --- /dev/null +++ b/mozilla/layout/html/forms/src/Makefile @@ -0,0 +1,48 @@ +#!gmake +# +# 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. + +DEPTH=../../../.. + +include $(DEPTH)/config/config.mk + +LIBRARY_NAME = raptorhtmlforms_s + +LCFLAGS += -D_IMPL_NS_HTML + +# Note the sophisticated alphabetical ordering :-| +CPPSRCS = \ + nsForm.cpp \ + nsInput.cpp \ + nsInputButton.cpp \ + nsInputCheckbox.cpp \ + nsInputFile.cpp \ + nsInputFrame.cpp \ + nsInputHidden.cpp \ + nsInputImage.cpp \ + nsInputPassword.cpp \ + nsInputRadio.cpp \ + nsInputText.cpp \ + $(NULL) + +MODULE = raptor + +INCLUDES += -I../../base/src -I../../style/src + +REQUIRES = xpcom raptor dom + +include $(DEPTH)/config/rules.mk + diff --git a/mozilla/layout/html/forms/src/makefile.win b/mozilla/layout/html/forms/src/makefile.win new file mode 100644 index 00000000000..40f96792c7d --- /dev/null +++ b/mozilla/layout/html/forms/src/makefile.win @@ -0,0 +1,52 @@ +#!nmake +# +# 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. + +DEPTH=..\..\..\.. +IGNORE_MANIFEST=1 + +LIBRARY_NAME=raptorhtmlforms_s + +DEFINES=-D_IMPL_NS_HTML -I..\..\base\src -I..\..\style\src \ + -I$(PUBLIC)\dom +MODULE=raptor +REQUIRES=xpcom raptor + +CPPSRCS=nsForm.cpp nsInput.cpp nsInputButton.cpp nsInputCheckbox.cpp \ + nsInputFile.cpp nsInputFrame.cpp nsInputHidden.cpp nsInputImage.cpp \ + nsInputPassword.cpp nsInputRadio.cpp nsInputText.cpp + +CPP_OBJS=.\$(OBJDIR)\nsForm.obj .\$(OBJDIR)\nsInput.obj \ + .\$(OBJDIR)\nsInputButton.obj .\$(OBJDIR)\nsInputCheckbox.obj \ + .\$(OBJDIR)\nsInputFile.obj .\$(OBJDIR)\nsInputFrame.obj \ + .\$(OBJDIR)\nsInputHidden.obj .\$(OBJDIR)\nsInputImage.obj \ + .\$(OBJDIR)\nsInputPassword.obj .\$(OBJDIR)\nsInputRadio.obj \ + .\$(OBJDIR)\nsInputText.obj + +LINCS=-I$(XPDIST)\public\xpcom -I$(XPDIST)\public\raptor + +LCFLAGS = \ + $(LCFLAGS) \ + $(DEFINES) \ + $(NULL) + +include <$(DEPTH)\config\rules.mak> + +libs:: $(LIBRARY) + $(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib + +clobber:: + rm -f $(DIST)\lib\$(LIBRARY_NAME).lib diff --git a/mozilla/layout/html/forms/src/nsForm.cpp b/mozilla/layout/html/forms/src/nsForm.cpp new file mode 100644 index 00000000000..ef82b8db1cd --- /dev/null +++ b/mozilla/layout/html/forms/src/nsForm.cpp @@ -0,0 +1,410 @@ +/* -*- 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 "nsHTMLForms.h" +#include "nsIFormManager.h" +#include "nsIFormControl.h" +#include "nsIAtom.h" +#include "nsHTMLIIDs.h" +#include "nsIRenderingContext.h" +#include "nsIPresShell.h" +#include "nsIPresContext.h" +#include "nsIStyleContext.h" +#include "nsLeafFrame.h" +#include "nsCSSRendering.h" +#include "nsHTMLIIDs.h" +#include "nsDebug.h" +#include "nsIWidget.h" +#include "nsVoidArray.h" +#include "nsHTMLAtoms.h" +#include "nsIHTMLAttributes.h" +#include "nsCRT.h" + +// netlib has a general function (netlib\modules\liburl\src\escape.c) +// which does url encoding. Since netlib is not yet available for raptor, +// the following will suffice. Convert space to +, don't convert alphanumeric, +// conver each non alphanumeric char to %XY where XY is the hexadecimal +// equavalent of the binary representation of the character. +// +void EscapeURLString(char* aInString, char* aOutString) +{ + if (nsnull == aInString) { + return; + } + static char *toHex = "0123456789ABCDEF"; + char* outChar = aOutString; + for (char* inChar = aInString; *inChar; inChar++) { + if(' ' == *inChar) { // convert space to + + *outChar++ = '+'; + } else if ( (((*inChar - '0') >= 0) && (('9' - *inChar) >= 0)) || // don't conver + (((*inChar - 'a') >= 0) && (('z' - *inChar) >= 0)) || // alphanumeric + (((*inChar - 'A') >= 0) && (('Z' - *inChar) >= 0)) ) { + *outChar++ = *inChar; + } else { // convert all else to hex + *outChar++ = '%'; + *outChar++ = toHex[(*inChar >> 4) & 0x0F]; + *outChar++ = toHex[*inChar & 0x0F]; + } + } + *outChar = 0; // terminate the string +} + +nsString* EscapeURLString(nsString& aString) +{ + char* inBuf = aString.ToNewCString(); + char* outBuf = new char[ (strlen(inBuf) * 3) + 1 ]; + EscapeURLString(inBuf, outBuf); + nsString* result = new nsString(outBuf); + delete [] outBuf; + delete [] inBuf; + return result; +} + + +//---------------------------------------------------------------------- + +static NS_DEFINE_IID(kIFormManagerIID, NS_IFORMMANAGER_IID); + +class nsForm : public nsIFormManager +{ +public: + // Construct a new Form Element with no attributes. This needs to be + // made private and have a static COM create method. + nsForm(nsIAtom* aTag); + ~nsForm(); + + void* operator new(size_t sz) { + void* rv = new char[sz]; + nsCRT::zero(rv, sz); + return rv; + } + + NS_DECL_ISUPPORTS + + // callback for reset button controls. + virtual void OnReset(); + + // callback for text and textarea controls. If there is a single + // text/textarea and a return is entered, then this is equavalent to + // a submit. + virtual void OnReturn(); + + // callback for submit button controls. + virtual void OnSubmit(); + + // callback for tabs on controls that can gain focus. This will + // eventually need to be handled at the document level to support + // the tabindex attribute. + virtual void OnTab(); + + virtual PRInt32 GetFormControlCount() const; + virtual nsIFormControl* GetFormControlAt(PRInt32 aIndex) const; + virtual PRBool AddFormControl(nsIFormControl* aFormControl); + virtual PRBool RemoveFormControl(nsIFormControl* aFormControl, + PRBool aChildIsRef = PR_TRUE); + + virtual void SetAttribute(const nsString& aName, const nsString& aValue); + + virtual PRBool GetAttribute(const nsString& aName, + nsString& aResult) const; + + virtual nsresult GetRefCount() const; + +protected: + nsIAtom* mTag; + nsIHTMLAttributes* mAttributes; + nsVoidArray mChildren; + nsString* mAction; + nsString* mEncoding; + nsString* mTarget; + PRInt32 mMethod; +}; + +#define METHOD_UNSET 0 +#define METHOD_GET 1 +#define METHOD_POST 2 + +// CLASS nsForm + +// Note: operator new zeros our memory +nsForm::nsForm(nsIAtom* aTag) +{ + NS_INIT_REFCNT(); + mTag = aTag; + NS_IF_ADDREF(aTag); +} + +nsForm::~nsForm() +{ + NS_IF_RELEASE(mTag); + int numChildren = GetFormControlCount(); + for (int i = 0; i < numChildren; i++) { + nsIFormControl* child = GetFormControlAt(i); + RemoveFormControl(child, PR_FALSE); + child->SetFormManager(nsnull, PR_FALSE); + NS_RELEASE(child); + } + if (nsnull != mAction) delete mAction; + if (nsnull != mEncoding) delete mEncoding; + if (nsnull != mTarget) delete mTarget; +} + +NS_IMPL_QUERY_INTERFACE(nsForm,kIFormManagerIID); +NS_IMPL_ADDREF(nsForm); + +nsrefcnt nsForm::GetRefCount() const +{ + return mRefCnt; +} + +nsrefcnt nsForm::Release() +{ + --mRefCnt; + int numChildren = GetFormControlCount(); + PRBool externalRefsToChildren = PR_FALSE; // are there refs to any children besides me + for (int i = 0; i < numChildren; i++) { + nsIFormControl* child = GetFormControlAt(i); + if (child->GetRefCount() > 1) { + externalRefsToChildren = PR_TRUE; + break; + } + } + if (!externalRefsToChildren && ((int)mRefCnt == numChildren)) { + mRefCnt = 0; + delete this; + return 0; + } + return mRefCnt; +} + +PRInt32 +nsForm::GetFormControlCount() const +{ + return mChildren.Count(); +} + +nsIFormControl* +nsForm::GetFormControlAt(PRInt32 aIndex) const +{ + nsIFormControl* ctl = (nsIFormControl*) mChildren.ElementAt(aIndex); + NS_IF_ADDREF(ctl); + return ctl; +} + +PRBool +nsForm::AddFormControl(nsIFormControl* aChild) +{ + PRBool rv = mChildren.AppendElement(aChild); + if (rv) { + NS_ADDREF(aChild); + } + return rv; +} + +PRBool +nsForm::RemoveFormControl(nsIFormControl* aChild, PRBool aChildIsRef) +{ + PRBool rv = mChildren.RemoveElement(aChild); + if (rv && aChildIsRef) { + NS_RELEASE(aChild); + } + return rv; +} + +void +nsForm::OnReset() +{ + PRInt32 numChildren = mChildren.Count(); + for (int childX = 0; childX < numChildren; childX++) { + nsIFormControl* child = (nsIFormControl*) mChildren.ElementAt(childX); + child->Reset(); + } +} + +void +nsForm::OnReturn() +{ +} + +void +nsForm::OnSubmit() +{ + nsString data(""); // this could be more efficient, by allocating a larger buffer + PRBool firstTime = PR_TRUE; + + PRInt32 numChildren = mChildren.Count(); + for (PRInt32 childX = 0; childX < numChildren; childX++) { + nsIFormControl* child = (nsIFormControl*) mChildren.ElementAt(childX); + nsString childName; + if (PR_TRUE == child->GetName(childName)) { + PRInt32 numValues = 0; + PRInt32 maxNumValues = child->GetMaxNumValues(); + if (maxNumValues <= 0) { + continue; + } + nsString* values = new nsString[maxNumValues]; + if (PR_TRUE == child->GetValues(maxNumValues, numValues, values)) { + for (int valueX = 0; valueX < numValues; valueX++) { + if (PR_TRUE == firstTime) { + firstTime = PR_FALSE; + } else { + data += "&"; + } + nsString* convName = EscapeURLString(childName); + data += *convName; + delete convName; + data += "="; + nsString* convValue = EscapeURLString(values[valueX]); + data += *convValue; + delete convValue; + } + } + delete [] values; + } + } + char* out = data.ToNewCString(); + printf("\nsubmit data =\n%s\n", out); + delete [] out; +} + +void +nsForm::OnTab() +{ +} + +void nsForm::SetAttribute(const nsString& aName, const nsString& aValue) +{ + nsAutoString tmp(aName); + tmp.ToUpperCase(); + nsIAtom* atom = NS_NewAtom(aName); + + if (atom == nsHTMLAtoms::action) { + nsAutoString url(aValue); + url.StripWhitespace(); + if (nsnull == mAction) { + mAction = new nsString(url); + } + else { + *mAction = url; + } + } + else if (atom == nsHTMLAtoms::encoding) { + if (nsnull == mEncoding) { + mEncoding = new nsString(aValue); + } + else { + *mEncoding = aValue; + } + } + else if (atom == nsHTMLAtoms::target) { + if (nsnull == mTarget) { + mTarget = new nsString(aValue); + } + else { + *mTarget = aValue; + } + } + else if (atom == nsHTMLAtoms::method) { + if (aValue.EqualsIgnoreCase("post")) { + mMethod = METHOD_POST; + } + else { + mMethod = METHOD_GET; + } + } + else { + // Use default storage for unknown attributes + if (nsnull == mAttributes) { + NS_NewHTMLAttributes(&mAttributes, nsnull); + } + if (nsnull != mAttributes) { + mAttributes->SetAttribute(atom, aValue); + } + } + NS_RELEASE(atom); +} + +PRBool nsForm::GetAttribute(const nsString& aName, + nsString& aResult) const +{ + nsAutoString tmp(aName); + tmp.ToUpperCase(); + nsIAtom* atom = NS_NewAtom(aName); + PRBool rv = PR_FALSE; + if (atom == nsHTMLAtoms::action) { + if (nsnull != mAction) { + aResult = *mAction; + rv = PR_TRUE; + } + } + else if (atom == nsHTMLAtoms::encoding) { + if (nsnull != mEncoding) { + aResult = *mEncoding; + rv = PR_TRUE; + } + } + else if (atom == nsHTMLAtoms::target) { + if (nsnull != mTarget) { + aResult = *mTarget; + rv = PR_TRUE; + } + } + else if (atom == nsHTMLAtoms::method) { + if (METHOD_UNSET != mMethod) { + if (METHOD_POST == mMethod) { + aResult = "post"; + } + else { + aResult = "get"; + } + rv = PR_TRUE; + } + } + else { + // Use default storage for unknown attributes + if (nsnull != mAttributes) { + nsHTMLValue value; + if (eContentAttr_HasValue == mAttributes->GetAttribute(atom, value)) { + if (value.GetUnit() == eHTMLUnit_String) { + value.GetStringValue(aResult); + rv = PR_TRUE; + } + } + } + } + + NS_RELEASE(atom); + return rv; +} + +nsresult +NS_NewHTMLForm(nsIFormManager** aInstancePtrResult, + nsIAtom* aTag) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + + nsForm* it = new nsForm(aTag); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + nsresult result = it->QueryInterface(kIFormManagerIID, (void**) aInstancePtrResult); + return result; +} diff --git a/mozilla/layout/html/forms/src/nsFormElement.cpp b/mozilla/layout/html/forms/src/nsFormElement.cpp new file mode 100644 index 00000000000..993ef5cf79b --- /dev/null +++ b/mozilla/layout/html/forms/src/nsFormElement.cpp @@ -0,0 +1,150 @@ +/* -*- 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 "nsHTMLParts.h" +#include "nsHTMLTagContent.h" +#include "nsIRenderingContext.h" +#include "nsIPresContext.h" +#include "nsIStyleContext.h" +#include "nsLeafFrame.h" +#include "nsCSSRendering.h" +#include "nsHTMLIIDs.h" + +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); + +enum FormElementType { + eFormElementType_Submit, + eFormElementType_Reset, + eFormElementType_Text, + eFormElementType_Password, + eFormElementType_TextArea, +}; + +class FormElementFrame : public nsLeafFrame { +public: + FormElementFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + +protected: + virtual ~FormElementFrame(); + virtual void GetDesiredSize(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize); +}; + +class FormElementContent : public nsHTMLTagContent { +public: + FormElementContent(nsIAtom* aTag, FormElementType aType); + + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + +protected: + virtual ~FormElementContent(); + + FormElementType mType; +}; + +//---------------------------------------------------------------------- + +FormElementFrame::FormElementFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsLeafFrame(aContent, aIndexInParent, aParentFrame) +{ +} + +FormElementFrame::~FormElementFrame() +{ +} + +// XXX it would be cool if form element used our rendering sw, then +// they could be blended, and bordered, and so on... +void FormElementFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + nsStyleMolecule* myMol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, + aDirtyRect, mRect, *myMol, 0); +} + +void FormElementFrame::GetDesiredSize(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize) +{ + float p2t = aPresContext->GetPixelsToTwips(); + aDesiredSize.width = nscoord(75 * p2t); + aDesiredSize.height = nscoord(37 * p2t); +} + +//---------------------------------------------------------------------- + +FormElementContent::FormElementContent(nsIAtom* aTag, FormElementType aType) + : nsHTMLTagContent(aTag), + mType(aType) +{ +} + +FormElementContent::~FormElementContent() +{ +} + +nsIFrame* FormElementContent::CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + nsIFrame* rv = new FormElementFrame(this, aIndexInParent, aParentFrame); + return rv; +} + +NS_HTML nsresult +NS_NewHTMLSubmitButton(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIHTMLContent* it = new FormElementContent(aTag, eFormElementType_Submit); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIHTMLContentIID, (void**) aInstancePtrResult); +} + +NS_HTML nsresult +NS_NewHTMLResetButton(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIHTMLContent* it = new FormElementContent(aTag, eFormElementType_Reset); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIHTMLContentIID, (void**) aInstancePtrResult); +} diff --git a/mozilla/layout/html/forms/src/nsHTMLForms.h b/mozilla/layout/html/forms/src/nsHTMLForms.h new file mode 100644 index 00000000000..56adb6b80b3 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsHTMLForms.h @@ -0,0 +1,71 @@ +/* -*- 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. + */ +#ifndef nsHTMLForms_h___ +#define nsHTMLForms_h___ + +#include "nsIHTMLContent.h" +class nsIAtom; +class nsIFormManager; + +// Form and Form Controls + +extern nsresult +NS_NewHTMLForm(nsIFormManager** aInstancePtrResult, + nsIAtom* aTag); + +extern nsresult +NS_NewHTMLInputButton(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag, nsIFormManager* aManager); + +extern nsresult +NS_NewHTMLInputReset(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag, nsIFormManager* aManager); + +extern nsresult +NS_NewHTMLInputSubmit(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag, nsIFormManager* aManager); + +extern nsresult +NS_NewHTMLInputCheckbox(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag, nsIFormManager* aManager); + +extern nsresult +NS_NewHTMLInputFile(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag, nsIFormManager* aManager); + +extern nsresult +NS_NewHTMLInputHidden(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag, nsIFormManager* aManager); + +extern nsresult +NS_NewHTMLInputImage(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag, nsIFormManager* aManager); + +extern nsresult +NS_NewHTMLInputPassword(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag, nsIFormManager* aManager); + +extern nsresult +NS_NewHTMLInputRadio(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag, nsIFormManager* aManager); + +extern nsresult +NS_NewHTMLInputText(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag, nsIFormManager* aManager); + +#endif /* nsHTMLForms_h___ */ diff --git a/mozilla/layout/html/forms/src/nsInput.cpp b/mozilla/layout/html/forms/src/nsInput.cpp new file mode 100644 index 00000000000..719ccab225a --- /dev/null +++ b/mozilla/layout/html/forms/src/nsInput.cpp @@ -0,0 +1,292 @@ +/* -*- 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 "nsInput.h" +#include "nsIFormManager.h" +#include "nsInputFrame.h" +#include "nsHTMLParts.h" +#include "nsHTMLTagContent.h" +#include "nsIRenderingContext.h" +#include "nsIPresShell.h" +#include "nsIPresContext.h" +#include "nsIStyleContext.h" +#include "nsLeafFrame.h" +#include "nsCSSRendering.h" +#include "nsHTMLIIDs.h" +#include "nsHTMLAtoms.h" +#include "nsIView.h" +#include "nsIViewManager.h" +#include "nsCoord.h" +#include "nsDebug.h" +#include "nsIWidget.h" + +// Note: we inherit a base class operator new that zeros our memory +nsInput::nsInput(nsIAtom* aTag, nsIFormManager* aManager) + : nsHTMLTagContent(aTag), mControl() +{ +printf("** nsInput::nsInput this=%d\n", this); + mFormMan = aManager; + if (nsnull != mFormMan) { + NS_ADDREF(mFormMan); + mFormMan->AddFormControl(&mControl); + } +} + +nsInput::~nsInput() +{ +printf("** nsInput::~nsInput()\n"); + NS_IF_RELEASE(mWidget); + if (nsnull != mName) { + delete mName; + } + if (nsnull != mFormMan) { + // prevent mFormMan from decrementing its ref count on us + mFormMan->RemoveFormControl(&mControl, PR_FALSE); + NS_RELEASE(mFormMan); + } +} + +static NS_DEFINE_IID(kIFormControlIID, NS_IFORMCONTROL_IID); + +nsresult nsInput::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if (aIID.Equals(kIFormControlIID)) { + AddRef(); + *aInstancePtr = (void**) &mControl; + return NS_OK; + } + return nsHTMLTagContent::QueryInterface(aIID, aInstancePtr); +} + +nsrefcnt nsInput::Release() +{ + --mRefCnt; + int debugRefCnt = mRefCnt; + if (mRefCnt == 0) { + delete this; + return 0; + } + if ((mFormMan == nsnull) || (mRefCnt > 1)) { + return mRefCnt; + } + + int numSiblings = mFormMan->GetFormControlCount(); + PRBool externalRefs = PR_FALSE; // are there external refs to dad or any siblings + if ((int)mFormMan->GetRefCount() > numSiblings) { + externalRefs = PR_TRUE; + } else { + for (int i = 0; i < numSiblings; i++) { + nsIFormControl* sibling = mFormMan->GetFormControlAt(i); + if (sibling->GetRefCount() > 1) { + externalRefs = PR_TRUE; + break; + } + } + } + + if (!externalRefs) { + mRefCnt = 0; + delete this; + return 0; + } + + return mRefCnt; +} + + +nsIFrame* +nsInput::CreateFrame(nsIPresContext *aPresContext, + PRInt32 aIndexInParent, + nsIFrame *aParentFrame) +{ + NS_ASSERTION(0, "frames must be created by subclasses of Input"); + return nsnull; +} + +void +nsInput::SetWidget(nsIWidget* aWidget) +{ + if (aWidget != mWidget) { + NS_IF_RELEASE(mWidget); + NS_IF_ADDREF(aWidget); + mWidget = aWidget; + } +} + +nsrefcnt nsInput::GetRefCount() const +{ + return mRefCnt; +} + +// this is for internal use and does not do an AddRef +nsIWidget* +nsInput::GetWidget() +{ + return mWidget; +} + +void +nsInput::SetFormManager(nsIFormManager* aFormMan, PRBool aDecrementRef) +{ + if (aDecrementRef) { + NS_IF_RELEASE(mFormMan); + } + mFormMan = aFormMan; + NS_IF_ADDREF(aFormMan); +} + +nsIFormManager* +nsInput::GetFormManager() const +{ + NS_IF_ADDREF(mFormMan); + return mFormMan; +} + +/** + * Get the name associated with this form element. If there is no name + * then return PR_FALSE (form elements without names are not submitable). + */ +PRBool +nsInput::GetName(nsString& aName) +{ + if ((nsnull != mName) && (0 != mName->Length())) { + aName = *mName; + return PR_TRUE; + } + return PR_FALSE; +} + +void +nsInput::Reset() +{ +} + +PRInt32 +nsInput::GetMaxNumValues() +{ + return 0; +} + +PRBool +nsInput::GetValues(PRInt32 aMaxNumValues, PRInt32& aNumValues, nsString* aValues) +{ + aNumValues = 0; + return PR_FALSE; +} + +void nsInput::SetAttribute(nsIAtom* aAttribute, const nsString& aValue) +{ + if (aAttribute == nsHTMLAtoms::type) { + // You cannot set the type of a form element + return; + } + else if (aAttribute == nsHTMLAtoms::name) { + if (nsnull == mName) { + mName = new nsString(aValue); + } else { + mName->SetLength(0); + mName->Append(aValue); + } + } +} + +nsContentAttr nsInput::GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aValue) const +{ + nsContentAttr ca = eContentAttr_NotThere; + if (aAttribute == nsHTMLAtoms::type) { + nsAutoString tmp; + GetType(tmp); + aValue.Set(tmp); + ca = eContentAttr_HasValue; + } + else if (aAttribute == nsHTMLAtoms::name) { + aValue.Reset(); + if (nsnull != mName) { + aValue.Set(*mName); + ca = eContentAttr_HasValue; + } + } + else { + ca = nsHTMLTagContent::GetAttribute(aAttribute, aValue); + } + return ca; +} + +//---------------------------------------------------------------------- + +#define GET_OUTER() ((nsInput*) ((char*)this - nsInput::GetOuterOffset())) + +nsInput::AggInputControl::AggInputControl() +{ +} + +nsInput::AggInputControl::~AggInputControl() +{ +} + +nsrefcnt nsInput::AggInputControl::AddRef() +{ + return GET_OUTER()->AddRef(); +} + +nsrefcnt nsInput::AggInputControl::Release() +{ + return GET_OUTER()->Release(); +} + +nsresult nsInput::AggInputControl::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + return GET_OUTER()->QueryInterface(aIID, aInstancePtr); +} + +PRBool nsInput::AggInputControl::GetName(nsString& aName) +{ + return GET_OUTER()->GetName(aName); +} + +PRInt32 nsInput::AggInputControl::GetMaxNumValues() +{ + return GET_OUTER()->GetMaxNumValues(); +} + +PRBool nsInput::AggInputControl::GetValues(PRInt32 aMaxNumValues, + PRInt32& aNumValues, + nsString* aValues) +{ + return GET_OUTER()->GetValues(aMaxNumValues, aNumValues, aValues); +} + +void nsInput::AggInputControl::Reset() +{ + GET_OUTER()->Reset(); +} + +void nsInput::AggInputControl::SetFormManager(nsIFormManager* aFormMan, PRBool aDecrementRef) +{ + GET_OUTER()->SetFormManager(aFormMan, aDecrementRef); +} + +nsIFormManager* nsInput::AggInputControl::GetFormManager() const +{ + return GET_OUTER()->GetFormManager(); +} + +nsrefcnt nsInput::AggInputControl::GetRefCount() const +{ + return GET_OUTER()->GetRefCount(); +} diff --git a/mozilla/layout/html/forms/src/nsInput.h b/mozilla/layout/html/forms/src/nsInput.h new file mode 100644 index 00000000000..a576277e1f8 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsInput.h @@ -0,0 +1,110 @@ +/* -*- 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. + */ + +#ifndef nsInput_h___ +#define nsInput_h___ + +#include "nsHTMLTagContent.h" +#include "nsIFormControl.h" +class nsIFormManager; +class nsIWidget; +class nsIView; +class nsString; + +/** + * nsInput represents an html Input element. This is a base class for + * the various Input types (button, checkbox, file, hidden, password, + * reset, radio, submit, text) + */ +class nsInput : public nsHTMLTagContent { +public: + nsInput(nsIAtom* aTag, nsIFormManager* aManager); + + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); + + NS_IMETHOD_(nsrefcnt) Release(void); + + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void SetAttribute(nsIAtom* aAttribute, const nsString& aValue); + + virtual nsContentAttr GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aValue) const; + + // nsIFormControl + virtual PRBool GetName(nsString& aName); + virtual PRInt32 GetMaxNumValues(); + virtual PRBool GetValues(PRInt32 aMaxNumValues, PRInt32& aNumValues, + nsString* aValues); + virtual void Reset(); + virtual void SetFormManager(nsIFormManager* aFormMan, PRBool aDecrementRef = PR_TRUE); + virtual nsIFormManager* GetFormManager() const; + + static nsIView* GetAncestorWithWindow(nsIView* aView); + + void SetWidget(nsIWidget* aWidget); + + nsIWidget* GetWidget(); + + static PRInt32 GetOuterOffset() { + return offsetof(nsInput,mControl); + } + + virtual nsrefcnt GetRefCount() const; + +protected: + virtual ~nsInput(); + + /* + * Get the type of this input object + */ + virtual void GetType(nsString& aResult) const = 0; + + nsIWidget* mWidget; + nsIFormManager* mFormMan; + + // Attributes common to all html form elements + nsString* mName; + + // Aggregator class and instance variable used to aggregate in the + // nsIFormControl interface to nsInput w/o using multiple + // inheritance. + class AggInputControl : public nsIFormControl { + public: + AggInputControl(); + ~AggInputControl(); + + // nsISupports + NS_DECL_ISUPPORTS + + // nsIFormControl + virtual PRBool GetName(nsString& aName); + virtual PRInt32 GetMaxNumValues(); + virtual PRBool GetValues(PRInt32 aMaxNumValues, PRInt32& aNumValues, + nsString* aValues); + virtual void Reset(); + virtual void SetFormManager(nsIFormManager* aFormMan, PRBool aDecrementRef = PR_TRUE); + virtual nsIFormManager* GetFormManager() const; + virtual nsrefcnt GetRefCount() const; + }; + AggInputControl mControl; +}; + +#endif diff --git a/mozilla/layout/html/forms/src/nsInputButton.cpp b/mozilla/layout/html/forms/src/nsInputButton.cpp new file mode 100644 index 00000000000..4172444a910 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsInputButton.cpp @@ -0,0 +1,393 @@ +/* -*- 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 "nsInput.h" +#include "nsInputFrame.h" +#include "nsHTMLParts.h" +#include "nsHTMLTagContent.h" +#include "nsIRenderingContext.h" +#include "nsIPresContext.h" +#include "nsIPresShell.h" +#include "nsIStyleContext.h" +#include "nsLeafFrame.h" +#include "nsCSSRendering.h" +#include "nsHTMLIIDs.h" +#include "nsIButton.h" +#include "nsIViewManager.h" +#include "nsISupports.h" +#include "nsHTMLAtoms.h" +#include "nsIButton.h" +#include "nsIView.h" +#include "nsViewsCID.h" +#include "nsWidgetsCID.h" +#include "nsIDeviceContext.h" +#include "nsIFontCache.h" +#include "nsIFontMetrics.h" +#include "nsIFormManager.h" + +static NS_DEFINE_IID(kStyleFontSID, NS_STYLEFONT_SID); + +enum nsInputButtonType { + kInputButtonButton, + kInputButtonReset, + kInputButtonSubmit +}; + +class nsInputButton : public nsInput { +public: + nsInputButton (nsIAtom* aTag, nsIFormManager* aManager, + nsInputButtonType aType); + + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void SetAttribute(nsIAtom* aAttribute, const nsString& aValue); + + virtual nsContentAttr GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aResult) const; + + virtual void GetDefaultLabel(nsString& aLabel); + + nsInputButtonType GetButtonType() { return mType; } + + virtual PRInt32 GetMaxNumValues(); + + virtual PRBool GetValues(PRInt32 aMaxNumValues, PRInt32& aNumValues, nsString* aValues); + + // Attributes + nsString* mValue; + nscoord mWidth; + nscoord mHeight; + + protected: + virtual ~nsInputButton(); + + virtual void GetType(nsString& aResult) const; + + nsInputButtonType mType; +}; + +class nsInputButtonFrame : public nsInputFrame { +public: + nsInputButtonFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void PreInitializeWidget(nsIPresContext* aPresContext, + nsSize& aBounds); + + virtual void InitializeWidget(nsIView* aView); + + virtual void MouseClicked(); + + virtual const nsIID GetCID(); + + virtual const nsIID GetIID(); + + +protected: + virtual ~nsInputButtonFrame(); + nsString mCacheLabel; + nsFont* mCacheFont; // XXX this is bad, the lifetime of the font is not known or controlled +}; + + +// nsInputButton Implementation + +nsInputButton::nsInputButton(nsIAtom* aTag, nsIFormManager* aManager, + nsInputButtonType aType) + : nsInput(aTag, aManager), mType(aType) +{ + mWidth = -1; + mHeight = -1; +} + +nsInputButton::~nsInputButton() +{ + if (nsnull != mValue) { + delete mValue; + } +} + + +void nsInputButton::SetAttribute(nsIAtom* aAttribute, const nsString& aValue) +{ + if (aAttribute == nsHTMLAtoms::value) { + if (nsnull == mValue) { + mValue = new nsString(aValue); + } else { + mValue->SetLength(0); + mValue->Append(aValue); + } + } + else if (aAttribute == nsHTMLAtoms::width) { + nsHTMLValue value; + ParseValue(aValue, 0, 1000, value); + mWidth = value.GetIntValue(); + } + else if (aAttribute == nsHTMLAtoms::height) { + nsHTMLValue value; + ParseValue(aValue, 0, 1000, value); + mHeight = value.GetIntValue(); + } + else { + nsInput::SetAttribute(aAttribute, aValue); + } +} + +nsContentAttr nsInputButton::GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aResult) const +{ + nsContentAttr ca = eContentAttr_NotThere; + aResult.Reset(); + if (aAttribute == nsHTMLAtoms::value) { + if (nsnull != mValue) { + aResult.Set(*mValue); + ca = eContentAttr_HasValue; + } + } + else if (aAttribute == nsHTMLAtoms::width) { + if (0 <= mWidth) { + aResult.Set(mWidth, eHTMLUnit_Absolute); + ca = eContentAttr_HasValue; + } + } + else if (aAttribute == nsHTMLAtoms::height) { + if (0 <= mHeight) { + aResult.Set(mHeight, eHTMLUnit_Absolute); + ca = eContentAttr_HasValue; + } + } + else { + ca = nsInput::GetAttribute(aAttribute, aResult); + } + return ca; +} + +void nsInputButton::GetType(nsString& aResult) const +{ + aResult.SetLength(0); + switch (mType) { + case kInputButtonButton: + aResult.Append("button"); + break; + case kInputButtonReset: + aResult.Append("reset"); + break; + default: + case kInputButtonSubmit: + aResult.Append("submit"); + break; + } +} + +void +nsInputButton::GetDefaultLabel(nsString& aString) +{ + if (kInputButtonReset == mType) { + aString = "Reset"; + } else if (kInputButtonSubmit == mType) { + aString = "Submit"; + } else { + aString = "noname"; + } +} + +nsIFrame* +nsInputButton::CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + nsIFrame* rv = new nsInputButtonFrame(this, aIndexInParent, aParentFrame); + return rv; +} + +PRInt32 +nsInputButton::GetMaxNumValues() +{ + if (kInputButtonSubmit == mType) { + return 1; + } else { + return 0; + } +} + + +PRBool +nsInputButton::GetValues(PRInt32 aMaxNumValues, PRInt32& aNumValues, + nsString* aValues) +{ + if (aMaxNumValues <= 0) { + return PR_FALSE; + } + + if (kInputButtonSubmit != mType) { + aNumValues = 0; + return PR_FALSE; + } + + if (nsnull != mValue) { + aValues[0].SetLength(0); + aValues[0].Append(*mValue); + aNumValues = 1; + return PR_TRUE; + } else { + aNumValues = 0; + return PR_FALSE; + } +} + +//---------------------------------------------------------------------- +// nsInputButtonFrame Implementation + +nsInputButtonFrame::nsInputButtonFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsInputFrame(aContent, aIndexInParent, aParentFrame) +{ + mCacheLabel = ""; + mCacheFont = nsnull; +} + +nsInputButtonFrame::~nsInputButtonFrame() +{ + mCacheLabel = ""; + mCacheFont = nsnull; // should this be released? NO +} + +void +nsInputButtonFrame::MouseClicked() +{ + nsInputButton* button = (nsInputButton *) GetContent(); + nsIFormManager* formMan = button->GetFormManager(); + if (nsnull != formMan) { + if (kInputButtonReset == button->GetButtonType()) { + formMan->OnReset(); + } else if (kInputButtonSubmit == button->GetButtonType()) { + formMan->OnSubmit(); + } + NS_RELEASE(formMan); + } + NS_RELEASE(button); +} + + +void +nsInputButtonFrame::PreInitializeWidget(nsIPresContext* aPresContext, nsSize& aBounds) +{ + float p2t = aPresContext->GetPixelsToTwips(); + + nsInputButton* content = (nsInputButton *)GetContent(); // this must be an nsInputButton + nsIStyleContext* styleContext = GetStyleContext(aPresContext); + // should this be the parent + nsStyleFont* styleFont = (nsStyleFont*)styleContext->GetData(kStyleFontSID); + nsIDeviceContext* deviceContext = aPresContext->GetDeviceContext(); + nsIFontCache* fontCache = deviceContext->GetFontCache(); + + // get the label for the button + nsAutoString label; + if (nsnull == content->mValue) { + content->GetDefaultLabel(label); + } else { + label.Append(*content->mValue); + } + mCacheLabel = label; // cache the label + + // get the width and height based on the label, font, padding + nsIFontMetrics* fontMet = fontCache->GetMetricsFor(styleFont->mFont); + nscoord horPadding = (int) (5.0 * p2t); // need to get this from the widget + nscoord verPadding = (int) (5.0 * p2t); // need to get this from the widget + aBounds.width = fontMet->GetWidth(label) + (2 * horPadding); + aBounds.height = fontMet->GetHeight() + (2 * verPadding); + + mCacheFont = &(styleFont->mFont); // cache the font XXX this is bad, the lifetime of the font is not known or controlled + + NS_RELEASE(fontMet); + NS_RELEASE(fontCache); + NS_RELEASE(deviceContext); + NS_RELEASE(styleContext); + NS_RELEASE(content); +} + + +void +nsInputButtonFrame::InitializeWidget(nsIView *aView) +{ + nsIButton* button; + if (NS_OK == GetWidget(aView, (nsIWidget **)&button)) { + if (nsnull != mCacheFont) { + button->SetFont(*mCacheFont); + } + button->SetLabel(mCacheLabel); + NS_RELEASE(button); + } +} + +const nsIID +nsInputButtonFrame::GetIID() +{ + static NS_DEFINE_IID(kButtonIID, NS_IBUTTON_IID); + return kButtonIID; +} + +const nsIID +nsInputButtonFrame::GetCID() +{ + static NS_DEFINE_IID(kButtonCID, NS_BUTTON_CID); + return kButtonCID; +} + +nsresult +CreateButton(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag, nsIFormManager* aManager, + nsInputButtonType aType) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + + nsIHTMLContent* it = new nsInputButton(aTag, aManager, aType); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIHTMLContentIID, (void**) aInstancePtrResult); +} + +nsresult +NS_NewHTMLInputButton(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag, nsIFormManager* aManager) +{ + return CreateButton(aInstancePtrResult, aTag, aManager, kInputButtonButton); +} + +nsresult +NS_NewHTMLInputSubmit(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag, nsIFormManager* aManager) +{ + return CreateButton(aInstancePtrResult, aTag, aManager, kInputButtonSubmit); +} + +nsresult +NS_NewHTMLInputReset(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag, nsIFormManager* aManager) +{ + return CreateButton(aInstancePtrResult, aTag, aManager, kInputButtonReset); +} diff --git a/mozilla/layout/html/forms/src/nsInputCheckbox.cpp b/mozilla/layout/html/forms/src/nsInputCheckbox.cpp new file mode 100644 index 00000000000..1f289be8049 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsInputCheckbox.cpp @@ -0,0 +1,251 @@ +/* -*- 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 "nsInputCheckbox.h" +#include "nsICheckButton.h" +#include "nsInputFrame.h" +#include "nsIContent.h" +#include "prtypes.h" +#include "nsIFrame.h" +#include "nsISupports.h" +#include "nsIAtom.h" +#include "nsIPresContext.h" +#include "nsIHTMLContent.h" +#include "nsHTMLIIDs.h" +#include "nsWidgetsCID.h" +#include "nsIView.h" +#include "nsHTMLAtoms.h" + +class nsInputCheckboxFrame : public nsInputFrame { +public: + nsInputCheckboxFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void PreInitializeWidget(nsIPresContext* aPresContext, + nsSize& aBounds); + + virtual void InitializeWidget(nsIView *aView); + + virtual const nsIID GetCID(); + + virtual const nsIID GetIID(); + + virtual void MouseClicked(); + +protected: + virtual ~nsInputCheckboxFrame(); + PRBool mCacheState; +}; + +nsInputCheckboxFrame::nsInputCheckboxFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsInputFrame(aContent, aIndexInParent, aParentFrame) +{ +} + +nsInputCheckboxFrame::~nsInputCheckboxFrame() +{ + mCacheState = PR_FALSE; +} + + +const nsIID +nsInputCheckboxFrame::GetIID() +{ + static NS_DEFINE_IID(kCheckboxIID, NS_ICHECKBUTTON_IID); + return kCheckboxIID; +} + +const nsIID +nsInputCheckboxFrame::GetCID() +{ + static NS_DEFINE_IID(kCheckboxCID, NS_CHECKBUTTON_CID); + return kCheckboxCID; +} + +void +nsInputCheckboxFrame::PreInitializeWidget(nsIPresContext* aPresContext, + nsSize& aBounds) +{ + nsInputCheckbox* content = (nsInputCheckbox *)GetContent(); // this must be an nsCheckbox + + // get the state + nsHTMLValue value; + nsContentAttr result = content->GetAttribute(nsHTMLAtoms::checked, value); + if (result != eContentAttr_NotThere) { + mCacheState = PR_TRUE;/* XXX why cache state? */ + } + NS_RELEASE(content); + + float p2t = aPresContext->GetPixelsToTwips(); + aBounds.width = (int)(13 * p2t); + aBounds.height = (int)(13 * p2t); +} + +void +nsInputCheckboxFrame::InitializeWidget(nsIView *aView) +{ + nsICheckButton* checkbox; + if (NS_OK == GetWidget(aView, (nsIWidget **)&checkbox)) { + checkbox->SetState(mCacheState); + NS_RELEASE(checkbox); + } +} + +void +nsInputCheckboxFrame::MouseClicked() +{ + nsICheckButton* checkbox; + nsIView* view = GetView(); + if (NS_OK == GetWidget(view, (nsIWidget **)&checkbox)) { + PRBool newState = (checkbox->GetState()) ? PR_FALSE : PR_TRUE; + checkbox->SetState(newState); + NS_RELEASE(checkbox); + } + NS_RELEASE(view); +} + + + +// nsInputCheckbox + +nsInputCheckbox::nsInputCheckbox(nsIAtom* aTag, nsIFormManager* aManager) + : nsInput(aTag, aManager) +{ +} + +nsInputCheckbox::~nsInputCheckbox() +{ + if (nsnull != mValue) { + delete mValue; + } +} + + +PRInt32 +nsInputCheckbox::GetMaxNumValues() +{ + return 1; +} + + +PRBool +nsInputCheckbox::GetValues(PRInt32 aMaxNumValues, PRInt32& aNumValues, + nsString* aValues) +{ + if (aMaxNumValues <= 0) { + return PR_FALSE; + } + nsICheckButton* checkBox = (nsICheckButton *)GetWidget(); + PRBool state = checkBox->GetState(); + if(PR_TRUE != state) { + return PR_FALSE; + } + + if (nsnull == mValue) { + aValues[0] = "on"; + } else { + aValues[0] = *mValue; + } + aNumValues = 1; + + return PR_TRUE; +} + +void +nsInputCheckbox::Reset() +{ + nsICheckButton* checkbox = (nsICheckButton *)GetWidget(); + if (nsnull != checkbox) { + checkbox->SetState(mInitialChecked); + } +} + +nsIFrame* +nsInputCheckbox::CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + nsIFrame* rv = new nsInputCheckboxFrame(this, aIndexInParent, aParentFrame); + return rv; +} + +void nsInputCheckbox::GetType(nsString& aResult) const +{ + aResult = "checkbox"; +} + +void nsInputCheckbox::SetAttribute(nsIAtom* aAttribute, + const nsString& aValue) +{ + if (aAttribute == nsHTMLAtoms::checked) { + mInitialChecked = PR_TRUE; + } + else if (aAttribute == nsHTMLAtoms::value) { + if (nsnull == mValue) { + mValue = new nsString(aValue); + } else { + *mValue = aValue; + } + } + else { + nsInput::SetAttribute(aAttribute, aValue); + } +} + +nsContentAttr nsInputCheckbox::GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aResult) const +{ + nsContentAttr ca = eContentAttr_NotThere; + aResult.Reset(); + if (aAttribute == nsHTMLAtoms::checked) { + if (mInitialChecked) { + ca = eContentAttr_HasValue; + } + } + else if (aAttribute == nsHTMLAtoms::value) { + if (nsnull != mValue) { + aResult.Set(*mValue); + ca = eContentAttr_HasValue; + } + } + else { + ca = nsInput::GetAttribute(aAttribute, aResult); + } + return ca; +} + +NS_HTML nsresult +NS_NewHTMLInputCheckbox(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag, nsIFormManager* aManager) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + + nsIHTMLContent* it = new nsInputCheckbox(aTag, aManager); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIHTMLContentIID, (void**) aInstancePtrResult); +} + diff --git a/mozilla/layout/html/forms/src/nsInputCheckbox.h b/mozilla/layout/html/forms/src/nsInputCheckbox.h new file mode 100644 index 00000000000..5fc5da0a34a --- /dev/null +++ b/mozilla/layout/html/forms/src/nsInputCheckbox.h @@ -0,0 +1,55 @@ +/* -*- 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. + */ + +#ifndef nsInputCheckbox_h___ +#define nsInputCheckbox_h___ + +#include "nsInput.h" +class nsIAtom; +class nsString; + +class nsInputCheckbox : public nsInput { +public: + nsInputCheckbox (nsIAtom* aTag, nsIFormManager* aManager); + + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void SetAttribute(nsIAtom* aAttribute, const nsString& aValue); + + virtual nsContentAttr GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aResult) const; + + virtual PRInt32 GetMaxNumValues(); + + virtual PRBool GetValues(PRInt32 aMaxNumValues, PRInt32& aNumValues, + nsString* aValues); + + virtual void Reset(); + +protected: + virtual ~nsInputCheckbox(); + + virtual void GetType(nsString& aResult) const; + + nsString* mValue; + PRBool mInitialChecked; // initial checked flag value +}; + +#endif diff --git a/mozilla/layout/html/forms/src/nsInputFile.cpp b/mozilla/layout/html/forms/src/nsInputFile.cpp new file mode 100644 index 00000000000..721532f754e --- /dev/null +++ b/mozilla/layout/html/forms/src/nsInputFile.cpp @@ -0,0 +1,158 @@ +/* -*- 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 "nsInputFile.h" +#include "nsInputFrame.h" +#include "nsIContent.h" +#include "prtypes.h" +#include "nsIFrame.h" +#include "nsISupports.h" +#include "nsIAtom.h" +#include "nsIPresContext.h" +#include "nsIHTMLContent.h" +#include "nsHTMLIIDs.h" +#include "nsHTMLAtoms.h" + +class nsInputFileFrame : public nsInputFrame { +public: + nsInputFileFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void InitializeWidget(nsIView *aView); + +protected: + virtual ~nsInputFileFrame(); +}; + +nsInputFileFrame::nsInputFileFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsInputFrame(aContent, aIndexInParent, aParentFrame) +{ +} + +nsInputFileFrame::~nsInputFileFrame() +{ +} + + +void +nsInputFileFrame::InitializeWidget(nsIView *aView) +{ +} + +//---------------------------------------------------------------------- +// nsInputFile + +nsInputFile::nsInputFile(nsIAtom* aTag, nsIFormManager* aManager) + : nsInput(aTag, aManager) +{ +} + +nsInputFile::~nsInputFile() +{ + if (nsnull != mValue) { + delete mValue; + } +} + +nsIFrame* +nsInputFile::CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + nsIFrame* rv = new nsInputFileFrame(this, aIndexInParent, aParentFrame); + return rv; +} + +void nsInputFile::GetType(nsString& aResult) const +{ + aResult = "file"; +} + +void nsInputFile::SetAttribute(nsIAtom* aAttribute, const nsString& aValue) +{ + if (aAttribute == nsHTMLAtoms::size) { + nsHTMLValue value; + ParseValue(aValue, 1, value); + mSize = value.GetIntValue(); + } + else if (aAttribute == nsHTMLAtoms::maxlength) { + nsHTMLValue value; + ParseValue(aValue, 1, value);/* XXX nav doesn't clamp; what does it do with illegal values? */ + mMaxLength = value.GetIntValue(); + } + else if (aAttribute == nsHTMLAtoms::value) { + if (nsnull == mValue) { + mValue = new nsString(aValue); + } else { + *mValue = aValue; + } + } + else { + nsInput::SetAttribute(aAttribute, aValue); + } +} + +nsContentAttr nsInputFile::GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aResult) const +{ + nsContentAttr ca = eContentAttr_NotThere; + aResult.Reset(); + if (aAttribute == nsHTMLAtoms::size) { + if (0 < mSize) { + aResult.Set(mSize, eHTMLUnit_Absolute); + ca = eContentAttr_HasValue; + } + } + else if (aAttribute == nsHTMLAtoms::maxlength) { + if (0 < mMaxLength) { + aResult.Set(mMaxLength, eHTMLUnit_Absolute); + ca = eContentAttr_HasValue; + } + } + else if (aAttribute == nsHTMLAtoms::value) { + if (nsnull != mValue) { + aResult.Set(*mValue); + ca = eContentAttr_HasValue; + } + } + else { + ca = nsInput::GetAttribute(aAttribute, aResult); + } + return ca; +} + +NS_HTML nsresult +NS_NewHTMLInputFile(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag, nsIFormManager* aManager) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + + nsIHTMLContent* it = new nsInputFile(aTag, aManager); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIHTMLContentIID, (void**) aInstancePtrResult); +} + diff --git a/mozilla/layout/html/forms/src/nsInputFile.h b/mozilla/layout/html/forms/src/nsInputFile.h new file mode 100644 index 00000000000..a16e116155f --- /dev/null +++ b/mozilla/layout/html/forms/src/nsInputFile.h @@ -0,0 +1,51 @@ +/* -*- 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. + */ + +#ifndef nsInputFile_h___ +#define nsInputFile_h___ + +#include "nsInput.h" +class nsIAtom; +class nsString; + +class nsInputFile : public nsInput { +public: + nsInputFile (nsIAtom* aTag, nsIFormManager* aManager); + + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void SetAttribute(nsIAtom* aAttribute, const nsString& aValue); + + virtual nsContentAttr GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aResult) const; + +protected: + virtual ~nsInputFile(); + + virtual void GetType(nsString& aResult) const; + + nsString* mValue; + PRInt32 mSize; + PRInt32 mMaxLength; +}; + +#endif + + diff --git a/mozilla/layout/html/forms/src/nsInputFrame.cpp b/mozilla/layout/html/forms/src/nsInputFrame.cpp new file mode 100644 index 00000000000..d690b18cc28 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsInputFrame.cpp @@ -0,0 +1,283 @@ +/* -*- 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 "nsInput.h" +#include "nsInputFrame.h" +#include "nsHTMLParts.h" +#include "nsHTMLTagContent.h" +#include "nsIRenderingContext.h" +#include "nsIPresShell.h" +#include "nsIPresContext.h" +#include "nsIStyleContext.h" +#include "nsLeafFrame.h" +#include "nsCSSRendering.h" +#include "nsHTMLIIDs.h" +#include "nsIView.h" +#include "nsIViewManager.h" +#include "nsCoord.h" +#include "nsWidgetsCID.h" +#include "nsViewsCID.h" +#include "nsRepository.h" +#include "nsGUIEvent.h" + +#include "nsIButton.h" // remove this when GetCID is pure virtual +#include "nsICheckButton.h" //remove this +#include "nsITextWidget.h" //remove this +#include "nsISupports.h" + +nsInputFrame::nsInputFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsLeafFrame(aContent, aIndexInParent, aParentFrame) +{ + mCacheBounds.width = 0; + mCacheBounds.height = 0; + mLastMouseState = eMouseNone; +} + +nsInputFrame::~nsInputFrame() +{ +} + +// XXX it would be cool if form element used our rendering sw, then +// they could be blended, and bordered, and so on... +void +nsInputFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + static NS_DEFINE_IID(kIWidgetIID, NS_IWIDGET_IID); + + nsPoint offset; + nsIView *parent = GetOffsetFromView(offset); + if (nsnull == parent) { // a problem + NS_ASSERTION(0, "parent view was null\n"); + } else { + nsIView* view = GetView(); + float t2p = aPresContext.GetTwipsToPixels(); + //nsIWidget *widget = view->GetWindow(); + nsIWidget* widget; + nsresult result = GetWidget(view, &widget); + if (NS_OK == result) { + nsRect vBounds; + view->GetBounds(vBounds); + + if ((vBounds.x != offset.x) || (vBounds.y != offset.y)) + view->SetPosition(offset.x, offset.y); + + // initially the widget was created as hidden + if (nsViewVisibility_kHide == view->GetVisibility()) + view->SetVisibility(nsViewVisibility_kShow); + } else { + NS_ASSERTION(0, "could not get widget"); + } + NS_IF_RELEASE(widget); + NS_RELEASE(view); + NS_RELEASE(parent); + } +} + +PRBool +nsInputFrame::BoundsAreSet() +{ + if ((0 != mCacheBounds.width) || (0 != mCacheBounds.height)) { + return PR_TRUE; + } else { + return PR_FALSE; + } +} + + +void +nsInputFrame::GetDesiredSize(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize) +{ + if (!BoundsAreSet()) { + PreInitializeWidget(aPresContext, mCacheBounds); // sets mCacheBounds + } + aDesiredSize.width = mCacheBounds.width; + aDesiredSize.height = mCacheBounds.height; +} + +void +nsInputFrame::PreInitializeWidget(nsIPresContext* aPresContext, + nsSize& aBounds) +{ + // this should always be overridden by subclasses, but if not make it 10 x 10 + float p2t = aPresContext->GetPixelsToTwips(); + aBounds.width = (int)(10 * p2t); + aBounds.height = (int)(10 * p2t); +} + +nsIFrame::ReflowStatus +nsInputFrame::ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ + // XXX add in code to check for width/height being set via css + // and if set use them instead of calling GetDesiredSize. + + nsIView* view = GetView(); + if (nsnull == view) { + + static NS_DEFINE_IID(kViewCID, NS_VIEW_CID); + static NS_DEFINE_IID(kIViewIID, NS_IVIEW_IID); + + nsresult result = + NSRepository::CreateInstance(kViewCID, nsnull, kIViewIID, (void **)&view);// need to release + if (NS_OK != result) { + NS_ASSERTION(0, "Could not create view for button"); + return frNotComplete; + } + nsIPresShell *presShell = aPresContext->GetShell(); // need to release + nsIViewManager *viewMan = presShell->GetViewManager(); // need to release + + PreInitializeWidget(aPresContext, mCacheBounds); // sets mCacheBounds + //float t2p = aPresContext->GetTwipsToPixels(); + nsRect boundBox(0, 0, mCacheBounds.width, mCacheBounds.height); + + nsIView *parView = GetParentWithView()->GetView(); + + const nsIID id = GetCID(); + // initialize the view as hidden since we don't know the (x,y) until Paint + result = view->Init(viewMan, boundBox, parView, &id, nsnull, 0, nsnull, + 1.0f, nsViewVisibility_kHide); + if (NS_OK != result) { + NS_ASSERTION(0, "widget initialization failed"); + return frNotComplete; + } + + // set the content's widget, so it can get content modified by the widget + nsIWidget *widget; + result = GetWidget(view, &widget); + if (NS_OK == result) { + nsInput* content = (nsInput *)GetContent(); // change this cast to QueryInterface + content->SetWidget(widget); + NS_IF_RELEASE(widget); + NS_RELEASE(content); + } else { + NS_ASSERTION(0, "could not get widget"); + } + + viewMan->InsertChild(parView, view, 0); + SetView(view); + InitializeWidget(view); + + NS_IF_RELEASE(parView); + NS_IF_RELEASE(view); + NS_IF_RELEASE(viewMan); + NS_IF_RELEASE(presShell); + } + aDesiredSize.width = mCacheBounds.width; + aDesiredSize.height = mCacheBounds.height; + aDesiredSize.ascent = mCacheBounds.height; + aDesiredSize.descent = 0; + + if (nsnull != aMaxElementSize) { + aMaxElementSize->width = aDesiredSize.width; + aMaxElementSize->height = aDesiredSize.height; + } + + return frComplete; + +} + +nsresult +nsInputFrame::GetWidget(nsIView* aView, nsIWidget** aWidget) +{ + const nsIID id = GetIID(); + if (NS_OK == aView->QueryInterface(id, (void**)aWidget)) { + return NS_OK; + } else { + NS_ASSERTION(0, "The widget interface is invalid"); // need to print out more details of the widget + return NS_NOINTERFACE; + } +} + +const nsIID +nsInputFrame::GetIID() +{ + static NS_DEFINE_IID(kButtonIID, NS_IBUTTON_IID); + return kButtonIID; +} + +const nsIID +nsInputFrame::GetCID() +{ + static NS_DEFINE_IID(kButtonCID, NS_BUTTON_CID); + return kButtonCID; +} + +nsEventStatus nsInputFrame::HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent) +{ + // make sure that the widget in the event is this + static NS_DEFINE_IID(kSupportsIID, NS_ISUPPORTS_IID); + nsIWidget* thisWidget; + nsIView* view = GetView(); + nsresult result = GetWidget(view, &thisWidget); + nsISupports* thisWidgetSup; + result = thisWidget->QueryInterface(kSupportsIID, (void **)&thisWidgetSup); + nsISupports* eventWidgetSup; + result = aEvent->widget->QueryInterface(kSupportsIID, (void **)&eventWidgetSup); + + PRBool isOurEvent = (thisWidgetSup == eventWidgetSup) ? PR_TRUE : PR_FALSE; + + NS_RELEASE(eventWidgetSup); + NS_RELEASE(thisWidgetSup); + NS_IF_RELEASE(view); + NS_IF_RELEASE(thisWidget); + + if (!isOurEvent) { + return nsEventStatus_eIgnore; + } + + switch (aEvent->message) { + case NS_MOUSE_ENTER: + mLastMouseState = eMouseEnter; + break; + case NS_MOUSE_LEFT_BUTTON_DOWN: + mLastMouseState = + (eMouseEnter == mLastMouseState) ? eMouseDown : eMouseNone; + break; + case NS_MOUSE_LEFT_BUTTON_UP: + if (eMouseDown == mLastMouseState) { + /*nsIView* view = GetView(); + nsIWidget *widget = view->GetWindow(); + widget->SetFocus(); + NS_RELEASE(widget); + NS_RELEASE(view); */ + MouseClicked(); + //return PR_FALSE; + } + mLastMouseState = eMouseEnter; + break; + case NS_MOUSE_EXIT: + mLastMouseState = eMouseNone; + break; + } + return nsEventStatus_eIgnore; +} + + + + + + diff --git a/mozilla/layout/html/forms/src/nsInputFrame.h b/mozilla/layout/html/forms/src/nsInputFrame.h new file mode 100644 index 00000000000..4931d1bb079 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsInputFrame.h @@ -0,0 +1,83 @@ +/* -*- 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. + */ + +#ifndef nsInputFrame_h___ +#define nsInputFrame_h___ + +//#include "nsHTMLParts.h" +#include "nsHTMLTagContent.h" +#include "nsISupports.h" +#include "nsIWidget.h" +class nsIView; +//#include "nsIRenderingContext.h" +//#include "nsIPresContext.h" +//#include "nsIStyleContext.h" +#include "nsLeafFrame.h" +//#include "nsCSSRendering.h" +//#include "nsHTMLIIDs.h" + +enum nsMouseState { + eMouseNone, + eMouseEnter, + eMouseDown, + eMouseUp +}; + +class nsInputFrame : public nsLeafFrame { +public: + nsInputFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + virtual ReflowStatus ResizeReflow(nsIPresContext* aCX, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + + virtual const nsIID GetCID(); // make this pure virtual + + virtual const nsIID GetIID(); // make this pure virtual + + virtual nsresult GetWidget(nsIView* aView, nsIWidget** aWidget); + + virtual void InitializeWidget(nsIView *aView) = 0; // initialize widget in ResizeReflow + + virtual void PreInitializeWidget(nsIPresContext* aPresContext, + nsSize& aBounds); // make this pure virtual + + virtual nsEventStatus HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent); + + virtual void MouseClicked() {} + +protected: + virtual ~nsInputFrame(); + virtual void GetDesiredSize(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize); + PRBool BoundsAreSet(); + + nsSize mCacheBounds; + nsMouseState mLastMouseState; +}; + +#endif diff --git a/mozilla/layout/html/forms/src/nsInputHidden.cpp b/mozilla/layout/html/forms/src/nsInputHidden.cpp new file mode 100644 index 00000000000..96998ef7d0f --- /dev/null +++ b/mozilla/layout/html/forms/src/nsInputHidden.cpp @@ -0,0 +1,155 @@ +/* -*- 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 "nsInputHidden.h" +#include "nsInputFrame.h" +#include "nsIContent.h" +#include "prtypes.h" +#include "nsIFrame.h" +#include "nsISupports.h" +#include "nsIAtom.h" +#include "nsIPresContext.h" +#include "nsIHTMLContent.h" +#include "nsHTMLIIDs.h" +#include "nsHTMLAtoms.h" + +class nsInputHiddenFrame : public nsInputFrame { +public: + nsInputHiddenFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void InitializeWidget(nsIView *aView); + +protected: + virtual ~nsInputHiddenFrame(); +}; + +nsInputHiddenFrame::nsInputHiddenFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsInputFrame(aContent, aIndexInParent, aParentFrame) +{ +} + +nsInputHiddenFrame::~nsInputHiddenFrame() +{ +} + + +void +nsInputHiddenFrame::InitializeWidget(nsIView *aView) +{ +} + +// nsInputHidden + +nsInputHidden::nsInputHidden(nsIAtom* aTag, nsIFormManager* aManager) + : nsInput(aTag, aManager) +{ +} + +nsInputHidden::~nsInputHidden() +{ +} + +nsIFrame* +nsInputHidden::CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + nsIFrame* rv = new nsInputHiddenFrame(this, aIndexInParent, aParentFrame); + return rv; +} + +void nsInputHidden::GetType(nsString& aResult) const +{ + aResult = "hidden"; +} + +void nsInputHidden::SetAttribute(nsIAtom* aAttribute, const nsString& aValue) +{ + if (aAttribute == nsHTMLAtoms::value) { + if (nsnull == mValue) { + mValue = new nsString(aValue); + } else { + mValue->SetLength(0); + mValue->Append(aValue); + } + } + else if (aAttribute == nsHTMLAtoms::width) { + nsHTMLValue value; + ParseValue(aValue, 0, 1000, value); + mWidth = value.GetIntValue(); + } + else if (aAttribute == nsHTMLAtoms::height) { + nsHTMLValue value; + ParseValue(aValue, 0, 1000, value); + mHeight = value.GetIntValue(); + } + else { + nsInput::SetAttribute(aAttribute, aValue); + } +} + +nsContentAttr nsInputHidden::GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aResult) const +{ + nsContentAttr ca = eContentAttr_NotThere; + aResult.Reset(); + if (aAttribute == nsHTMLAtoms::value) { + if (nsnull != mValue) { + aResult.Set(*mValue); + ca = eContentAttr_HasValue; + } + } + else if (aAttribute == nsHTMLAtoms::width) { + if (0 <= mWidth) { + aResult.Set(mWidth, eHTMLUnit_Absolute); + ca = eContentAttr_HasValue; + } + } + else if (aAttribute == nsHTMLAtoms::height) { + if (0 <= mHeight) { + aResult.Set(mHeight, eHTMLUnit_Absolute); + ca = eContentAttr_HasValue; + } + } + else { + ca = nsInput::GetAttribute(aAttribute, aResult); + } + return ca; +} + +NS_HTML nsresult +NS_NewHTMLInputHidden(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag, nsIFormManager* aManager) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + + nsIHTMLContent* it = new nsInputHidden(aTag, aManager); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIHTMLContentIID, (void**) aInstancePtrResult); +} + diff --git a/mozilla/layout/html/forms/src/nsInputHidden.h b/mozilla/layout/html/forms/src/nsInputHidden.h new file mode 100644 index 00000000000..0b90eb79c59 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsInputHidden.h @@ -0,0 +1,50 @@ +/* -*- 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. + */ + +#ifndef nsInputHidden_h___ +#define nsInputHidden_h___ + +#include "nsInput.h" +class nsIAtom; +class nsString; + +class nsInputHidden : public nsInput { +public: + nsInputHidden (nsIAtom* aTag, nsIFormManager* aManager); + + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void SetAttribute(nsIAtom* aAttribute, const nsString& aValue); + + virtual nsContentAttr GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aResult) const; + +protected: + virtual ~nsInputHidden(); + + virtual void GetType(nsString& aResult) const; + + // XXX save code and subclass from nsInputButton? + nsString* mValue; + PRInt32 mWidth; + PRInt32 mHeight; +}; + +#endif diff --git a/mozilla/layout/html/forms/src/nsInputImage.cpp b/mozilla/layout/html/forms/src/nsInputImage.cpp new file mode 100644 index 00000000000..ac6c07cf7ad --- /dev/null +++ b/mozilla/layout/html/forms/src/nsInputImage.cpp @@ -0,0 +1,117 @@ +/* -*- 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 "nsInputImage.h" +#include "nsInputFrame.h" +#include "nsIContent.h" +#include "prtypes.h" +#include "nsIFrame.h" +#include "nsISupports.h" +#include "nsIAtom.h" +#include "nsIPresContext.h" +#include "nsIHTMLContent.h" +#include "nsHTMLIIDs.h" + +class nsInputImageFrame : public nsInputFrame { +public: + nsInputImageFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void InitializeWidget(nsIView *aView); + +protected: + virtual ~nsInputImageFrame(); +}; + +nsInputImageFrame::nsInputImageFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsInputFrame(aContent, aIndexInParent, aParentFrame) +{ +} + +nsInputImageFrame::~nsInputImageFrame() +{ +} + + +void +nsInputImageFrame::InitializeWidget(nsIView *aView) +{ +} + +//---------------------------------------------------------------------- +// nsInputImage + +nsInputImage::nsInputImage(nsIAtom* aTag, nsIFormManager* aManager) + : nsInput(aTag, aManager) +{ +} + +nsInputImage::~nsInputImage() +{ +} + +nsIFrame* +nsInputImage::CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + nsIFrame* rv = new nsInputImageFrame(this, aIndexInParent, aParentFrame); + return rv; +} + +void nsInputImage::GetType(nsString& aResult) const +{ + aResult = "image"; +} + +void nsInputImage::SetAttribute(nsIAtom* aAttribute, const nsString& aValue) +{ + // XXX need to read nav4 code first + nsInput::SetAttribute(aAttribute, aValue); +} + +nsContentAttr nsInputImage::GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aResult) const +{ + // XXX need to read nav4 code first + nsContentAttr ca = eContentAttr_NotThere; + aResult.Reset(); + ca = nsInput::GetAttribute(aAttribute, aResult); + return ca; +} + +NS_HTML nsresult +NS_NewHTMLInputImage(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag, nsIFormManager* aManager) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + + nsIHTMLContent* it = new nsInputImage(aTag, aManager); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIHTMLContentIID, (void**) aInstancePtrResult); +} + diff --git a/mozilla/layout/html/forms/src/nsInputImage.h b/mozilla/layout/html/forms/src/nsInputImage.h new file mode 100644 index 00000000000..87ca8175bc8 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsInputImage.h @@ -0,0 +1,47 @@ +/* -*- 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. + */ + +#ifndef nsInputImage_h___ +#define nsInputImage_h___ + +#include "nsInput.h" +class nsIAtom; +class nsString; + +class nsInputImage : public nsInput { +public: + nsInputImage (nsIAtom* aTag, nsIFormManager* aManager); + + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void SetAttribute(nsIAtom* aAttribute, const nsString& aValue); + + virtual nsContentAttr GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aResult) const; + +protected: + virtual ~nsInputImage(); + + virtual void GetType(nsString& aResult) const; +}; + +#endif + + diff --git a/mozilla/layout/html/forms/src/nsInputPassword.cpp b/mozilla/layout/html/forms/src/nsInputPassword.cpp new file mode 100644 index 00000000000..92ad9c9eef8 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsInputPassword.cpp @@ -0,0 +1,95 @@ +/* -*- 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 "nsInputPassword.h" +#include "nsInputFrame.h" +#include "nsIContent.h" +#include "prtypes.h" +#include "nsIFrame.h" +#include "nsISupports.h" +#include "nsIAtom.h" +#include "nsIPresContext.h" +#include "nsIHTMLContent.h" +#include "nsHTMLIIDs.h" + +class nsInputPasswordFrame : public nsInputFrame { +public: + nsInputPasswordFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void InitializeWidget(nsIView *aView); + +protected: + virtual ~nsInputPasswordFrame(); +}; + +nsInputPasswordFrame::nsInputPasswordFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsInputFrame(aContent, aIndexInParent, aParentFrame) +{ +} + +nsInputPasswordFrame::~nsInputPasswordFrame() +{ +} + + +void +nsInputPasswordFrame::InitializeWidget(nsIView *aView) +{ +} + +// nsInputPassword + +nsInputPassword::nsInputPassword(nsIAtom* aTag, nsIFormManager* aManager) + : nsInputText(aTag, aManager) +{ +} + +nsInputPassword::~nsInputPassword() +{ +} + +nsIFrame* +nsInputPassword::CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + nsIFrame* rv = new nsInputPasswordFrame(this, aIndexInParent, aParentFrame); + return rv; +} + +NS_HTML nsresult +NS_NewHTMLInputPassword(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag, nsIFormManager* aManager) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + + nsIHTMLContent* it = new nsInputPassword(aTag, aManager); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIHTMLContentIID, (void**) aInstancePtrResult); +} + diff --git a/mozilla/layout/html/forms/src/nsInputPassword.h b/mozilla/layout/html/forms/src/nsInputPassword.h new file mode 100644 index 00000000000..7e2688016ae --- /dev/null +++ b/mozilla/layout/html/forms/src/nsInputPassword.h @@ -0,0 +1,40 @@ +/* -*- 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. + */ + +#ifndef nsInputPassword_h___ +#define nsInputPassword_h___ + +#include "nsInputText.h" +class nsIAtom; +class nsString; + +class nsInputPassword : public nsInputText { +public: + nsInputPassword (nsIAtom* aTag, nsIFormManager* aManager); + + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + +protected: + virtual ~nsInputPassword(); +}; + +#endif + + diff --git a/mozilla/layout/html/forms/src/nsInputRadio.cpp b/mozilla/layout/html/forms/src/nsInputRadio.cpp new file mode 100644 index 00000000000..708d1e377b1 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsInputRadio.cpp @@ -0,0 +1,133 @@ +/* -*- 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 "nsInputRadio.h" +#include "nsInputFrame.h" +#include "nsIContent.h" +#include "prtypes.h" +#include "nsIFrame.h" +#include "nsISupports.h" +#include "nsIAtom.h" +#include "nsIPresContext.h" +#include "nsIHTMLContent.h" +#include "nsHTMLIIDs.h" +#include "nsIRadioButton.h" +#include "nsWidgetsCID.h" +#include "nsSize.h" + +class nsInputRadioFrame : public nsInputFrame { +public: + nsInputRadioFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void PreInitializeWidget(nsIPresContext* aPresContext, + nsSize& aBounds); + + virtual void InitializeWidget(nsIView *aView); + + virtual const nsIID GetCID(); + + virtual const nsIID GetIID(); + +protected: + virtual ~nsInputRadioFrame(); +}; + +nsInputRadioFrame::nsInputRadioFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsInputFrame(aContent, aIndexInParent, aParentFrame) +{ +} + +nsInputRadioFrame::~nsInputRadioFrame() +{ +} + + +const nsIID +nsInputRadioFrame::GetIID() +{ + static NS_DEFINE_IID(kRadioIID, NS_IRADIOBUTTON_IID); + return kRadioIID; +} + +const nsIID +nsInputRadioFrame::GetCID() +{ + static NS_DEFINE_IID(kRadioCID, NS_RADIOBUTTON_CID); + return kRadioCID; +} + +void +nsInputRadioFrame::PreInitializeWidget(nsIPresContext* aPresContext, + nsSize& aBounds) +{ + float p2t = aPresContext->GetPixelsToTwips(); + aBounds.width = (int)(12 * p2t); + aBounds.height = (int)(12 * p2t); +} + +void +nsInputRadioFrame::InitializeWidget(nsIView *aView) +{ +} + +// nsInputRadio + +nsInputRadio::nsInputRadio(nsIAtom* aTag, nsIFormManager* aManager) + : nsInputCheckbox(aTag, aManager) +{ +} + +nsInputRadio::~nsInputRadio() +{ +} + +nsIFrame* +nsInputRadio::CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + nsIFrame* rv = new nsInputRadioFrame(this, aIndexInParent, aParentFrame); + return rv; +} + +void nsInputRadio::GetType(nsString& aResult) const +{ + aResult = "radio"; +} + +NS_HTML nsresult +NS_NewHTMLInputRadio(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag, nsIFormManager* aManager) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + + nsIHTMLContent* it = new nsInputRadio(aTag, aManager); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIHTMLContentIID, (void**) aInstancePtrResult); +} + diff --git a/mozilla/layout/html/forms/src/nsInputRadio.h b/mozilla/layout/html/forms/src/nsInputRadio.h new file mode 100644 index 00000000000..40367ceb486 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsInputRadio.h @@ -0,0 +1,42 @@ +/* -*- 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. + */ + +#ifndef nsInputRadio_h___ +#define nsInputRadio_h___ + +#include "nsInputCheckbox.h" +class nsIAtom; +class nsString; + +class nsInputRadio : public nsInputCheckbox { +public: + nsInputRadio (nsIAtom* aTag, nsIFormManager* aManager); + + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + +protected: + virtual ~nsInputRadio(); + + virtual void GetType(nsString& aResult) const; +}; + +#endif + + diff --git a/mozilla/layout/html/forms/src/nsInputText.cpp b/mozilla/layout/html/forms/src/nsInputText.cpp new file mode 100644 index 00000000000..f9a3b01a8a9 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsInputText.cpp @@ -0,0 +1,241 @@ +/* -*- 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 "nsInputText.h" +#include "nsInputFrame.h" +#include "nsIContent.h" +#include "prtypes.h" +#include "nsIFrame.h" +#include "nsISupports.h" +#include "nsIAtom.h" +#include "nsIPresContext.h" +#include "nsIHTMLContent.h" +#include "nsHTMLIIDs.h" +#include "nsITextWidget.h" +#include "nsWidgetsCID.h" +#include "nsSize.h" +#include "nsString.h" +#include "nsHTMLAtoms.h" + +class nsInputTextFrame : public nsInputFrame { +public: + nsInputTextFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void PreInitializeWidget(nsIPresContext* aPresContext, + nsSize& aBounds); + + virtual void InitializeWidget(nsIView *aView); + + virtual const nsIID GetCID(); + + virtual const nsIID GetIID(); + +protected: + virtual ~nsInputTextFrame(); + nsString mCacheValue; +}; + +nsInputTextFrame::nsInputTextFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsInputFrame(aContent, aIndexInParent, aParentFrame) +{ +} + +nsInputTextFrame::~nsInputTextFrame() +{ +} + +const nsIID +nsInputTextFrame::GetIID() +{ + static NS_DEFINE_IID(kTextIID, NS_ITEXTWIDGET_IID); + return kTextIID; +} + +const nsIID +nsInputTextFrame::GetCID() +{ + static NS_DEFINE_IID(kTextCID, NS_TEXTFIELD_CID); + return kTextCID; +} + +void +nsInputTextFrame::PreInitializeWidget(nsIPresContext* aPresContext, + nsSize& aBounds) +{ + nsInputText* content = (nsInputText *)GetContent(); // this must be an nsInputButton + + // get the value of the text + if (nsnull != content->mValue) { + mCacheValue = *content->mValue; + } else { + mCacheValue = ""; + } + NS_RELEASE(content); + + float p2t = aPresContext->GetPixelsToTwips(); + aBounds.width = (int)(120 * p2t); + aBounds.height = (int)(20 * p2t); +} + +void +nsInputTextFrame::InitializeWidget(nsIView *aView) +{ + nsITextWidget* text; + if (NS_OK == GetWidget(aView, (nsIWidget **)&text)) { + text->SetText(mCacheValue); + NS_RELEASE(text); + } +} + +//---------------------------------------------------------------------- +// nsInputText + +nsInputText::nsInputText(nsIAtom* aTag, nsIFormManager* aManager) + : nsInput(aTag, aManager) +{ +} + +nsInputText::~nsInputText() +{ + if (nsnull != mValue) { + delete mValue; + } +} + +nsIFrame* +nsInputText::CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + nsIFrame* rv = new nsInputTextFrame(this, aIndexInParent, aParentFrame); + printf("** nsInputText::CreateFrame frame=%d", rv); + return rv; +} + +PRInt32 +nsInputText::GetMaxNumValues() +{ + return 1; +} + +PRBool +nsInputText::GetValues(PRInt32 aMaxNumValues, PRInt32& aNumValues, + nsString* aValues) +{ + if (aMaxNumValues <= 0) { + return PR_FALSE; + } + nsITextWidget* text = (nsITextWidget *)GetWidget(); + nsString value; + text->GetText(aValues[0], 0); // the last parm is not used + aNumValues = 1; + + return PR_TRUE; +} + + +void +nsInputText::Reset() +{ + nsITextWidget* text = (nsITextWidget *)GetWidget(); + if (nsnull == mValue) { + text->SetText(""); + } else { + text->SetText(*mValue); + } +} + +void nsInputText::GetType(nsString& aResult) const +{ + aResult = "text"; +} + +void nsInputText::SetAttribute(nsIAtom* aAttribute, const nsString& aValue) +{ + if (aAttribute == nsHTMLAtoms::size) { + nsHTMLValue value; + ParseValue(aValue, 1, value); + mSize = value.GetIntValue(); + } + else if (aAttribute == nsHTMLAtoms::maxlength) { + nsHTMLValue value; + ParseValue(aValue, 1, value);/* XXX nav doesn't clamp; what does it do with illegal values? */ + mMaxLength = value.GetIntValue(); + } + else if (aAttribute == nsHTMLAtoms::value) { + if (nsnull == mValue) { + mValue = new nsString(aValue); + } else { + *mValue = aValue; + } + } + else { + nsInput::SetAttribute(aAttribute, aValue); + } +} + +nsContentAttr nsInputText::GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aResult) const +{ + nsContentAttr ca = eContentAttr_NotThere; + aResult.Reset(); + if (aAttribute == nsHTMLAtoms::size) { + if (0 < mSize) { + aResult.Set(mSize, eHTMLUnit_Absolute); + ca = eContentAttr_HasValue; + } + } + else if (aAttribute == nsHTMLAtoms::maxlength) { + if (0 < mMaxLength) { + aResult.Set(mMaxLength, eHTMLUnit_Absolute); + ca = eContentAttr_HasValue; + } + } + else if (aAttribute == nsHTMLAtoms::value) { + if (nsnull != mValue) { + aResult.Set(*mValue); + ca = eContentAttr_HasValue; + } + } + else { + ca = nsInput::GetAttribute(aAttribute, aResult); + } + return ca; +} + +NS_HTML nsresult +NS_NewHTMLInputText(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag, nsIFormManager* aManager) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + + nsIHTMLContent* it = new nsInputText(aTag, aManager); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIHTMLContentIID, (void**) aInstancePtrResult); +} + diff --git a/mozilla/layout/html/forms/src/nsInputText.h b/mozilla/layout/html/forms/src/nsInputText.h new file mode 100644 index 00000000000..9977ffb2b66 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsInputText.h @@ -0,0 +1,61 @@ +/* -*- 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. + */ + +#ifndef nsInputText_h___ +#define nsInputText_h___ + +#include "nsInput.h" +#include "nsString.h" +class nsIAtom; +class nsString; +class nsView; + +class nsInputText : public nsInput { +public: + nsInputText (nsIAtom* aTag, nsIFormManager* aManager); + + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void SetAttribute(nsIAtom* aAttribute, const nsString& aValue); + + virtual nsContentAttr GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aResult) const; + + virtual PRInt32 GetMaxNumValues(); + + virtual PRBool GetValues(PRInt32 aMaxNumValues, PRInt32& aNumValues, + nsString* aValues); + + virtual void Reset(); + + // Note: this has a copy of code from nsInputFile + nsString* mValue; + PRInt32 mSize; + PRInt32 mMaxLength; + +protected: + virtual ~nsInputText(); + + virtual void GetType(nsString& aResult) const; +}; + +#endif + + diff --git a/mozilla/layout/html/makefile.win b/mozilla/layout/html/makefile.win new file mode 100644 index 00000000000..97d8ffb0509 --- /dev/null +++ b/mozilla/layout/html/makefile.win @@ -0,0 +1,23 @@ +#!nmake +# +# 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. + +DEPTH=..\.. +IGNORE_MANIFEST=1 + +DIRS = base document forms style table tests + +include <$(DEPTH)\config\rules.mak> diff --git a/mozilla/layout/html/style/Makefile b/mozilla/layout/html/style/Makefile new file mode 100644 index 00000000000..c650dc9b7ab --- /dev/null +++ b/mozilla/layout/html/style/Makefile @@ -0,0 +1,24 @@ +#!gmake +# +# 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. + +DEPTH = ../../.. + +DIRS = public src + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/layout/html/style/makefile.win b/mozilla/layout/html/style/makefile.win new file mode 100644 index 00000000000..c9c67f325a1 --- /dev/null +++ b/mozilla/layout/html/style/makefile.win @@ -0,0 +1,23 @@ +#!nmake +# +# 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. + +DEPTH=..\..\.. +IGNORE_MANIFEST=1 + +DIRS=public src + +include <$(DEPTH)\config\rules.mak> diff --git a/mozilla/layout/html/style/public/Makefile b/mozilla/layout/html/style/public/Makefile new file mode 100644 index 00000000000..8db535b96d6 --- /dev/null +++ b/mozilla/layout/html/style/public/Makefile @@ -0,0 +1,26 @@ +#!gmake +# +# 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. + +DEPTH=../../../.. + +EXPORTS = \ + nsICSSParser.h \ + $(NULL) + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/layout/html/style/public/makefile.win b/mozilla/layout/html/style/public/makefile.win new file mode 100644 index 00000000000..91188cd8315 --- /dev/null +++ b/mozilla/layout/html/style/public/makefile.win @@ -0,0 +1,25 @@ +#!nmake +# +# 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. + +DEPTH=..\..\..\.. +IGNORE_MANIFEST=1 + +EXPORTS=nsICSSParser.h +MODULE=raptor + +include <$(DEPTH)\config\rules.mak> + diff --git a/mozilla/layout/html/style/public/nsICSSParser.h b/mozilla/layout/html/style/public/nsICSSParser.h new file mode 100644 index 00000000000..e9b21f10215 --- /dev/null +++ b/mozilla/layout/html/style/public/nsICSSParser.h @@ -0,0 +1,56 @@ +/* -*- 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. + */ +#ifndef nsCSS1Parser_h___ +#define nsCSS1Parser_h___ + +#include "nslayout.h" +#include "nsISupports.h" +class nsIStyleSheet; +class nsIUnicharInputStream; +class nsIURL; + +#define NS_ICSS_PARSER_IID \ +{ 0xcc9c0610, 0x968c, 0x11d1, \ + {0x93, 0x23, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +// Interface to the css parser. +class nsICSSParser : public nsISupports { +public: + // Return a mask of the various css standards that this parser + // supports. + virtual PRUint32 GetInfoMask() = 0; + + // Set a style sheet for the parser to fill in. The style sheet must + // implement the nsICSSStyleSheet interface + virtual nsresult SetStyleSheet(nsIStyleSheet* aSheet) = 0; + + virtual nsIStyleSheet* Parse(PRInt32* aErrorCode, + nsIUnicharInputStream* aInput, + nsIURL* aInputURL) = 0; +}; + +// Values or'd in the GetInfoMask; other bits are reserved +#define NS_CSS_GETINFO_CSS1 ((PRUint32) 0x00000001L) +#define NS_CSS_GETINFO_CSSP ((PRUint32) 0x00000002L) +#define NS_CSS_GETINFO_CSS2 ((PRUint32) 0x00000004L) +#define NS_CSS_GETINFO_CSS_FROSTING ((PRUint32) 0x00000008L) + +extern NS_HTML nsresult + NS_NewCSSParser(nsICSSParser** aInstancePtrResult); + +#endif /* nsCSS1Parser_h___ */ diff --git a/mozilla/layout/html/style/src/Makefile b/mozilla/layout/html/style/src/Makefile new file mode 100644 index 00000000000..6f6502f7a3a --- /dev/null +++ b/mozilla/layout/html/style/src/Makefile @@ -0,0 +1,48 @@ +#!gmake +# +# 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. + +DEPTH=../../../.. + +include $(DEPTH)/config/config.mk + +LIBRARY_NAME = raptorhtmlstyle_s + +# Note the sophisticated alphabetical ordering :-| +CPPSRCS = \ + nsCSSKeywords.cpp \ + nsCSSLayout.cpp \ + nsCSSDeclaration.cpp \ + nsCSSParser.cpp \ + nsCSSProps.cpp \ + nsCSSRendering.cpp \ + nsCSSScanner.cpp \ + nsCSSStyleRule.cpp \ + nsCSSStyleSheet.cpp \ + nsHTMLAttributes.cpp \ + nsHTMLStyleSheet.cpp \ + nsHTMLValue.cpp \ + $(NULL) + +MODULE = raptor + +INCLUDES += -I../../base/src -I. + +LCFLAGS += -D_IMPL_NS_HTML + +REQUIRES = xpcom raptor dom + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/layout/html/style/src/makefile.win b/mozilla/layout/html/style/src/makefile.win new file mode 100644 index 00000000000..bc360ccee3a --- /dev/null +++ b/mozilla/layout/html/style/src/makefile.win @@ -0,0 +1,52 @@ +#!nmake +# +# 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. + +DEPTH=..\..\..\.. +IGNORE_MANIFEST=1 + +LIBRARY_NAME=raptorhtmlstyle_s +MODULE=raptor +REQUIRES=xpcom raptor + +DEFINES=-D_IMPL_NS_HTML -I..\..\base\src + +CPPSRCS=nsCSSKeywords.cpp nsCSSLayout.cpp nsCSSDeclaration.cpp \ + nsCSSParser.cpp nsCSSProps.cpp nsCSSRendering.cpp nsCSSScanner.cpp \ + nsCSSStyleRule.cpp nsCSSStyleSheet.cpp nsHTMLAttributes.cpp \ + nsHTMLStyleSheet.cpp nsHTMLValue.cpp + +CPP_OBJS=.\$(OBJDIR)\nsCSSKeywords.obj .\$(OBJDIR)\nsCSSLayout.obj \ + .\$(OBJDIR)\nsCSSDeclaration.obj .\$(OBJDIR)\nsCSSParser.obj \ + .\$(OBJDIR)\nsCSSProps.obj .\$(OBJDIR)\nsCSSRendering.obj \ + .\$(OBJDIR)\nsCSSScanner.obj .\$(OBJDIR)\nsCSSStyleRule.obj \ + .\$(OBJDIR)\nsCSSStyleSheet.obj .\$(OBJDIR)\nsHTMLAttributes.obj \ + .\$(OBJDIR)\nsHTMLStyleSheet.obj .\$(OBJDIR)\nsHTMLValue.obj + +LINCS=-I$(XPDIST)\public\xpcom -I$(XPDIST)\public\raptor + +LCFLAGS = \ + $(LCFLAGS) \ + $(DEFINES) \ + $(NULL) + +include <$(DEPTH)\config\rules.mak> + +libs:: $(LIBRARY) + $(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib + +clobber:: + rm -f $(DIST)\lib\$(LIBRARY_NAME).lib diff --git a/mozilla/layout/html/style/src/nsCSSDeclaration.cpp b/mozilla/layout/html/style/src/nsCSSDeclaration.cpp new file mode 100644 index 00000000000..2f9d7ac6155 --- /dev/null +++ b/mozilla/layout/html/style/src/nsCSSDeclaration.cpp @@ -0,0 +1,1350 @@ +/* -*- 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 "nsICSSDeclaration.h" +#include "nsString.h" +#include "nsCRT.h" +#include "nsCSSProps.h" +#include "nsCSSPropIDs.h" +#include "nsUnitConversion.h" + +static NS_DEFINE_IID(kCSSFontSID, NS_CSS_FONT_SID); +static NS_DEFINE_IID(kCSSColorSID, NS_CSS_COLOR_SID); +static NS_DEFINE_IID(kCSSTextSID, NS_CSS_TEXT_SID); +static NS_DEFINE_IID(kCSSMarginSID, NS_CSS_MARGIN_SID); +static NS_DEFINE_IID(kCSSPositionSID, NS_CSS_POSITION_SID); +static NS_DEFINE_IID(kCSSListSID, NS_CSS_LIST_SID); +static NS_DEFINE_IID(kICSSDeclarationIID, NS_ICSS_DECLARATION_IID); + + +nsCSSValue::nsCSSValue(void) + : mUnit(eCSSUnit_Null) +{ + mValue.mInt = 0; +} + +nsCSSValue::nsCSSValue(PRInt32 aValue, nsCSSUnit aUnit) + : mUnit(aUnit) +{ + mValue.mInt = aValue; +} + +nsCSSValue::nsCSSValue(float aValue, nsCSSUnit aUnit) + : mUnit(aUnit) +{ + mValue.mFloat = aValue; +} + +nsCSSValue::nsCSSValue(const nsString& aValue) + : mUnit(eCSSUnit_String) +{ + mValue.mString = aValue.ToNewString(); +} + +nsCSSValue::nsCSSValue(nscolor aValue) + : mUnit(eCSSUnit_Color) +{ + mValue.mColor = aValue; +} + +nsCSSValue::nsCSSValue(const nsCSSValue& aCopy) + : mUnit(aCopy.mUnit) +{ + if (eCSSUnit_String == mUnit) { + if (nsnull != aCopy.mValue.mString) { + mValue.mString = (aCopy.mValue.mString)->ToNewString(); + } + else { + mValue.mString = nsnull; + } + } + else if ((eCSSUnit_Absolute <= mUnit) && (mUnit <= eCSSUnit_Enumerated)) { + mValue.mInt = aCopy.mValue.mInt; + } + else if (eCSSUnit_Color == mUnit){ + mValue.mColor = aCopy.mValue.mColor; + } + else { + mValue.mFloat = aCopy.mValue.mFloat; + } +} + +nsCSSValue::~nsCSSValue(void) +{ + Reset(); +} + +nsCSSValue& nsCSSValue::operator=(const nsCSSValue& aCopy) +{ + Reset(); + mUnit = aCopy.mUnit; + if (eCSSUnit_String == mUnit) { + if (nsnull != aCopy.mValue.mString) { + mValue.mString = (aCopy.mValue.mString)->ToNewString(); + } + } + else if ((eCSSUnit_Absolute <= mUnit) && (mUnit <= eCSSUnit_Enumerated)) { + mValue.mInt = aCopy.mValue.mInt; + } + else if (eCSSUnit_Color == mUnit){ + mValue.mColor = aCopy.mValue.mColor; + } + else { + mValue.mFloat = aCopy.mValue.mFloat; + } + return *this; +} + +PRBool nsCSSValue::operator==(const nsCSSValue& aOther) const +{ + if (mUnit == aOther.mUnit) { + if (eCSSUnit_String == mUnit) { + if (nsnull == mValue.mString) { + if (nsnull == aOther.mValue.mString) { + return PR_TRUE; + } + } + else if (nsnull != aOther.mValue.mString) { + return mValue.mString->Equals(*(aOther.mValue.mString)); + } + } + else if ((eCSSUnit_Absolute <= mUnit) && (mUnit < eCSSUnit_Percent)) { + return PRBool(mValue.mInt == aOther.mValue.mInt); + } + else if (eCSSUnit_Color == mUnit){ + return PRBool(mValue.mColor == aOther.mValue.mColor); + } + else { + return PRBool(mValue.mFloat == aOther.mValue.mFloat); + } + } + return PR_FALSE; +} + +nscoord nsCSSValue::GetLengthTwips(void) const +{ + NS_ASSERTION(IsFixedLengthUnit(), "not a fixed length unit"); + + if (IsFixedLengthUnit()) { + switch (mUnit) { + case eCSSUnit_Inch: + return (nscoord)NS_INCHES_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Foot: + return (nscoord)NS_FEET_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Mile: + return (nscoord)NS_MILES_TO_TWIPS(mValue.mFloat); + + case eCSSUnit_Millimeter: + return (nscoord)NS_MILLIMETERS_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Centimeter: + return (nscoord)NS_CENTIMETERS_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Meter: + return (nscoord)NS_METERS_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Kilometer: + return (nscoord)NS_KILOMETERS_TO_TWIPS(mValue.mFloat); + + case eCSSUnit_Point: + return (nscoord)NS_POINTS_TO_TWIPS_FLOAT(mValue.mFloat); + case eCSSUnit_Pica: + return (nscoord)NS_PICAS_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Didot: + return (nscoord)NS_DIDOTS_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Cicero: + return (nscoord)NS_CICEROS_TO_TWIPS(mValue.mFloat); + } + } + return 0; +} + +void nsCSSValue::Reset(void) +{ + if ((eCSSUnit_String == mUnit) && (nsnull != mValue.mString)) { + delete mValue.mString; + } + mUnit = eCSSUnit_Null; + mValue.mInt = 0; +}; + +void nsCSSValue::Set(PRInt32 aValue, nsCSSUnit aUnit) +{ + Reset(); + mUnit = aUnit; + mValue.mInt = aValue; +} + +void nsCSSValue::Set(float aValue, nsCSSUnit aUnit) +{ + Reset(); + mUnit = aUnit; + mValue.mFloat = aValue; +} + +void nsCSSValue::Set(const nsString& aValue) +{ + Reset(); + mUnit = eCSSUnit_String; + mValue.mString = aValue.ToNewString(); +} + +void nsCSSValue::Set(nscolor aValue) +{ + Reset(); + mUnit = eCSSUnit_Color; + mValue.mColor = aValue; +} + +void nsCSSValue::AppendToString(nsString& aBuffer, PRInt32 aPropID) const +{ + if (eCSSUnit_Null == mUnit) { + return; + } + + if (-1 < aPropID) { + aBuffer.Append(nsCSSProps::kNameTable[aPropID].name); + aBuffer.Append(": "); + } + + if (eCSSUnit_String == mUnit) { + if (nsnull != mValue.mString) { + aBuffer.Append('"'); + aBuffer.Append(*(mValue.mString)); + aBuffer.Append('"'); + } + else { + aBuffer.Append("null str"); + } + } + else if ((eCSSUnit_Absolute <= mUnit) && (mUnit <= eCSSUnit_Enumerated)) { + aBuffer.Append(mValue.mInt, 10); + aBuffer.Append("[0x"); + aBuffer.Append(mValue.mInt, 16); + aBuffer.Append(']'); + } + else if (eCSSUnit_Color == mUnit){ + aBuffer.Append("(0x"); + aBuffer.Append(NS_GET_R(mValue.mColor), 16); + aBuffer.Append(" 0x"); + aBuffer.Append(NS_GET_G(mValue.mColor), 16); + aBuffer.Append(" 0x"); + aBuffer.Append(NS_GET_B(mValue.mColor), 16); + aBuffer.Append(" 0x"); + aBuffer.Append(NS_GET_A(mValue.mColor), 16); + aBuffer.Append(')'); + } + else if (eCSSUnit_Percent <= mUnit) { + aBuffer.Append(mValue.mFloat); + } + + switch (mUnit) { + case eCSSUnit_Null: break; + case eCSSUnit_Auto: aBuffer.Append("auto"); break; + case eCSSUnit_String: break; + case eCSSUnit_Absolute: aBuffer.Append("abs"); break; + case eCSSUnit_Enumerated: aBuffer.Append("enum"); break; + case eCSSUnit_Color: aBuffer.Append("rbga"); break; + case eCSSUnit_Percent: aBuffer.Append("%"); break; + case eCSSUnit_Number: aBuffer.Append("#"); break; + case eCSSUnit_Inch: aBuffer.Append("in"); break; + case eCSSUnit_Foot: aBuffer.Append("ft"); break; + case eCSSUnit_Mile: aBuffer.Append("mi"); break; + case eCSSUnit_Millimeter: aBuffer.Append("mm"); break; + case eCSSUnit_Centimeter: aBuffer.Append("cm"); break; + case eCSSUnit_Meter: aBuffer.Append("m"); break; + case eCSSUnit_Kilometer: aBuffer.Append("km"); break; + case eCSSUnit_Point: aBuffer.Append("pt"); break; + case eCSSUnit_Pica: aBuffer.Append("pc"); break; + case eCSSUnit_Didot: aBuffer.Append("dt"); break; + case eCSSUnit_Cicero: aBuffer.Append("cc"); break; + case eCSSUnit_EM: aBuffer.Append("em"); break; + case eCSSUnit_EN: aBuffer.Append("en"); break; + case eCSSUnit_XHeight: aBuffer.Append("ex"); break; + case eCSSUnit_CapHeight: aBuffer.Append("cap"); break; + case eCSSUnit_Pixel: aBuffer.Append("px"); break; + } + aBuffer.Append(' '); +} + +void nsCSSValue::ToString(nsString& aBuffer, PRInt32 aPropID) const +{ + aBuffer.SetLength(0); + AppendToString(aBuffer, aPropID); +} + +const nsID& nsCSSFont::GetID(void) +{ + return kCSSFontSID; +} + +void nsCSSFont::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + nsAutoString buffer; + + mFamily.AppendToString(buffer, PROP_FONT_FAMILY); + mStyle.AppendToString(buffer, PROP_FONT_STYLE); + mVariant.AppendToString(buffer, PROP_FONT_VARIANT); + mWeight.AppendToString(buffer, PROP_FONT_WEIGHT); + mSize.AppendToString(buffer, PROP_FONT_SIZE); + fputs(buffer, out); +} + + +const nsID& nsCSSColor::GetID(void) +{ + return kCSSColorSID; +} + +void nsCSSColor::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + nsAutoString buffer; + + mColor.AppendToString(buffer, PROP_COLOR); + mBackColor.AppendToString(buffer, PROP_BACKGROUND_COLOR); + mBackImage.AppendToString(buffer, PROP_BACKGROUND_IMAGE); + mBackRepeat.AppendToString(buffer, PROP_BACKGROUND_REPEAT); + mBackAttachment.AppendToString(buffer, PROP_BACKGROUND_ATTACHMENT); + mBackPositionX.AppendToString(buffer, PROP_BACKGROUND_X_POSITION); + mBackPositionY.AppendToString(buffer, PROP_BACKGROUND_Y_POSITION); + mBackFilter.AppendToString(buffer, PROP_BACKGROUND_FILTER); + fputs(buffer, out); +} + +const nsID& nsCSSText::GetID(void) +{ + return kCSSTextSID; +} + +void nsCSSText::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + nsAutoString buffer; + + mWordSpacing.AppendToString(buffer, PROP_WORD_SPACING); + mLetterSpacing.AppendToString(buffer, PROP_LETTER_SPACING); + mDecoration.AppendToString(buffer, PROP_TEXT_DECORATION); + mVertAlign.AppendToString(buffer, PROP_VERTICAL_ALIGN); + mTransform.AppendToString(buffer, PROP_TEXT_TRANSFORM); + mHorzAlign.AppendToString(buffer, PROP_TEXT_ALIGN); + mIndent.AppendToString(buffer, PROP_TEXT_INDENT); + mLineHeight.AppendToString(buffer, PROP_LINE_HEIGHT); + mWhiteSpace.AppendToString(buffer, PROP_WHITE_SPACE); + fputs(buffer, out); +} + +void nsCSSRect::List(FILE* out, PRInt32 aPropID, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + nsAutoString buffer; + + if (-1 < aPropID) { + buffer.Append(nsCSSProps::kNameTable[aPropID].name); + buffer.Append(": "); + } + + mTop.AppendToString(buffer); + mRight.AppendToString(buffer); + mBottom.AppendToString(buffer); + mLeft.AppendToString(buffer); + fputs(buffer, out); +} + +nsCSSMargin::nsCSSMargin(void) + : mMargin(nsnull), mPadding(nsnull), mBorder(nsnull), mColor(nsnull), mStyle(nsnull) +{ +} + +nsCSSMargin::~nsCSSMargin(void) +{ + if (nsnull != mMargin) { + delete mMargin; + } + if (nsnull != mPadding) { + delete mPadding; + } + if (nsnull != mBorder) { + delete mBorder; + } + if (nsnull != mColor) { + delete mColor; + } + if (nsnull != mStyle) { + delete mStyle; + } +} + +const nsID& nsCSSMargin::GetID(void) +{ + return kCSSMarginSID; +} + +void nsCSSMargin::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + if (nsnull != mMargin) { + mMargin->List(out, PROP_MARGIN, aIndent); + } + if (nsnull != mPadding) { + mPadding->List(out, PROP_PADDING, aIndent); + } + if (nsnull != mBorder) { + mBorder->List(out, PROP_BORDER_WIDTH, aIndent); + } + if (nsnull != mColor) { + mColor->List(out, PROP_BORDER_COLOR, aIndent); + } + if (nsnull != mStyle) { + mStyle->List(out, PROP_BORDER_STYLE, aIndent); + } +} + +nsCSSPosition::nsCSSPosition(void) + : mClip(nsnull) +{ +} + +nsCSSPosition::~nsCSSPosition(void) +{ + if (nsnull != mClip) { + delete mClip; + } +} + +const nsID& nsCSSPosition::GetID(void) +{ + return kCSSPositionSID; +} + +void nsCSSPosition::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + nsAutoString buffer; + + mPosition.AppendToString(buffer, PROP_POSITION); + mWidth.AppendToString(buffer, PROP_WIDTH); + mHeight.AppendToString(buffer, PROP_HEIGHT); + mLeft.AppendToString(buffer, PROP_LEFT); + mTop.AppendToString(buffer, PROP_TOP); + fputs(buffer, out); + if (nsnull != mClip) { + mClip->List(out, PROP_CLIP); + } + buffer.SetLength(0); + mOverflow.AppendToString(buffer, PROP_OVERFLOW); + mZIndex.AppendToString(buffer, PROP_OVERFLOW); + mVisibility.AppendToString(buffer, PROP_VISIBILITY); + mFloat.AppendToString(buffer, PROP_FLOAT); + mClear.AppendToString(buffer, PROP_CLEAR); + mDisplay.AppendToString(buffer, PROP_DISPLAY); + mFilter.AppendToString(buffer, PROP_FILTER); + fputs(buffer, out); +} + +const nsID& nsCSSList::GetID(void) +{ + return kCSSListSID; +} + +void nsCSSList::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + nsAutoString buffer; + + mType.AppendToString(buffer, PROP_LIST_STYLE_TYPE); + mImage.AppendToString(buffer, PROP_LIST_STYLE_IMAGE); + mPosition.AppendToString(buffer, PROP_LIST_STYLE_POSITION); + fputs(buffer, out); +} + + + +class CSSDeclarationImpl : public nsICSSDeclaration { +public: + void* operator new(size_t size); + + CSSDeclarationImpl(void); + ~CSSDeclarationImpl(void); + + NS_DECL_ISUPPORTS + + nsresult GetData(const nsID& aSID, nsCSSStruct** aData); + nsresult EnsureData(const nsID& aSID, nsCSSStruct** aData); + + nsresult AddValue(const char* aProperty, const nsCSSValue& aValue); + nsresult AddValue(PRInt32 aProperty, const nsCSSValue& aValue); + nsresult GetValue(const char* aProperty, nsCSSValue& aValue); + nsresult GetValue(PRInt32 aProperty, nsCSSValue& aValue); + + void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + +private: + CSSDeclarationImpl(const CSSDeclarationImpl& aCopy); + CSSDeclarationImpl& operator=(const CSSDeclarationImpl& aCopy); + PRBool operator==(const CSSDeclarationImpl& aCopy) const; + +protected: + nsCSSFont* mFont; + nsCSSColor* mColor; + nsCSSText* mText; + nsCSSMargin* mMargin; + nsCSSPosition* mPosition; + nsCSSList* mList; +}; + +void* CSSDeclarationImpl::operator new(size_t size) +{ + void* result = new char[size]; + + nsCRT::zero(result, size); + return result; +} + +CSSDeclarationImpl::CSSDeclarationImpl(void) +{ + NS_INIT_REFCNT(); +} + +CSSDeclarationImpl::~CSSDeclarationImpl(void) +{ + if (nsnull != mFont) { + delete mFont; + } + if (nsnull != mColor) { + delete mColor; + } + if (nsnull != mText) { + delete mText; + } + if (nsnull != mMargin) { + delete mMargin; + } + if (nsnull != mPosition) { + delete mPosition; + } + if (nsnull != mList) { + delete mList; + } +} + +NS_IMPL_ISUPPORTS(CSSDeclarationImpl, kICSSDeclarationIID); + +nsresult CSSDeclarationImpl::GetData(const nsID& aSID, nsCSSStruct** aDataPtr) +{ + if (nsnull == aDataPtr) { + return NS_ERROR_NULL_POINTER; + } + + if (aSID.Equals(kCSSFontSID)) { + *aDataPtr = mFont; + } + else if (aSID.Equals(kCSSColorSID)) { + *aDataPtr = mColor; + } + else if (aSID.Equals(kCSSTextSID)) { + *aDataPtr = mText; + } + else if (aSID.Equals(kCSSMarginSID)) { + *aDataPtr = mMargin; + } + else if (aSID.Equals(kCSSPositionSID)) { + *aDataPtr = mPosition; + } + else if (aSID.Equals(kCSSListSID)) { + *aDataPtr = mList; + } + else { + return NS_NOINTERFACE; + } + return NS_OK; +} + +nsresult CSSDeclarationImpl::EnsureData(const nsID& aSID, nsCSSStruct** aDataPtr) +{ + if (nsnull == aDataPtr) { + return NS_ERROR_NULL_POINTER; + } + + if (aSID.Equals(kCSSFontSID)) { + if (nsnull == mFont) { + mFont = new nsCSSFont(); + } + *aDataPtr = mFont; + } + else if (aSID.Equals(kCSSColorSID)) { + if (nsnull == mColor) { + mColor = new nsCSSColor(); + } + *aDataPtr = mColor; + } + else if (aSID.Equals(kCSSTextSID)) { + if (nsnull == mText) { + mText = new nsCSSText(); + } + *aDataPtr = mText; + } + else if (aSID.Equals(kCSSMarginSID)) { + if (nsnull == mMargin) { + mMargin = new nsCSSMargin(); + } + *aDataPtr = mMargin; + } + else if (aSID.Equals(kCSSPositionSID)) { + if (nsnull == mPosition) { + mPosition = new nsCSSPosition(); + } + *aDataPtr = mPosition; + } + else if (aSID.Equals(kCSSListSID)) { + if (nsnull == mList) { + mList = new nsCSSList(); + } + *aDataPtr = mList; + } + else { + return NS_NOINTERFACE; + } + if (nsnull == *aDataPtr) { + return NS_ERROR_OUT_OF_MEMORY; + } + return NS_OK; +} + +nsresult CSSDeclarationImpl::AddValue(const char* aProperty, const nsCSSValue& aValue) +{ + return AddValue(nsCSSProps::LookupName(aProperty), aValue); +} + +nsresult CSSDeclarationImpl::AddValue(PRInt32 aProperty, const nsCSSValue& aValue) +{ + nsresult result = NS_OK; + + switch (aProperty) { + // nsCSSFont + case PROP_FONT_FAMILY: + case PROP_FONT_STYLE: + case PROP_FONT_VARIANT: + case PROP_FONT_WEIGHT: + case PROP_FONT_SIZE: + if (nsnull == mFont) { + mFont = new nsCSSFont(); + } + if (nsnull != mFont) { + switch (aProperty) { + case PROP_FONT_FAMILY: mFont->mFamily = aValue; break; + case PROP_FONT_STYLE: mFont->mStyle = aValue; break; + case PROP_FONT_VARIANT: mFont->mVariant = aValue; break; + case PROP_FONT_WEIGHT: mFont->mWeight = aValue; break; + case PROP_FONT_SIZE: mFont->mSize = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + // nsCSSColor + case PROP_COLOR: + case PROP_BACKGROUND_COLOR: + case PROP_BACKGROUND_IMAGE: + case PROP_BACKGROUND_REPEAT: + case PROP_BACKGROUND_ATTACHMENT: + case PROP_BACKGROUND_X_POSITION: + case PROP_BACKGROUND_Y_POSITION: + case PROP_BACKGROUND_FILTER: + if (nsnull == mColor) { + mColor = new nsCSSColor(); + } + if (nsnull != mColor) { + switch (aProperty) { + case PROP_COLOR: mColor->mColor = aValue; break; + case PROP_BACKGROUND_COLOR: mColor->mBackColor = aValue; break; + case PROP_BACKGROUND_IMAGE: mColor->mBackImage = aValue; break; + case PROP_BACKGROUND_REPEAT: mColor->mBackRepeat = aValue; break; + case PROP_BACKGROUND_ATTACHMENT: mColor->mBackAttachment = aValue; break; + case PROP_BACKGROUND_X_POSITION: mColor->mBackPositionX = aValue; break; + case PROP_BACKGROUND_Y_POSITION: mColor->mBackPositionY = aValue; break; + case PROP_BACKGROUND_FILTER: mColor->mBackFilter = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + // nsCSSText + case PROP_WORD_SPACING: + case PROP_LETTER_SPACING: + case PROP_TEXT_DECORATION: + case PROP_VERTICAL_ALIGN: + case PROP_TEXT_TRANSFORM: + case PROP_TEXT_ALIGN: + case PROP_TEXT_INDENT: + case PROP_LINE_HEIGHT: + case PROP_WHITE_SPACE: + if (nsnull == mText) { + mText = new nsCSSText(); + } + if (nsnull != mText) { + switch (aProperty) { + case PROP_WORD_SPACING: mText->mWordSpacing = aValue; break; + case PROP_LETTER_SPACING: mText->mLetterSpacing = aValue; break; + case PROP_TEXT_DECORATION: mText->mDecoration = aValue; break; + case PROP_VERTICAL_ALIGN: mText->mVertAlign = aValue; break; + case PROP_TEXT_TRANSFORM: mText->mTransform = aValue; break; + case PROP_TEXT_ALIGN: mText->mHorzAlign = aValue; break; + case PROP_TEXT_INDENT: mText->mIndent = aValue; break; + case PROP_LINE_HEIGHT: mText->mLineHeight = aValue; break; + case PROP_WHITE_SPACE: mText->mWhiteSpace = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + // nsCSSMargin + case PROP_MARGIN_TOP: + case PROP_MARGIN_RIGHT: + case PROP_MARGIN_BOTTOM: + case PROP_MARGIN_LEFT: + if (nsnull == mMargin) { + mMargin = new nsCSSMargin(); + } + if (nsnull != mMargin) { + if (nsnull == mMargin->mMargin) { + mMargin->mMargin = new nsCSSRect(); + } + if (nsnull != mMargin->mMargin) { + switch (aProperty) { + case PROP_MARGIN_TOP: mMargin->mMargin->mTop = aValue; break; + case PROP_MARGIN_RIGHT: mMargin->mMargin->mRight = aValue; break; + case PROP_MARGIN_BOTTOM: mMargin->mMargin->mBottom = aValue; break; + case PROP_MARGIN_LEFT: mMargin->mMargin->mLeft = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + case PROP_PADDING_TOP: + case PROP_PADDING_RIGHT: + case PROP_PADDING_BOTTOM: + case PROP_PADDING_LEFT: + if (nsnull == mMargin) { + mMargin = new nsCSSMargin(); + } + if (nsnull != mMargin) { + if (nsnull == mMargin->mPadding) { + mMargin->mPadding = new nsCSSRect(); + } + if (nsnull != mMargin->mPadding) { + switch (aProperty) { + case PROP_PADDING_TOP: mMargin->mPadding->mTop = aValue; break; + case PROP_PADDING_RIGHT: mMargin->mPadding->mRight = aValue; break; + case PROP_PADDING_BOTTOM: mMargin->mPadding->mBottom = aValue; break; + case PROP_PADDING_LEFT: mMargin->mPadding->mLeft = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + case PROP_BORDER_TOP_WIDTH: + case PROP_BORDER_RIGHT_WIDTH: + case PROP_BORDER_BOTTOM_WIDTH: + case PROP_BORDER_LEFT_WIDTH: + if (nsnull == mMargin) { + mMargin = new nsCSSMargin(); + } + if (nsnull != mMargin) { + if (nsnull == mMargin->mBorder) { + mMargin->mBorder = new nsCSSRect(); + } + if (nsnull != mMargin->mBorder) { + switch (aProperty) { + case PROP_BORDER_TOP_WIDTH: mMargin->mBorder->mTop = aValue; break; + case PROP_BORDER_RIGHT_WIDTH: mMargin->mBorder->mRight = aValue; break; + case PROP_BORDER_BOTTOM_WIDTH: mMargin->mBorder->mBottom = aValue; break; + case PROP_BORDER_LEFT_WIDTH: mMargin->mBorder->mLeft = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + case PROP_BORDER_TOP_COLOR: + case PROP_BORDER_RIGHT_COLOR: + case PROP_BORDER_BOTTOM_COLOR: + case PROP_BORDER_LEFT_COLOR: + if (nsnull == mMargin) { + mMargin = new nsCSSMargin(); + } + if (nsnull != mMargin) { + if (nsnull == mMargin->mColor) { + mMargin->mColor = new nsCSSRect(); + } + if (nsnull != mMargin->mColor) { + switch (aProperty) { + case PROP_BORDER_TOP_COLOR: mMargin->mColor->mTop = aValue; break; + case PROP_BORDER_RIGHT_COLOR: mMargin->mColor->mRight = aValue; break; + case PROP_BORDER_BOTTOM_COLOR: mMargin->mColor->mBottom = aValue; break; + case PROP_BORDER_LEFT_COLOR: mMargin->mColor->mLeft = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + case PROP_BORDER_TOP_STYLE: + case PROP_BORDER_RIGHT_STYLE: + case PROP_BORDER_BOTTOM_STYLE: + case PROP_BORDER_LEFT_STYLE: + if (nsnull == mMargin) { + mMargin = new nsCSSMargin(); + } + if (nsnull != mMargin) { + if (nsnull == mMargin->mStyle) { + mMargin->mStyle = new nsCSSRect(); + } + if (nsnull != mMargin->mStyle) { + switch (aProperty) { + case PROP_BORDER_TOP_STYLE: mMargin->mStyle->mTop = aValue; break; + case PROP_BORDER_RIGHT_STYLE: mMargin->mStyle->mRight = aValue; break; + case PROP_BORDER_BOTTOM_STYLE: mMargin->mStyle->mBottom = aValue; break; + case PROP_BORDER_LEFT_STYLE: mMargin->mStyle->mLeft = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + // nsCSSPosition + case PROP_POSITION: + case PROP_WIDTH: + case PROP_HEIGHT: + case PROP_LEFT: + case PROP_TOP: + case PROP_OVERFLOW: + case PROP_Z_INDEX: + case PROP_VISIBILITY: + case PROP_FLOAT: + case PROP_CLEAR: + case PROP_DISPLAY: + case PROP_FILTER: + if (nsnull == mPosition) { + mPosition = new nsCSSPosition(); + } + if (nsnull != mPosition) { + switch (aProperty) { + case PROP_POSITION: mPosition->mPosition = aValue; break; + case PROP_WIDTH: mPosition->mWidth = aValue; break; + case PROP_HEIGHT: mPosition->mHeight = aValue; break; + case PROP_LEFT: mPosition->mLeft = aValue; break; + case PROP_TOP: mPosition->mTop = aValue; break; + case PROP_OVERFLOW: mPosition->mOverflow = aValue; break; + case PROP_Z_INDEX: mPosition->mZIndex = aValue; break; + case PROP_VISIBILITY: mPosition->mVisibility = aValue; break; + case PROP_FLOAT: mPosition->mFloat = aValue; break; + case PROP_CLEAR: mPosition->mClear = aValue; break; + case PROP_DISPLAY: mPosition->mDisplay = aValue; break; + case PROP_FILTER: mPosition->mFilter = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + case PROP_CLIP_TOP: + case PROP_CLIP_RIGHT: + case PROP_CLIP_BOTTOM: + case PROP_CLIP_LEFT: + if (nsnull == mPosition) { + mPosition = new nsCSSPosition(); + } + if (nsnull != mPosition) { + if (nsnull == mPosition->mClip) { + mPosition->mClip = new nsCSSRect(); + } + if (nsnull != mPosition->mClip) { + switch(aProperty) { + case PROP_CLIP_TOP: mPosition->mClip->mTop = aValue; break; + case PROP_CLIP_RIGHT: mPosition->mClip->mRight = aValue; break; + case PROP_CLIP_BOTTOM: mPosition->mClip->mBottom = aValue; break; + case PROP_CLIP_LEFT: mPosition->mClip->mLeft = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + // nsCSSList + case PROP_LIST_STYLE_TYPE: + case PROP_LIST_STYLE_IMAGE: + case PROP_LIST_STYLE_POSITION: + if (nsnull == mList) { + mList = new nsCSSList(); + } + if (nsnull != mList) { + switch (aProperty) { + case PROP_LIST_STYLE_TYPE: mList->mType = aValue; break; + case PROP_LIST_STYLE_IMAGE: mList->mImage = aValue; break; + case PROP_LIST_STYLE_POSITION: mList->mPosition = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + case PROP_BACKGROUND: + case PROP_BORDER: + case PROP_CLIP: + case PROP_FONT: + case PROP_LIST_STYLE: + case PROP_MARGIN: + case PROP_PADDING: + case PROP_BACKGROUND_POSITION: + case PROP_BORDER_TOP: + case PROP_BORDER_RIGHT: + case PROP_BORDER_BOTTOM: + case PROP_BORDER_LEFT: + case PROP_BORDER_COLOR: + case PROP_BORDER_STYLE: + case PROP_BORDER_WIDTH: + NS_ERROR("can't query for shorthand properties"); + default: + result = NS_ERROR_ILLEGAL_VALUE; + break; + } + return result; +} + +nsresult CSSDeclarationImpl::GetValue(const char* aProperty, nsCSSValue& aValue) +{ + return GetValue(nsCSSProps::LookupName(aProperty), aValue); +} + +nsresult CSSDeclarationImpl::GetValue(PRInt32 aProperty, nsCSSValue& aValue) +{ + nsresult result = NS_OK; + + switch (aProperty) { + // nsCSSFont + case PROP_FONT_FAMILY: + case PROP_FONT_STYLE: + case PROP_FONT_VARIANT: + case PROP_FONT_WEIGHT: + case PROP_FONT_SIZE: + if (nsnull != mFont) { + switch (aProperty) { + case PROP_FONT_FAMILY: aValue = mFont->mFamily; break; + case PROP_FONT_STYLE: aValue = mFont->mStyle; break; + case PROP_FONT_VARIANT: aValue = mFont->mVariant; break; + case PROP_FONT_WEIGHT: aValue = mFont->mWeight; break; + case PROP_FONT_SIZE: aValue = mFont->mSize; break; + } + } + else { + aValue.Reset(); + } + break; + + // nsCSSColor + case PROP_COLOR: + case PROP_BACKGROUND_COLOR: + case PROP_BACKGROUND_IMAGE: + case PROP_BACKGROUND_REPEAT: + case PROP_BACKGROUND_ATTACHMENT: + case PROP_BACKGROUND_X_POSITION: + case PROP_BACKGROUND_Y_POSITION: + case PROP_BACKGROUND_FILTER: + if (nsnull != mColor) { + switch (aProperty) { + case PROP_COLOR: aValue = mColor->mColor; break; + case PROP_BACKGROUND_COLOR: aValue = mColor->mBackColor; break; + case PROP_BACKGROUND_IMAGE: aValue = mColor->mBackImage; break; + case PROP_BACKGROUND_REPEAT: aValue = mColor->mBackRepeat; break; + case PROP_BACKGROUND_ATTACHMENT: aValue = mColor->mBackAttachment; break; + case PROP_BACKGROUND_X_POSITION: aValue = mColor->mBackPositionX; break; + case PROP_BACKGROUND_Y_POSITION: aValue = mColor->mBackPositionY; break; + case PROP_BACKGROUND_FILTER: aValue = mColor->mBackFilter; break; + } + } + else { + aValue.Reset(); + } + break; + + // nsCSSText + case PROP_WORD_SPACING: + case PROP_LETTER_SPACING: + case PROP_TEXT_DECORATION: + case PROP_VERTICAL_ALIGN: + case PROP_TEXT_TRANSFORM: + case PROP_TEXT_ALIGN: + case PROP_TEXT_INDENT: + case PROP_LINE_HEIGHT: + case PROP_WHITE_SPACE: + if (nsnull != mText) { + switch (aProperty) { + case PROP_WORD_SPACING: aValue = mText->mWordSpacing; break; + case PROP_LETTER_SPACING: aValue = mText->mLetterSpacing; break; + case PROP_TEXT_DECORATION: aValue = mText->mDecoration; break; + case PROP_VERTICAL_ALIGN: aValue = mText->mVertAlign; break; + case PROP_TEXT_TRANSFORM: aValue = mText->mTransform; break; + case PROP_TEXT_ALIGN: aValue = mText->mHorzAlign; break; + case PROP_TEXT_INDENT: aValue = mText->mIndent; break; + case PROP_LINE_HEIGHT: aValue = mText->mLineHeight; break; + case PROP_WHITE_SPACE: aValue = mText->mWhiteSpace; break; + } + } + else { + aValue.Reset(); + } + break; + + // nsCSSMargin + case PROP_MARGIN_TOP: + case PROP_MARGIN_RIGHT: + case PROP_MARGIN_BOTTOM: + case PROP_MARGIN_LEFT: + if ((nsnull != mMargin) && (nsnull != mMargin->mMargin)) { + switch (aProperty) { + case PROP_MARGIN_TOP: aValue = mMargin->mMargin->mTop; break; + case PROP_MARGIN_RIGHT: aValue = mMargin->mMargin->mRight; break; + case PROP_MARGIN_BOTTOM: aValue = mMargin->mMargin->mBottom; break; + case PROP_MARGIN_LEFT: aValue = mMargin->mMargin->mLeft; break; + } + } + else { + aValue.Reset(); + } + break; + + case PROP_PADDING_TOP: + case PROP_PADDING_RIGHT: + case PROP_PADDING_BOTTOM: + case PROP_PADDING_LEFT: + if ((nsnull != mMargin) && (nsnull != mMargin->mPadding)) { + switch (aProperty) { + case PROP_PADDING_TOP: aValue = mMargin->mPadding->mTop; break; + case PROP_PADDING_RIGHT: aValue = mMargin->mPadding->mRight; break; + case PROP_PADDING_BOTTOM: aValue = mMargin->mPadding->mBottom; break; + case PROP_PADDING_LEFT: aValue = mMargin->mPadding->mLeft; break; + } + } + else { + aValue.Reset(); + } + break; + + case PROP_BORDER_TOP_WIDTH: + case PROP_BORDER_RIGHT_WIDTH: + case PROP_BORDER_BOTTOM_WIDTH: + case PROP_BORDER_LEFT_WIDTH: + if ((nsnull != mMargin) && (nsnull != mMargin->mBorder)) { + switch (aProperty) { + case PROP_BORDER_TOP_WIDTH: aValue = mMargin->mBorder->mTop; break; + case PROP_BORDER_RIGHT_WIDTH: aValue = mMargin->mBorder->mRight; break; + case PROP_BORDER_BOTTOM_WIDTH: aValue = mMargin->mBorder->mBottom; break; + case PROP_BORDER_LEFT_WIDTH: aValue = mMargin->mBorder->mLeft; break; + } + } + else { + aValue.Reset(); + } + break; + + case PROP_BORDER_TOP_COLOR: + case PROP_BORDER_RIGHT_COLOR: + case PROP_BORDER_BOTTOM_COLOR: + case PROP_BORDER_LEFT_COLOR: + if ((nsnull != mMargin) && (nsnull != mMargin->mColor)) { + switch (aProperty) { + case PROP_BORDER_TOP_COLOR: aValue = mMargin->mColor->mTop; break; + case PROP_BORDER_RIGHT_COLOR: aValue = mMargin->mColor->mRight; break; + case PROP_BORDER_BOTTOM_COLOR: aValue = mMargin->mColor->mBottom; break; + case PROP_BORDER_LEFT_COLOR: aValue = mMargin->mColor->mLeft; break; + } + } + else { + aValue.Reset(); + } + break; + + case PROP_BORDER_TOP_STYLE: + case PROP_BORDER_RIGHT_STYLE: + case PROP_BORDER_BOTTOM_STYLE: + case PROP_BORDER_LEFT_STYLE: + if ((nsnull != mMargin) && (nsnull != mMargin->mStyle)) { + switch (aProperty) { + case PROP_BORDER_TOP_STYLE: aValue = mMargin->mStyle->mTop; break; + case PROP_BORDER_RIGHT_STYLE: aValue = mMargin->mStyle->mRight; break; + case PROP_BORDER_BOTTOM_STYLE: aValue = mMargin->mStyle->mBottom; break; + case PROP_BORDER_LEFT_STYLE: aValue = mMargin->mStyle->mLeft; break; + } + } + else { + aValue.Reset(); + } + break; + + // nsCSSPosition + case PROP_POSITION: + case PROP_WIDTH: + case PROP_HEIGHT: + case PROP_LEFT: + case PROP_TOP: + case PROP_OVERFLOW: + case PROP_Z_INDEX: + case PROP_VISIBILITY: + case PROP_FLOAT: + case PROP_CLEAR: + case PROP_DISPLAY: + case PROP_FILTER: + if (nsnull != mPosition) { + switch (aProperty) { + case PROP_POSITION: aValue = mPosition->mPosition; break; + case PROP_WIDTH: aValue = mPosition->mWidth; break; + case PROP_HEIGHT: aValue = mPosition->mHeight; break; + case PROP_LEFT: aValue = mPosition->mLeft; break; + case PROP_TOP: aValue = mPosition->mTop; break; + case PROP_OVERFLOW: aValue = mPosition->mOverflow; break; + case PROP_Z_INDEX: aValue = mPosition->mZIndex; break; + case PROP_VISIBILITY: aValue = mPosition->mVisibility; break; + case PROP_FLOAT: aValue = mPosition->mFloat; break; + case PROP_CLEAR: aValue = mPosition->mClear; break; + case PROP_DISPLAY: aValue = mPosition->mDisplay; break; + case PROP_FILTER: aValue = mPosition->mFilter; break; + } + } + else { + aValue.Reset(); + } + break; + + case PROP_CLIP_TOP: + case PROP_CLIP_RIGHT: + case PROP_CLIP_BOTTOM: + case PROP_CLIP_LEFT: + if ((nsnull != mPosition) && (nsnull != mPosition->mClip)) { + switch(aProperty) { + case PROP_CLIP_TOP: aValue = mPosition->mClip->mTop; break; + case PROP_CLIP_RIGHT: aValue = mPosition->mClip->mRight; break; + case PROP_CLIP_BOTTOM: aValue = mPosition->mClip->mBottom; break; + case PROP_CLIP_LEFT: aValue = mPosition->mClip->mLeft; break; + } + } + else { + aValue.Reset(); + } + break; + + // nsCSSList + case PROP_LIST_STYLE_TYPE: + case PROP_LIST_STYLE_IMAGE: + case PROP_LIST_STYLE_POSITION: + if (nsnull != mList) { + switch (aProperty) { + case PROP_LIST_STYLE_TYPE: aValue = mList->mType; break; + case PROP_LIST_STYLE_IMAGE: aValue = mList->mImage; break; + case PROP_LIST_STYLE_POSITION: aValue = mList->mPosition; break; + } + } + else { + aValue.Reset(); + } + break; + + case PROP_BACKGROUND: + case PROP_BORDER: + case PROP_CLIP: + case PROP_FONT: + case PROP_LIST_STYLE: + case PROP_MARGIN: + case PROP_PADDING: + case PROP_BACKGROUND_POSITION: + case PROP_BORDER_TOP: + case PROP_BORDER_RIGHT: + case PROP_BORDER_BOTTOM: + case PROP_BORDER_LEFT: + case PROP_BORDER_COLOR: + case PROP_BORDER_STYLE: + case PROP_BORDER_WIDTH: + NS_ERROR("can't query for shorthand properties"); + default: + result = NS_ERROR_ILLEGAL_VALUE; + break; + } + return result; +} + +void CSSDeclarationImpl::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + fputs("{ ", out); + + if (nsnull != mFont) { + mFont->List(out); + } + if (nsnull != mColor) { + mColor->List(out); + } + if (nsnull != mText) { + mText->List(out); + } + if (nsnull != mMargin) { + mMargin->List(out); + } + if (nsnull != mPosition) { + mPosition->List(out); + } + if (nsnull != mList) { + mList->List(out); + } + + fputs("}", out); +} + +NS_HTML nsresult + NS_NewCSSDeclaration(nsICSSDeclaration** aInstancePtrResult) +{ + if (aInstancePtrResult == nsnull) { + return NS_ERROR_NULL_POINTER; + } + + CSSDeclarationImpl *it = new CSSDeclarationImpl(); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(kICSSDeclarationIID, (void **) aInstancePtrResult); +} + + +/* +font +=========== + +'font-family', string (list) +'font-style', enum +'font-variant' enum (ie: small caps) +'font-weight' enum +'font-size' abs, pct, enum, +-1 + + +color/background +============= + +color: color +background-color: color +background-image: url(string) +background-repeat: enum +background-attachment: enum +background-position-x -y: abs, pct, enum (left/top center right/bottom (pct?)) + + + +text +======= +word-spacing: abs, "normal" +letter-spacing: abs, "normal" +text-decoration: enum +vertical-align: enum, pct +text-transform: enum +text-align: enum +text-indent: abs, pct +line-height: "normal", abs, pct, number-factor +white-space: enum + +margin +======= +margin-top -right -bottom -left: "auto", abs, pct +padding-top -right -bottom -left: abs, pct +border-top -right -bottom -left-width: enum, abs +border-top -right -bottom -left-color: color +border-top -right -bottom -left-style: enum + +size +======= +position: enum +width: abs, pct, "auto" +height: abs, pct, "auto" +left: abs, pct, "auto" +top: abs, pct, "auto" +clip: shape, "auto" (shape: rect - abs, auto) +overflow: enum +z-index: int, auto +visibity: enum + +float: enum +clear: enum + +display: enum + +filter: string + +list +======== +list-style-type: enum +list-style-image: url, "none" +list-style-position: enum (bool? in/out) + +*/ + + + diff --git a/mozilla/layout/html/style/src/nsCSSKeywordIDs.h b/mozilla/layout/html/style/src/nsCSSKeywordIDs.h new file mode 100644 index 00000000000..35b51399756 --- /dev/null +++ b/mozilla/layout/html/style/src/nsCSSKeywordIDs.h @@ -0,0 +1,88 @@ +/* Do not edit - generated by genhash.pl */ +#define KEYWORD_ABSOLUTE 0 +#define KEYWORD_AUTO 1 +#define KEYWORD_BASELINE 2 +#define KEYWORD_BLINK 3 +#define KEYWORD_BLOCK 4 +#define KEYWORD_BOLD 5 +#define KEYWORD_BOLDER 6 +#define KEYWORD_BOTH 7 +#define KEYWORD_BOTTOM 8 +#define KEYWORD_CAPITALIZE 9 +#define KEYWORD_CENTER 10 +#define KEYWORD_CIRCLE 11 +#define KEYWORD_CM 12 +#define KEYWORD_DASHED 13 +#define KEYWORD_DECIMAL 14 +#define KEYWORD_DISC 15 +#define KEYWORD_DOTTED 16 +#define KEYWORD_DOUBLE 17 +#define KEYWORD_EM 18 +#define KEYWORD_EX 19 +#define KEYWORD_FIXED 20 +#define KEYWORD_GROOVE 21 +#define KEYWORD_HIDDEN 22 +#define KEYWORD_IN 23 +#define KEYWORD_INHERIT 24 +#define KEYWORD_INLINE 25 +#define KEYWORD_INSET 26 +#define KEYWORD_INSIDE 27 +#define KEYWORD_ITALIC 28 +#define KEYWORD_JUSTIFY 29 +#define KEYWORD_LARGE 30 +#define KEYWORD_LARGER 31 +#define KEYWORD_LEFT 32 +#define KEYWORD_LIGHTER 33 +#define KEYWORD_LINE_THROUGH 34 +#define KEYWORD_LIST_ITEM 35 +#define KEYWORD_LOWER_ALPHA 36 +#define KEYWORD_LOWER_ROMAN 37 +#define KEYWORD_LOWERCASE 38 +#define KEYWORD_MEDIUM 39 +#define KEYWORD_MIDDLE 40 +#define KEYWORD_MM 41 +#define KEYWORD_NO_REPEAT 42 +#define KEYWORD_NONE 43 +#define KEYWORD_NORMAL 44 +#define KEYWORD_NOSHADE 45 +#define KEYWORD_NOWRAP 46 +#define KEYWORD_OBLIQUE 47 +#define KEYWORD_OUTSET 48 +#define KEYWORD_OUTSIDE 49 +#define KEYWORD_OVERLINE 50 +#define KEYWORD_PARAGRAPH 51 +#define KEYWORD_PC 52 +#define KEYWORD_PRE 53 +#define KEYWORD_PT 54 +#define KEYWORD_PX 55 +#define KEYWORD_RELATIVE 56 +#define KEYWORD_REPEAT 57 +#define KEYWORD_REPEAT_X 58 +#define KEYWORD_REPEAT_Y 59 +#define KEYWORD_RIDGE 60 +#define KEYWORD_RIGHT 61 +#define KEYWORD_SCROLL 62 +#define KEYWORD_SMALL 63 +#define KEYWORD_SMALL_CAPS 64 +#define KEYWORD_SMALLER 65 +#define KEYWORD_SOLID 66 +#define KEYWORD_SQUARE 67 +#define KEYWORD_STATIC 68 +#define KEYWORD_SUB 69 +#define KEYWORD_SUPER 70 +#define KEYWORD_TEXT_BOTTOM 71 +#define KEYWORD_TEXT_TOP 72 +#define KEYWORD_THICK 73 +#define KEYWORD_THIN 74 +#define KEYWORD_TOP 75 +#define KEYWORD_TRANSPARENT 76 +#define KEYWORD_UNDERLINE 77 +#define KEYWORD_UPPER_ALPHA 78 +#define KEYWORD_UPPER_ROMAN 79 +#define KEYWORD_UPPERCASE 80 +#define KEYWORD_VISIBLE 81 +#define KEYWORD_X_LARGE 82 +#define KEYWORD_X_SMALL 83 +#define KEYWORD_XX_LARGE 84 +#define KEYWORD_XX_SMALL 85 +#define KEYWORD_MAX 86 diff --git a/mozilla/layout/html/style/src/nsCSSKeywords.cpp b/mozilla/layout/html/style/src/nsCSSKeywords.cpp new file mode 100644 index 00000000000..e5f8c9b2654 --- /dev/null +++ b/mozilla/layout/html/style/src/nsCSSKeywords.cpp @@ -0,0 +1,389 @@ + +/* +** This is a generated file, do not edit it. This file is created by +** genhash.pl +*/ + +#include "plstr.h" +#include "nsCSSKeywords.h" +#define TOTAL_KEYWORDS 86 +#define MIN_WORD_LENGTH 2 +#define MAX_WORD_LENGTH 12 +#define MIN_HASH_VALUE 8 +#define MAX_HASH_VALUE 322 +/* maximum key range = 315, duplicates = 0 */ + + +struct StaticNameTable { + char* tag; + PRInt32 id; +}; + +static const unsigned char kLowerLookup[256] = { + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, + 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, + 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, + 64, + 97,98,99,100,101,102,103,104,105,106,107,108,109, + 110,111,112,113,114,115,116,117,118,119,120,121,122, + + 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, + + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 +}; + +#define MYLOWER(x) kLowerLookup[((x) & 0x7f)] + +/** + * Map a name to an ID or -1 + */ +PRInt32 nsCSSKeywords::LookupName(const char* str) +{ + static unsigned short asso_values[] = + { + 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 15, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 323, 323, 5, 125, 115, + 35, 0, 5, 55, 60, 110, 0, 5, 0, 5, + 75, 0, 90, 5, 0, 25, 0, 27, 0, 90, + 10, 0, 323, 323, 323, 323, 323, 323, + }; + static unsigned char lengthtable[] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 8, 4, 5, 6, 2, 0, + 0, 0, 0, 2, 0, 0, 0, 11, 2, 0, 0, 0, 11, 0, + 0, 0, 0, 0, 7, 6, 7, 0, 4, 0, 0, 0, 5, 0, + 7, 8, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, + 0, 7, 0, 7, 0, 6, 0, 6, 0, 5, 0, 0, 6, 0, + 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 6, 0, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0, 6, 0, + 8, 9, 0, 0, 0, 0, 9, 0, 6, 7, 8, 0, 0, 11, + 2, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, + 0, 2, 0, 0, 0, 6, 7, 0, 0, 5, 6, 0, 0, 0, + 0, 0, 7, 0, 0, 0, 6, 5, 0, 9, 5, 6, 0, 0, + 4, 0, 6, 7, 0, 0, 0, 0, 0, 8, 4, 5, 0, 0, + 0, 9, 5, 0, 7, 0, 0, 0, 11, 0, 0, 0, 5, 0, + 0, 3, 0, 10, 0, 0, 0, 4, 0, 6, 0, 0, 0, 0, + 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 5, 6, 0, 0, 0, 10, 9, 0, 0, + 0, 0, 0, 0, 11, 0, 0, 6, 0, 0, 0, 0, 6, 0, + 8, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 4, 0, 0, + 7, 0, 0, 0, 9, 0, 0, 0, 0, 6, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 6, 0, 0, 4, 0, 0, 0, 11, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, + 2, + }; + static struct StaticNameTable wordlist[] = + { + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"relative", 56}, + {"left", 32}, + {"large", 30}, + {"larger", 31}, + {"em", 18}, + {"",}, {"",}, {"",}, {"",}, + {"mm", 41}, + {"",}, {"",}, {"",}, + {"transparent", 76}, + {"ex", 19}, + {"",}, {"",}, {"",}, + {"text-bottom", 71}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"x-large", 82}, + {"outset", 48}, + {"outside", 49}, + {"",}, + {"auto", 1}, + {"",}, {"",}, {"",}, + {"small", 63}, + {"",}, + {"smaller", 65}, + {"xx-small", 85}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"medium", 39}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"x-small", 83}, + {"",}, + {"justify", 29}, + {"",}, + {"groove", 21}, + {"",}, + {"square", 67}, + {"",}, + {"solid", 66}, + {"",}, {"",}, + {"double", 17}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"dotted", 16}, + {"",}, {"",}, {"",}, {"",}, + {"normal", 44}, + {"",}, + {"overline", 50}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"pt", 54}, + {"pre", 53}, + {"",}, {"",}, + {"repeat", 57}, + {"",}, + {"xx-large", 84}, + {"no-repeat", 42}, + {"",}, {"",}, {"",}, {"",}, + {"lowercase", 38}, + {"",}, + {"dashed", 13}, + {"noshade", 45}, + {"text-top", 72}, + {"",}, {"",}, + {"lower-alpha", 36}, + {"px", 55}, + {"repeat-y", 59}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"repeat-x", 58}, + {"",}, {"",}, {"",}, + {"cm", 12}, + {"",}, {"",}, {"",}, + {"bolder", 6}, + {"oblique", 47}, + {"",}, {"",}, + {"block", 4}, + {"bottom", 8}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"visible", 81}, + {"",}, {"",}, {"",}, + {"scroll", 62}, + {"super", 70}, + {"",}, + {"list-item", 35}, + {"ridge", 60}, + {"static", 68}, + {"",}, {"",}, + {"none", 43}, + {"",}, + {"middle", 40}, + {"decimal", 14}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"absolute", 0}, + {"bold", 5}, + {"fixed", 20}, + {"",}, {"",}, {"",}, + {"paragraph", 51}, + {"right", 61}, + {"",}, + {"lighter", 33}, + {"",}, {"",}, {"",}, + {"lower-roman", 37}, + {"",}, {"",}, {"",}, + {"thick", 73}, + {"",}, {"",}, + {"top", 75}, + {"",}, + {"small-caps", 64}, + {"",}, {"",}, {"",}, + {"both", 7}, + {"",}, + {"inline", 25}, + {"",}, {"",}, {"",}, {"",}, + {"center", 10}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + + {"inset", 26}, + {"inside", 27}, + {"",}, {"",}, {"",}, + {"capitalize", 9}, + {"uppercase", 80}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"upper-alpha", 78}, + {"",}, {"",}, + {"circle", 11}, + {"",}, {"",}, {"",}, {"",}, + {"italic", 28}, + {"",}, + {"baseline", 2}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"blink", 3}, + {"",}, {"",}, {"",}, + {"thin", 74}, + {"",}, {"",}, + {"inherit", 24}, + {"",}, {"",}, {"",}, + {"underline", 77}, + {"",}, {"",}, {"",}, {"",}, + {"nowrap", 46}, + {"in", 23}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"hidden", 22}, + {"",}, {"",}, + {"disc", 15}, + {"",}, {"",}, {"",}, + {"upper-roman", 79}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, + {"sub", 69}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, + {"line-through", 34}, + {"",}, {"",}, {"",}, {"",}, + {"pc", 52}, + }; + + if (str != NULL) { + int len = PL_strlen(str); + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) { + register int hval = len; + + switch (hval) + { + default: + case 7: + hval += asso_values[MYLOWER(str[6])]; + case 6: + case 5: + case 4: + case 3: + hval += asso_values[MYLOWER(str[2])]; + case 2: + hval += asso_values[MYLOWER(str[1])]; + case 1: + hval += asso_values[MYLOWER(str[0])]; + break; + } + hval += asso_values[MYLOWER(str[len - 1])]; + if (hval <= MAX_HASH_VALUE && hval >= MIN_HASH_VALUE) { + if (len == lengthtable[hval]) { + register const char *tag = wordlist[hval].tag; + + /* + ** While not at the end of the string, if they ever differ + ** they are not equal. We know "tag" is already lower case. + */ + while ((*tag != '\0')&&(*str != '\0')) { + if (*tag != (char) MYLOWER(*str)) { + return -1; + } + tag++; + str++; + } + + /* + ** One of the strings has ended, if they are both ended, then they + ** are equal, otherwise not. + */ + if ((*tag == '\0')&&(*str == '\0')) { + return wordlist[hval].id; + } + } + } + } + } + return -1; +} + +const nsCSSKeywords::NameTableEntry nsCSSKeywords::kNameTable[] = { + { "absolute", 0 }, + { "auto", 1 }, + { "baseline", 2 }, + { "blink", 3 }, + { "block", 4 }, + { "bold", 5 }, + { "bolder", 6 }, + { "both", 7 }, + { "bottom", 8 }, + { "capitalize", 9 }, + { "center", 10 }, + { "circle", 11 }, + { "cm", 12 }, + { "dashed", 13 }, + { "decimal", 14 }, + { "disc", 15 }, + { "dotted", 16 }, + { "double", 17 }, + { "em", 18 }, + { "ex", 19 }, + { "fixed", 20 }, + { "groove", 21 }, + { "hidden", 22 }, + { "in", 23 }, + { "inherit", 24 }, + { "inline", 25 }, + { "inset", 26 }, + { "inside", 27 }, + { "italic", 28 }, + { "justify", 29 }, + { "large", 30 }, + { "larger", 31 }, + { "left", 32 }, + { "lighter", 33 }, + { "line-through", 34 }, + { "list-item", 35 }, + { "lower-alpha", 36 }, + { "lower-roman", 37 }, + { "lowercase", 38 }, + { "medium", 39 }, + { "middle", 40 }, + { "mm", 41 }, + { "no-repeat", 42 }, + { "none", 43 }, + { "normal", 44 }, + { "noshade", 45 }, + { "nowrap", 46 }, + { "oblique", 47 }, + { "outset", 48 }, + { "outside", 49 }, + { "overline", 50 }, + { "paragraph", 51 }, + { "pc", 52 }, + { "pre", 53 }, + { "pt", 54 }, + { "px", 55 }, + { "relative", 56 }, + { "repeat", 57 }, + { "repeat-x", 58 }, + { "repeat-y", 59 }, + { "ridge", 60 }, + { "right", 61 }, + { "scroll", 62 }, + { "small", 63 }, + { "small-caps", 64 }, + { "smaller", 65 }, + { "solid", 66 }, + { "square", 67 }, + { "static", 68 }, + { "sub", 69 }, + { "super", 70 }, + { "text-bottom", 71 }, + { "text-top", 72 }, + { "thick", 73 }, + { "thin", 74 }, + { "top", 75 }, + { "transparent", 76 }, + { "underline", 77 }, + { "upper-alpha", 78 }, + { "upper-roman", 79 }, + { "uppercase", 80 }, + { "visible", 81 }, + { "x-large", 82 }, + { "x-small", 83 }, + { "xx-large", 84 }, + { "xx-small", 85 }, +}; diff --git a/mozilla/layout/html/style/src/nsCSSKeywords.h b/mozilla/layout/html/style/src/nsCSSKeywords.h new file mode 100644 index 00000000000..1db3cbe5ee3 --- /dev/null +++ b/mozilla/layout/html/style/src/nsCSSKeywords.h @@ -0,0 +1,40 @@ +/* -*- 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. + */ +#ifndef nsCSSKeywords_h___ +#define nsCSSKeywords_h___ + +#include "nslayout.h" +#include "nsCSSKeywordIDs.h" + +class NS_LAYOUT nsCSSKeywords { +public: + // Given a null terminated string of 7 bit characters, return the + // tag id (see nsHTMLTagIDs.h) for the tag or -1 if the tag is not + // known. The lookup function uses a perfect hash. + static PRInt32 LookupName(const char* str); + + struct NameTableEntry { + const char* name; + PRInt32 id; + }; + + // A table whose index is the tag id (from LookupName) + static const NameTableEntry kNameTable[]; +}; + +#endif /* nsCSSKeywords_h___ */ diff --git a/mozilla/layout/html/style/src/nsCSSLayout.cpp b/mozilla/layout/html/style/src/nsCSSLayout.cpp new file mode 100644 index 00000000000..b21ce611ba6 --- /dev/null +++ b/mozilla/layout/html/style/src/nsCSSLayout.cpp @@ -0,0 +1,229 @@ +/* -*- 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 "nsCSSLayout.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsIContent.h" +#include "nsIFrame.h" +#include "nsIFontMetrics.h" +#include "nsIPresContext.h" +#include "nsRect.h" + +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); + +// XXX what about ebina's center vs. ncsa-center? +/* + * Notes: It's a known fact that this doesn't do what ebina's layout + * engine does because his code did vertical alignment on the + * fly. Hopefully that's ok because his code generated surprising + * results in a number of unusual cases. + */ +nscoord nsCSSLayout::VerticallyAlignChildren(nsIPresContext* aCX, + nsIFrame* aContainer, + nsStyleFont* aContainerFont, + nscoord aY0, + nsIFrame* aFirstChild, + PRIntn aChildCount, + nscoord* aAscents, + nscoord aMaxAscent) +{ + // Determine minimum and maximum y values for the line and + // perform alignment of all children except those requesting bottom + // alignment. The second pass will align bottom children (if any) + nsIFontMetrics* fm = aCX->GetMetricsFor(aContainerFont->mFont); + nsIFrame* kid = aFirstChild; + nsRect kidRect; + nscoord minY = aY0; + nscoord maxY = aY0; + PRIntn bottomAlignKids = 0; + PRIntn kidCount = aChildCount; + while (--kidCount >= 0) { + nscoord kidAscent = *aAscents++; + nsIStyleContext* kidSC = kid->GetStyleContext(aCX); + nsIContent* kidContent = kid->GetContent(); + nsStyleMolecule* kidMol = + (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + PRIntn verticalAlign = kidMol->verticalAlign; + float verticalAlignPct = kidMol->verticalAlignPct; + NS_RELEASE(kidSC); + NS_RELEASE(kidContent); + + kid->GetRect(kidRect); + + // Vertically align the child + nscoord kidYTop = 0; + switch (verticalAlign) { + default: + case NS_STYLE_VERTICAL_ALIGN_BASELINE: + // Align the kid's baseline at the max baseline + kidYTop = aMaxAscent - kidAscent; + break; + + case NS_STYLE_VERTICAL_ALIGN_TOP: + // Align the top of the kid with the top of the line box + break; + + case NS_STYLE_VERTICAL_ALIGN_SUB: + // Move baseline by 1/2 the ascent of the child. + // NOTE: CSSx doesn't seem to specify what subscripting does + // so we are using ebina's logic + kidYTop = aMaxAscent + (kidAscent/2) - kidAscent; + break; + + case NS_STYLE_VERTICAL_ALIGN_SUPER: + // Move baseline by 1/2 the ascent of the child + // NOTE: CSSx doesn't seem to specify what superscripting does + // so we are using ebina's logic + kidYTop = aMaxAscent - (kidAscent/2) - kidAscent; + break; + + case NS_STYLE_VERTICAL_ALIGN_BOTTOM: + bottomAlignKids++; + break; + + case NS_STYLE_VERTICAL_ALIGN_MIDDLE: + kidYTop = aMaxAscent - (fm->GetHeight(/*'x'XXX */) / 2) - kidRect.height/2; + break; + + case NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM: + kidYTop = aMaxAscent + fm->GetMaxDescent() - kidRect.height; + break; + + case NS_STYLE_VERTICAL_ALIGN_TEXT_TOP: + kidYTop = aMaxAscent - fm->GetMaxAscent(); + break; + + case NS_STYLE_VERTICAL_ALIGN_LENGTH: + // XXX css2 hasn't yet specified what this means! + break; + + case NS_STYLE_VERTICAL_ALIGN_PCT: + // XXX need kidMol->lineHeight in translated to a value form... + break; + } + + // Place kid and update min and max Y values + nscoord y = aY0 + kidYTop; + if (y < minY) minY = y; + kid->MoveTo(kidRect.x, y); + y += kidRect.height; + if (y > maxY) maxY = y; + + kid = kid->GetNextSibling(); + } + + nscoord lineHeight = maxY - minY; + + if (0 != bottomAlignKids) { + // Position all of the bottom aligned children + kidCount = aChildCount; + kid = aFirstChild; + while (--kidCount >= 0) { + // Get kid's vertical align style data + nsIStyleContext* kidSC = kid->GetStyleContext(aCX); + nsIContent* kidContent = kid->GetContent(); + nsStyleMolecule* kidMol = + (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + PRIntn verticalAlign = kidMol->verticalAlign; + NS_RELEASE(kidSC); + NS_RELEASE(kidContent); + + // Vertically align the child + if (verticalAlign == NS_STYLE_VERTICAL_ALIGN_BOTTOM) { + // Place kid along the bottom + kid->GetRect(kidRect); + kid->MoveTo(kidRect.x, aY0 + lineHeight - kidRect.height); + if (--bottomAlignKids == 0) { + // Stop on lost bottom aligned kid + break; + } + } + + kid = kid->GetNextSibling(); + } + } + + NS_RELEASE(fm); + return lineHeight; +} + +/** + * Horizontally place the children in the container frame. + */ +void nsCSSLayout::HorizontallyPlaceChildren(nsIPresContext* aCX, + nsIFrame* aContainer, + nsStyleMolecule* aContainerStyle, + nsIFrame* aFirstChild, + PRInt32 aChildCount, + nscoord aLineWidth, + nscoord aMaxWidth) +{ + PRIntn textAlign = aContainerStyle->textAlign; + + nscoord dx = 0; + switch (textAlign) { + case NS_STYLE_TEXT_ALIGN_LEFT: + case NS_STYLE_TEXT_ALIGN_JUSTIFY: + // Default layout has everything aligned left + return; + + case NS_STYLE_TEXT_ALIGN_RIGHT: + dx = aMaxWidth - aLineWidth; + break; + + case NS_STYLE_TEXT_ALIGN_CENTER: + dx = (aMaxWidth - aLineWidth) / 2; + break; + } + + // Position children + nsPoint origin; + nsIFrame* kid = aFirstChild; + while (--aChildCount >= 0) { + kid->GetOrigin(origin); + kid->MoveTo(origin.x + dx, origin.y); + kid = kid->GetNextSibling(); + } +} + +/** + * Apply css relative positioning to any child that requires it. + */ +void nsCSSLayout::RelativePositionChildren(nsIPresContext* aCX, + nsIFrame* aContainer, + nsStyleMolecule* aContainerStyle, + nsIFrame* aFirstChild, + PRInt32 aChildCount) +{ + nsPoint origin; + nsIFrame* kid = aFirstChild; + while (--aChildCount >= 0) { + nsIContent* kidContent = kid->GetContent(); + nsIStyleContext* kidSC = kid->GetStyleContext(aCX); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + if (NS_STYLE_POSITION_RELATIVE == kidMol->positionFlags) { + kid->GetOrigin(origin); + nscoord dx = kidMol->left; + nscoord dy = kidMol->top; + kid->MoveTo(origin.x + dx, origin.y + dy); + } + NS_RELEASE(kidContent); + NS_RELEASE(kidSC); + kid = kid->GetNextSibling(); + } +} diff --git a/mozilla/layout/html/style/src/nsCSSLayout.h b/mozilla/layout/html/style/src/nsCSSLayout.h new file mode 100644 index 00000000000..2b6e8ff2f6d --- /dev/null +++ b/mozilla/layout/html/style/src/nsCSSLayout.h @@ -0,0 +1,63 @@ +/* -*- 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. + */ +#ifndef nsCSSLayout_h___ +#define nsCSSLayout_h___ + +#include "nsCoord.h" +class nsIPresContext; +struct nsStyleFont; +struct nsStyleMolecule; +class nsIFrame; + +class nsCSSLayout { +public: + /** + * Perform vertical alignment ala CSS. Return the height of the + * line. + */ + static nscoord VerticallyAlignChildren(nsIPresContext* aPresContext, + nsIFrame* aContainer, + nsStyleFont* aContainerFont, + nscoord aY0, + nsIFrame* aFirstChild, + PRInt32 aChildCount, + nscoord* aAscents, + nscoord aMaxAscent); + + /** + * Perform horizontal alignment ala CSS. + */ + static void HorizontallyPlaceChildren(nsIPresContext* aPresContext, + nsIFrame* aContainer, + nsStyleMolecule* aContainerStyle, + nsIFrame* aFirstChild, + PRInt32 aChildCount, + nscoord aLineWidth, + nscoord aMaxWidth); + + /** + * Perform relative positioning ala CSS + */ + static void RelativePositionChildren(nsIPresContext* aPresContext, + nsIFrame* aContainer, + nsStyleMolecule* aContainerStyle, + nsIFrame* aFirstChild, + PRInt32 aChildCount); +}; + +#endif /* nsCSSLayout_h___ */ diff --git a/mozilla/layout/html/style/src/nsCSSParser.cpp b/mozilla/layout/html/style/src/nsCSSParser.cpp new file mode 100644 index 00000000000..79220097b2c --- /dev/null +++ b/mozilla/layout/html/style/src/nsCSSParser.cpp @@ -0,0 +1,2186 @@ +/* -*- 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 "nsICSSParser.h" +#include "nsCSSProps.h" +#include "nsCSSKeywords.h" +#include "nsCSSScanner.h" +#include "nsICSSStyleRule.h" +#include "nsIUnicharInputStream.h" +#include "nsIStyleSet.h" +#include "nsICSSStyleSheet.h" +#include "nsICSSDeclaration.h" +#include "nsStyleConsts.h" +#include "nsIURL.h" +#include "nsString.h" +#include "nsIAtom.h" +#include "nsVoidArray.h" +#include "nsColor.h" + +static NS_DEFINE_IID(kICSSParserIID, NS_ICSS_PARSER_IID); +static NS_DEFINE_IID(kICSSStyleSheetIID, NS_ICSS_STYLE_SHEET_IID); +static NS_DEFINE_IID(kIStyleSheetIID, NS_ISTYLE_SHEET_IID); + +// XXX url's spec'd in a style sheet are relative to the style sheet +// (this includes things like background-image!). +// XXX cell-padding, spacing, etc.??? + +struct Selector { + nsString mTag; // weight 1 + nsString mID; // weight 100 + nsString mClass; // weight 10 + nsString mPseudo; // weight 10 (== class) + PRUint32 mMask; // which fields have values + + Selector(); + ~Selector(); + + PRInt32 Weight() const; +#ifdef NS_DEBUG + void Dump() const; +#endif +}; + +#define SELECTOR_TAG 0x1 +#define SELECTOR_ID 0x2 +#define SELECTOR_CLASS 0x4 +#define SELECTOR_PSEUDO 0x8 + +#define SELECTOR_WEIGHT_BASE 10 + +Selector::Selector() +{ + mMask = 0; +} + +Selector::~Selector() +{ +} + +PRInt32 Selector::Weight() const +{ + return (((0 != (SELECTOR_TAG & mMask)) ? 1 : 0) + + ((0 != (SELECTOR_ID & mMask)) ? (SELECTOR_WEIGHT_BASE * SELECTOR_WEIGHT_BASE) : 0) + + ((0 != ((SELECTOR_CLASS | SELECTOR_PSEUDO) & mMask)) ? SELECTOR_WEIGHT_BASE : 0)); +} + +#ifdef NS_DEBUG +void Selector::Dump() const +{ + PRBool needSpace = PR_FALSE; + if (mTag.Length() > 0) { + fputs(mTag, stdout); + needSpace = PR_TRUE; + } + if (mID.Length() > 0) { + if (needSpace) fputs(" ", stdout); + fputs("#", stdout); + fputs(mID, stdout); + needSpace = PR_TRUE; + } + if (mClass.Length() > 0) { + if (needSpace) fputs(" ", stdout); + fputs(".", stdout); + fputs(mClass, stdout); + needSpace = PR_TRUE; + } + if (mPseudo.Length() > 0) { + if (needSpace) fputs(" ", stdout); + fputs(":", stdout); + fputs(mPseudo, stdout); + needSpace = PR_TRUE; + } +} +#endif + +// e.g. "P B, H1 B { ... }" has a selector list with two elements, +// each of which has two selectors. +struct SelectorList { + SelectorList* mNext; + nsVoidArray mSelectors; + + SelectorList(); + + void Destroy(); + + void AddSelector(Selector* aSelector) { + mSelectors.AppendElement(aSelector); + } + +#ifdef NS_DEBUG + void Dump(); +#endif + +private: + ~SelectorList(); +}; + +SelectorList::SelectorList() +{ + mNext = nsnull; +} + +SelectorList::~SelectorList() +{ + PRInt32 n = mSelectors.Count(); + for (PRInt32 i = 0; i < n; i++) { + Selector* sel = (Selector*) mSelectors.ElementAt(i); + delete sel; + } +} + +void SelectorList::Destroy() +{ + SelectorList* list = this; + while (nsnull != list) { + SelectorList* next = list->mNext; + delete list; + list = next; + } +} + +#ifdef NS_DEBUG +void SelectorList::Dump() +{ + PRInt32 n = mSelectors.Count(); + for (PRInt32 i = 0; i < n; i++) { + Selector* sel = (Selector*) mSelectors.ElementAt(i); + sel->Dump(); + fputs(" ", stdout); + } + if (mNext) { + fputs(", ", stdout); + mNext->Dump(); + } +} +#endif + +//---------------------------------------------------------------------- + +// Your basic top-down recursive descent style parser +class CSSParserImpl : public nsICSSParser { +public: + CSSParserImpl(); + CSSParserImpl(nsICSSStyleSheet* aSheet); + ~CSSParserImpl(); + + NS_DECL_ISUPPORTS + + virtual PRUint32 GetInfoMask(); + + virtual nsresult SetStyleSheet(nsIStyleSheet* aSheet); + + virtual nsIStyleSheet* Parse(PRInt32* aErrorCode, + nsIUnicharInputStream* aInput, + nsIURL* aInputURL); + +protected: + PRBool GetToken(PRInt32* aErrorCode, PRBool aSkipWS); + void UngetToken(); + + PRBool ExpectSymbol(PRInt32* aErrorCode, char aSymbol, PRBool aSkipWS); + nsString* NextIdent(PRInt32* aErrorCode); + void SkipUntil(PRInt32* aErrorCode, PRUnichar aStopSymbol); + void SkipRuleSet(PRInt32* aErrorCode); + void SkipDeclaration(PRInt32* aErrorCode); + + PRBool ParseRuleSet(PRInt32* aErrorCode); + PRBool ParseAtRule(PRInt32* aErrorCode); + PRBool ParseImportRule(PRInt32* aErrorCode); + + PRBool ParseSelectorGroup(PRInt32* aErrorCode, SelectorList* aListHead); + PRBool ParseSelectorList(PRInt32* aErrorCode, SelectorList* aListHead); + PRBool ParseSelector(PRInt32* aErrorCode, Selector* aSelectorResult); + nsICSSDeclaration* ParseDeclarationBlock(PRInt32* aErrorCode); + PRBool ParseDeclaration(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration); + PRBool ParseProperty(PRInt32* aErrorCode, const char* aName, + nsICSSDeclaration* aDeclaration); + PRBool ParseProperty(PRInt32* aErrorCode, const char* aName, + nsICSSDeclaration* aDeclaration, PRInt32 aID); + + // Property specific parsing routines + PRBool ParseBackground(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration); + PRBool ParseBackgroundFilter(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName); + PRBool ParseForegroundFilter(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName); + PRBool ParseBackgroundPosition(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName); + PRBool ParseBorder(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration); + PRBool ParseBorderColor(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration); + PRBool ParseBorderSide(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aNames[], PRInt32 aWhichSide); + PRBool ParseBorderStyle(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration); + PRBool ParseBorderWidth(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration); + PRBool ParseClip(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration); + PRBool ParseFont(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName); + PRBool ParseFontFamily(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName); + PRBool ParseFontWeight(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName); + PRBool ParseListStyle(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration); + PRBool ParseMargin(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration); + PRBool ParsePadding(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration); + PRBool ParseTextDecoration(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName); + + // Reused utility parsing routines + PRBool ParseBoxProperties(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aNames[]); + PRInt32 ParseChoice(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aNames[], PRInt32 aNumNames); + PRBool ParseColor(PRInt32* aErrorCode, nscolor* aColorResult); + PRBool ParseColorComponent(PRInt32* aErrorCode, PRUint8* aComponent, + char aStop); + PRBool ParseEnum(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName, PRInt32* aTable); + PRInt32 SearchKeywordTable(PRInt32 aID, PRInt32 aTable[]); + PRBool ParseVariant(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName, PRInt32 aVariant, + PRInt32* aTable); + PRBool TranslateLength(nsICSSDeclaration* aDeclaration, const char* aName, + float aNumber, const nsString& aDimension); + + void ProcessImport(const nsString& aURLSpec); + + // Current token. The value is valid after calling GetToken + nsCSSToken mToken; + + // After an UngetToken is done this flag is true. The next call to + // GetToken clears the flag. + PRBool mHavePushBack; + + nsCSSScanner* mScanner; + nsIURL* mURL; + nsICSSStyleSheet* mSheet; + + PRBool mInHead; +}; + +NS_HTML nsresult +NS_NewCSSParser(nsICSSParser** aInstancePtrResult) +{ + CSSParserImpl *it = new CSSParserImpl(); + + if (it == nsnull) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(kICSSParserIID, (void **) aInstancePtrResult); +} + +CSSParserImpl::CSSParserImpl() +{ + NS_INIT_REFCNT(); + mScanner = nsnull; + mSheet = nsnull; + mHavePushBack = PR_FALSE; +} + +CSSParserImpl::CSSParserImpl(nsICSSStyleSheet* aSheet) +{ + NS_INIT_REFCNT(); + mScanner = nsnull; + mSheet = aSheet; aSheet->AddRef(); + mHavePushBack = PR_FALSE; +} + +NS_IMPL_ISUPPORTS(CSSParserImpl,kICSSParserIID) + +CSSParserImpl::~CSSParserImpl() +{ + NS_IF_RELEASE(mSheet); +} + +PRUint32 CSSParserImpl::GetInfoMask() +{ + return NS_CSS_GETINFO_CSS1 | NS_CSS_GETINFO_CSSP; +} + +nsresult CSSParserImpl::SetStyleSheet(nsIStyleSheet* aSheet) +{ + NS_PRECONDITION(nsnull != aSheet, "null ptr"); + if (nsnull == aSheet) { + return NS_ERROR_NULL_POINTER; + } + + // Make sure the sheet supports the correct interface! + static NS_DEFINE_IID(kICSSStyleSheetIID, NS_ICSS_STYLE_SHEET_IID); + nsICSSStyleSheet* cssSheet; + nsresult rv = aSheet->QueryInterface(kICSSStyleSheetIID, (void**)&cssSheet); + if (NS_OK != rv) { + return rv; + } + + // Switch to using the new sheet + NS_IF_RELEASE(mSheet); + mSheet = cssSheet; + + return NS_OK; +} + +nsIStyleSheet* CSSParserImpl::Parse(PRInt32* aErrorCode, + nsIUnicharInputStream* aInput, + nsIURL* aInputURL) +{ + if (nsnull == mSheet) { + NS_NewCSSStyleSheet(&mSheet, aInputURL); + } + + mScanner = new nsCSSScanner(); + mScanner->Init(aInput); + mURL = aInputURL; + if (nsnull != aInputURL) { + aInputURL->AddRef(); + } + mInHead = PR_TRUE; + nsCSSToken* tk = &mToken; + for (;;) { + // Get next non-whitespace token + if (!GetToken(aErrorCode, PR_TRUE)) { + break; + } + if (eCSSToken_AtKeyword == tk->mType) { + ParseAtRule(aErrorCode); + continue; + } else if (eCSSToken_Symbol == tk->mType) { + // Discard dangling semicolons. This is not part of the CSS1 + // forward compatible parsing spec, but it makes alot of sense. + if (';' == tk->mSymbol) { + continue; + } + } + mInHead = PR_FALSE; + UngetToken(); + ParseRuleSet(aErrorCode); + } + delete mScanner; + mScanner = nsnull; + NS_IF_RELEASE(mURL); + + nsIStyleSheet* rv = nsnull; + mSheet->QueryInterface(kIStyleSheetIID, (void**)&rv); + return rv; +} + +//---------------------------------------------------------------------- + +PRBool CSSParserImpl::GetToken(PRInt32* aErrorCode, PRBool aSkipWS) +{ + for (;;) { + if (!mHavePushBack) { + if (!mScanner->Next(aErrorCode, &mToken)) { + break; + } + } + mHavePushBack = PR_FALSE; + if (aSkipWS && (eCSSToken_WhiteSpace == mToken.mType)) { + continue; + } + return PR_TRUE; + } + return PR_FALSE; +} + +void CSSParserImpl::UngetToken() +{ + NS_PRECONDITION(mHavePushBack == PR_FALSE, "double pushback"); + mHavePushBack = PR_TRUE; +} + +PRBool CSSParserImpl::ExpectSymbol(PRInt32* aErrorCode, + char aSymbol, + PRBool aSkipWS) +{ + if (!GetToken(aErrorCode, aSkipWS)) { + return PR_FALSE; + } + nsCSSToken* tk = &mToken; + if ((eCSSToken_Symbol == tk->mType) && (aSymbol == tk->mSymbol)) { + return PR_TRUE; + } + UngetToken(); + return PR_FALSE; +} + +nsString* CSSParserImpl::NextIdent(PRInt32* aErrorCode) +{ + if (!GetToken(aErrorCode, PR_TRUE)) { + return nsnull; + } + if (eCSSToken_Ident != mToken.mType) { + UngetToken(); + return nsnull; + } + return &mToken.mIdent; +} + +// XXX @media type {, types } '{' rules '}' +// XXX @font-face +// XXX @page { :left | :right } '{' declarations '}' +PRBool CSSParserImpl::ParseAtRule(PRInt32* aErrorCode) +{ + nsCSSToken* tk = &mToken; + if (mInHead && tk->mIdent.EqualsIgnoreCase("import")) { + ParseImportRule(aErrorCode); + return PR_TRUE; + } + + // Skip over unsupported at rule + for (;;) { + if (!GetToken(aErrorCode, PR_TRUE)) { + return PR_FALSE; + } + if (eCSSToken_Symbol == tk->mType) { + PRUnichar symbol = tk->mSymbol; + if (symbol == ';') { + break; + } + if (symbol == '{') { + SkipUntil(aErrorCode, '}'); + break; + } else if (symbol == '(') { + SkipUntil(aErrorCode, ')'); + } else if (symbol == '[') { + SkipUntil(aErrorCode, ']'); + } + } + } + mInHead = PR_FALSE; + return PR_TRUE; +} + +// Parse a CSS1 import rule: "@import STRING | URL" +PRBool CSSParserImpl::ParseImportRule(PRInt32* aErrorCode) +{ + nsCSSToken* tk = &mToken; + if (!GetToken(aErrorCode, PR_TRUE)) { + return PR_FALSE; + } + if ((eCSSToken_String == tk->mType) || (eCSSToken_URL == tk->mType)) { + if (ExpectSymbol(aErrorCode, ';', PR_TRUE)) { + ProcessImport(tk->mIdent); + return PR_TRUE; + } + if ((eCSSToken_Symbol != tk->mType) || (';' != tk->mSymbol)) { + SkipUntil(aErrorCode, ';'); + } + } + mInHead = PR_FALSE; + return PR_TRUE; +} + +void CSSParserImpl::ProcessImport(const nsString& aURLSpec) +{ + // XXX probably need a way to encode unicode junk for the part of + // the url that follows a "?" + char* cp = aURLSpec.ToNewCString(); + nsIURL* url; + nsresult rv = NS_NewURL(&url, mURL, cp); + delete cp; + if (NS_OK != rv) { + // import url is bad + // XXX log this somewhere for easier web page debugging + return; + } + + if (PR_FALSE == mSheet->ContainsStyleSheet(url)) { // don't allow circular references + + PRInt32 ec; + nsIInputStream* in = url->Open(&ec); + if (nsnull == in) { + // failure to make connection + // XXX log this somewhere for easier web page debugging + } + else { + + nsIUnicharInputStream* uin; + rv = NS_NewConverterStream(&uin, nsnull, in); + if (NS_OK != rv) { + // XXX no iso-latin-1 converter? out of memory? + NS_RELEASE(in); + } + else { + + NS_RELEASE(in); + + // Create a new parse to parse the import. + + if (NS_OK == rv) { + CSSParserImpl *parser = new CSSParserImpl(); + nsIStyleSheet* childSheet = parser->Parse(&ec, uin, url); + NS_RELEASE(parser); + if (nsnull != childSheet) { + nsICSSStyleSheet* cssChild = nsnull; + if (NS_OK == childSheet->QueryInterface(kICSSStyleSheetIID, (void**)&cssChild)) { + mSheet->AppendStyleSheet(cssChild); + NS_RELEASE(cssChild); + } + } + NS_RELEASE(childSheet); + } + NS_RELEASE(uin); + } + } + } + NS_RELEASE(url); +} + +void CSSParserImpl::SkipUntil(PRInt32* aErrorCode, PRUnichar aStopSymbol) +{ + nsCSSToken* tk = &mToken; + for (;;) { + if (!GetToken(aErrorCode, PR_TRUE)) { + break; + } + if (eCSSToken_Symbol == tk->mType) { + PRUnichar symbol = tk->mSymbol; + if (symbol == aStopSymbol) { + break; + } else if ('{' == symbol) { + SkipUntil(aErrorCode, '}'); + } else if ('[' == symbol) { + SkipUntil(aErrorCode, ']'); + } else if ('(' == symbol) { + SkipUntil(aErrorCode, ')'); + } + } + } +} + +void CSSParserImpl::SkipDeclaration(PRInt32* aErrorCode) +{ + nsCSSToken* tk = &mToken; + for (;;) { + if (!GetToken(aErrorCode, PR_TRUE)) { + break; + } + if (eCSSToken_Symbol == tk->mType) { + PRUnichar symbol = tk->mSymbol; + if (';' == symbol) { + break; + } + if ('}' == symbol) { + UngetToken(); + break; + } + if ('{' == symbol) { + SkipUntil(aErrorCode, '}'); + } else if ('(' == symbol) { + SkipUntil(aErrorCode, ')'); + } else if ('[' == symbol) { + SkipUntil(aErrorCode, ']'); + } + } + } +} + +void CSSParserImpl::SkipRuleSet(PRInt32* aErrorCode) +{ + nsCSSToken* tk = &mToken; + for (;;) { + if (!GetToken(aErrorCode, PR_TRUE)) { + break; + } + if (eCSSToken_Symbol == tk->mType) { + PRUnichar symbol = tk->mSymbol; + if ('{' == symbol) { + SkipUntil(aErrorCode, '}'); + break; + } + if ('(' == symbol) { + SkipUntil(aErrorCode, ')'); + } else if ('[' == symbol) { + SkipUntil(aErrorCode, ']'); + } + } + } +} + +PRBool CSSParserImpl::ParseRuleSet(PRInt32* aErrorCode) +{ + nsCSSToken* tk = &mToken; + + // First get the list of selectors for the rule + SelectorList *slist = new SelectorList(); + if (!ParseSelectorList(aErrorCode, slist)) { + SkipRuleSet(aErrorCode); + slist->Destroy(); + return PR_FALSE; + } + + // Next parse the declaration block + nsICSSDeclaration* declaration = ParseDeclarationBlock(aErrorCode); + if (nsnull == declaration) { + // XXX skip something here + slist->Destroy(); + return PR_FALSE; + } + +#if 0 + slist->Dump(); + fputs("{\n", stdout); + declaration->List(); + fputs("}\n", stdout); +#endif + + // Translate the selector list and declaration block into style data + + // XXX PSL working here + + SelectorList* list = slist; + nsCSSSelector selector; + nsICSSStyleRule* rule; + + while (nsnull != list) { + PRInt32 selIndex = list->mSelectors.Count(); + + Selector* sel = (Selector*)list->mSelectors[--selIndex]; + selector.Set(sel->mTag, sel->mID, sel->mClass, sel->mPseudo); + PRInt32 weight = sel->Weight(); + + if (NS_OK == NS_NewCSSStyleRule(&rule, selector)) { + while (--selIndex >= 0) { + Selector* sel = (Selector*)list->mSelectors[selIndex]; + selector.Set(sel->mTag, sel->mID, sel->mClass, sel->mPseudo); + + rule->AddSelector(selector); + weight += sel->Weight(); + } + rule->SetDeclaration(declaration); + rule->SetWeight(weight); +// rule->List(); + mSheet->AppendStyleRule(rule); + NS_RELEASE(rule); + } + + list = list->mNext; + } + + // XXX PSL working here + + // Release temporary storage + slist->Destroy(); + NS_RELEASE(declaration); + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseSelectorList(PRInt32* aErrorCode, + SelectorList* aListHead) +{ + if (!ParseSelectorGroup(aErrorCode, aListHead)) { + // must have at least one selector group + return PR_FALSE; + } + + // After that there must either be a "," or a "{" + nsCSSToken* tk = &mToken; + for (;;) { + if (!GetToken(aErrorCode, PR_TRUE)) { + return PR_FALSE; + } + if (eCSSToken_Symbol != tk->mType) { + UngetToken(); + return PR_FALSE; + } + if (',' == tk->mSymbol) { + // Another selector group must follow + SelectorList* newList = new SelectorList(); + if (!ParseSelectorGroup(aErrorCode, newList)) { + newList->Destroy(); + return PR_FALSE; + } + // add new list to the end of the selector list + aListHead->mNext = newList; + aListHead = newList; + continue; + } else if ('{' == tk->mSymbol) { + UngetToken(); + break; + } else { + UngetToken(); + return PR_FALSE; + } + } + + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseSelectorGroup(PRInt32* aErrorCode, + SelectorList* aList) +{ + for (;;) { + Selector* sel = new Selector(); + if (!ParseSelector(aErrorCode, sel)) { + delete sel; + break; + } + aList->AddSelector(sel); + } + return (PRBool) (aList->mSelectors.Count() > 0); +} + +/** + * These are the 15 possible kinds of CSS1 style selectors: + *
      + *
    • Tag + *
    • Tag#Id + *
    • Tag#Id.Class + *
    • Tag#Id.Class:Pseudo + *
    • Tag#Id:Pseudo + *
    • Tag.Class + *
    • Tag.Class:Pseudo + *
    • Tag:Pseudo + *
    • #Id + *
    • #Id.Class + *
    • #Id.Class:Pseudo + *
    • #Id:Pseudo + *
    • .Class + *
    • .Class:Pseudo + *
    • :Pseudo + *
    + */ +PRBool CSSParserImpl::ParseSelector(PRInt32* aErrorCode, + Selector* aSelectorResult) +{ + PRUint32 mask = 0; + aSelectorResult->mTag.SetLength(0); + aSelectorResult->mClass.SetLength(0); + aSelectorResult->mID.SetLength(0); + aSelectorResult->mPseudo.SetLength(0); + + nsCSSToken* tk = &mToken; + if (!GetToken(aErrorCode, PR_TRUE)) { + return PR_FALSE; + } + if (eCSSToken_Ident == tk->mType) { + // tag + mask |= SELECTOR_TAG; + aSelectorResult->mTag.Append(tk->mIdent); + if (!GetToken(aErrorCode, PR_FALSE)) { + // premature eof is ok (here!) + return PR_TRUE; + } + } + if (eCSSToken_ID == tk->mType) { + // #id + mask |= SELECTOR_ID; + aSelectorResult->mID.Append(tk->mIdent); + if (!GetToken(aErrorCode, PR_FALSE)) { + // premature eof is ok (here!) + return PR_TRUE; + } + } + if ((eCSSToken_Symbol == tk->mType) && ('.' == tk->mSymbol)) { + // .class + mask |= SELECTOR_CLASS; + if (!GetToken(aErrorCode, PR_FALSE)) { + return PR_FALSE; + } + if (eCSSToken_Ident != tk->mType) { + // malformed selector + UngetToken(); + return PR_FALSE; + } + aSelectorResult->mClass.Append(tk->mIdent); + if (!GetToken(aErrorCode, PR_FALSE)) { + // premature eof is ok (here!) + return PR_TRUE; + } + } + if ((eCSSToken_Symbol == tk->mType) && (':' == tk->mSymbol)) { + // :pseudo + mask |= SELECTOR_PSEUDO; + if (!GetToken(aErrorCode, PR_FALSE)) { + // premature eof + return PR_FALSE; + } + if (eCSSToken_Ident != tk->mType) { + // malformed selector + UngetToken(); + return PR_FALSE; + } + aSelectorResult->mPseudo.Append(tk->mIdent); + tk = nsnull; + } + if (nsnull != tk) { + UngetToken(); + } + if (mask == 0) { + return PR_FALSE; + } + aSelectorResult->mMask = mask; + return PR_TRUE; +} + +nsICSSDeclaration* CSSParserImpl::ParseDeclarationBlock(PRInt32* aErrorCode) +{ + if (!ExpectSymbol(aErrorCode, '{', PR_TRUE)) { + return nsnull; + } + nsICSSDeclaration* declaration = nsnull; + if (NS_OK == NS_NewCSSDeclaration(&declaration)) { + for (;;) { + if (!ParseDeclaration(aErrorCode, declaration)) { + SkipDeclaration(aErrorCode); + if (ExpectSymbol(aErrorCode, '}', PR_TRUE)) { + break; + } + // Since the skipped declaration didn't end the block we parse + // the next declaration. + } + } + } + return declaration; +} + +PRBool CSSParserImpl::ParseColor(PRInt32* aErrorCode, nscolor* aColorResult) +{ + char cbuf[50]; + + if (!GetToken(aErrorCode, PR_TRUE)) { + return PR_FALSE; + } + + nsCSSToken* tk = &mToken; + switch (tk->mType) { + case eCSSToken_ID: + // #xxyyzz + tk->mIdent.ToCString(cbuf, sizeof(cbuf)); + if (NS_HexToRGB(cbuf, aColorResult)) { + return PR_TRUE; + } + break; + + case eCSSToken_Ident: + if (!tk->mIdent.EqualsIgnoreCase("rgb")) { + // named color (maybe!) + tk->mIdent.ToCString(cbuf, sizeof(cbuf)); + if (NS_ColorNameToRGB(cbuf, aColorResult)) { + return PR_TRUE; + } + } else { + // rgb ( component , component , component ) + PRUint8 r, g, b; + if (ExpectSymbol(aErrorCode, '(', PR_TRUE) && + ParseColorComponent(aErrorCode, &r, ',') && + ParseColorComponent(aErrorCode, &g, ',') && + ParseColorComponent(aErrorCode, &b, ')')) { + *aColorResult = NS_RGB(r,g,b); + return PR_TRUE; + } + } + break; + + default: + break; + } + + // It's not a color + UngetToken(); + return PR_FALSE; +} + +PRBool CSSParserImpl::ParseColorComponent(PRInt32* aErrorCode, + PRUint8* aComponent, + char aStop) +{ + if (!GetToken(aErrorCode, PR_TRUE)) { + return PR_FALSE; + } + float value; + nsCSSToken* tk = &mToken; + switch (tk->mType) { + case eCSSToken_Number: + value = tk->mNumber; + break; + case eCSSToken_Percentage: + value = tk->mNumber * 255.0f; + break; + default: + UngetToken(); + return PR_FALSE; + } + if (ExpectSymbol(aErrorCode, aStop, PR_TRUE)) { + if (value < 0.0f) value = 0.0f; + if (value > 255.0f) value = 255.0f; + *aComponent = (PRUint8) value; + return PR_TRUE; + } + return PR_FALSE; +} + +//---------------------------------------------------------------------- + +PRBool CSSParserImpl::ParseDeclaration(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + // Get property name + nsCSSToken* tk = &mToken; + for (;;) { + if (!GetToken(aErrorCode, PR_TRUE)) { + return PR_FALSE; + } + if (eCSSToken_Ident == tk->mType) { + if (!ExpectSymbol(aErrorCode, ':', PR_TRUE)) { + return PR_FALSE; + } + break; + } + if ((eCSSToken_Symbol == tk->mType) && (';' == tk->mSymbol)) { + // dangling semicolons are skipped + continue; + } + + // Not a declaration... + UngetToken(); + return PR_FALSE; + } + + // Map property name to it's ID and then parse the property + char propertyName[100]; + tk->mIdent.ToCString(propertyName, sizeof(propertyName)); + if (!ParseProperty(aErrorCode, propertyName, aDeclaration)) { + return PR_FALSE; + } + + // Make sure valid property declaration is terminated with either a + // semicolon or a right-curly-brace. + if (!GetToken(aErrorCode, PR_TRUE)) { + // Premature eof is not ok + return PR_FALSE; + } + if (eCSSToken_Symbol == tk->mType) { + if (';' == tk->mSymbol) { + return PR_TRUE; + } + if ('}' == tk->mSymbol) { + UngetToken(); + return PR_TRUE; + } + } + return PR_FALSE; +} + +// Flags for ParseVariant method +#define VARIANT_KEYWORD 0x01 +#define VARIANT_LENGTH 0x02 +#define VARIANT_PERCENT 0x04 +#define VARIANT_COLOR 0x08 +#define VARIANT_URL 0x10 +#define VARIANT_NUMBER 0x20 +#define VARIANT_INTEGER 0x40 + +// Common combinations of variants +#define VARIANT_KL (VARIANT_KEYWORD | VARIANT_LENGTH) +#define VARIANT_KLP (VARIANT_KEYWORD | VARIANT_LENGTH | VARIANT_PERCENT) +#define VARIANT_KLPN (VARIANT_KLP | VARIANT_NUMBER) +#define VARIANT_KP (VARIANT_KEYWORD | VARIANT_PERCENT) +#define VARIANT_KI (VARIANT_KEYWORD | VARIANT_INTEGER) +#define VARIANT_LP (VARIANT_LENGTH | VARIANT_PERCENT) +#define VARIANT_CK (VARIANT_COLOR | VARIANT_KEYWORD) +#define VARIANT_C VARIANT_COLOR +#define VARIANT_UK (VARIANT_URL | VARIANT_KEYWORD) + +// Keyword id tables for variant/enum parsing +static PRInt32 kBackgroundAttachmentKTable[] = { + KEYWORD_FIXED, NS_STYLE_BG_ATTACHMENT_FIXED, + KEYWORD_SCROLL, NS_STYLE_BG_ATTACHMENT_SCROLL, + -1 +}; + +static PRInt32 kBackgroundColorKTable[] = { + KEYWORD_TRANSPARENT, NS_STYLE_BG_COLOR_TRANSPARENT, + -1 +}; + +static PRInt32 kBackgroundImageKTable[] = { + KEYWORD_NONE, NS_STYLE_BG_IMAGE_NONE, + -1 +}; + +static PRInt32 kBackgroundRepeatKTable[] = { + KEYWORD_NO_REPEAT, NS_STYLE_BG_REPEAT_OFF, + KEYWORD_REPEAT, NS_STYLE_BG_REPEAT_XY, + KEYWORD_REPEAT_X, NS_STYLE_BG_REPEAT_X, + KEYWORD_REPEAT_Y, NS_STYLE_BG_REPEAT_Y, + -1 +}; + +static PRInt32 kBorderStyleKTable[] = { + KEYWORD_NONE, NS_STYLE_BORDER_STYLE_NONE, + KEYWORD_DOTTED, NS_STYLE_BORDER_STYLE_DOTTED, + KEYWORD_DASHED, NS_STYLE_BORDER_STYLE_DASHED, + KEYWORD_SOLID, NS_STYLE_BORDER_STYLE_SOLID, + KEYWORD_DOUBLE, NS_STYLE_BORDER_STYLE_DOUBLE, + KEYWORD_GROOVE, NS_STYLE_BORDER_STYLE_GROOVE, + KEYWORD_RIDGE, NS_STYLE_BORDER_STYLE_RIDGE, + KEYWORD_INSET, NS_STYLE_BORDER_STYLE_INSET, + KEYWORD_OUTSET, NS_STYLE_BORDER_STYLE_OUTSET, + -1 +}; + +static PRInt32 kBorderWidthKTable[] = { + KEYWORD_THIN, NS_STYLE_BORDER_WIDTH_THIN, + KEYWORD_MEDIUM, NS_STYLE_BORDER_WIDTH_MEDIUM, + KEYWORD_THICK, NS_STYLE_BORDER_WIDTH_THICK, + -1 +}; + +static PRInt32 kClearKTable[] = { + KEYWORD_NONE, NS_STYLE_CLEAR_NONE, + KEYWORD_LEFT, NS_STYLE_CLEAR_LEFT, + KEYWORD_RIGHT, NS_STYLE_CLEAR_RIGHT, + KEYWORD_BOTH, NS_STYLE_CLEAR_BOTH, + -1 +}; + +static PRInt32 kClipKTable[] = { + KEYWORD_AUTO, NS_STYLE_CLIP_AUTO, + -1 +}; + +static PRInt32 kDisplayKTable[] = { + KEYWORD_NONE, NS_STYLE_DISPLAY_NONE, + KEYWORD_BLOCK, NS_STYLE_DISPLAY_BLOCK, + KEYWORD_INLINE, NS_STYLE_DISPLAY_INLINE, + KEYWORD_LIST_ITEM, NS_STYLE_DISPLAY_LIST_ITEM, + -1 +}; + +static PRInt32 kFloatKTable[] = { + KEYWORD_NONE, NS_STYLE_FLOAT_NONE, + KEYWORD_LEFT, NS_STYLE_FLOAT_LEFT, + KEYWORD_RIGHT, NS_STYLE_FLOAT_RIGHT, + -1 +}; + +static PRInt32 kFontSizeKTable[] = { + KEYWORD_XX_SMALL, NS_STYLE_FONT_SIZE_XXSMALL, + KEYWORD_X_SMALL, NS_STYLE_FONT_SIZE_XSMALL, + KEYWORD_SMALL, NS_STYLE_FONT_SIZE_SMALL, + KEYWORD_MEDIUM, NS_STYLE_FONT_SIZE_MEDIUM, + KEYWORD_LARGE, NS_STYLE_FONT_SIZE_LARGE, + KEYWORD_X_LARGE, NS_STYLE_FONT_SIZE_XLARGE, + KEYWORD_XX_LARGE, NS_STYLE_FONT_SIZE_XXLARGE, + KEYWORD_LARGER, NS_STYLE_FONT_SIZE_LARGER, + KEYWORD_SMALLER, NS_STYLE_FONT_SIZE_SMALLER, + -1 +}; + +static PRInt32 kFontStyleKTable[] = { + KEYWORD_NORMAL, NS_STYLE_FONT_STYLE_NORMAL, + KEYWORD_ITALIC, NS_STYLE_FONT_STYLE_ITALIC, + KEYWORD_OBLIQUE, NS_STYLE_FONT_STYLE_OBLIQUE, + -1 +}; + +static PRInt32 kFontVariantKTable[] = { + KEYWORD_NORMAL, NS_STYLE_FONT_VARIANT_NORMAL, + KEYWORD_SMALL_CAPS, NS_STYLE_FONT_VARIANT_SMALL_CAPS, + -1 +}; + +static PRInt32 kLeftKTable[] = { + KEYWORD_AUTO, NS_STYLE_LEFT_AUTO, + -1 +}; + +static PRInt32 kHeightKTable[] = { + KEYWORD_AUTO, NS_STYLE_HEIGHT_AUTO, + -1 +}; + +static PRInt32 kLineHeightKTable[] = { + KEYWORD_NORMAL, NS_STYLE_LINE_HEIGHT_NORMAL, + -1 +}; + +static PRInt32 kListStyleImageKTable[] = { + KEYWORD_NONE, NS_STYLE_LIST_STYLE_IMAGE_NONE, + -1 +}; + +static PRInt32 kListStylePositionKTable[] = { + KEYWORD_INSIDE, NS_STYLE_LIST_STYLE_POSITION_INSIDE, + KEYWORD_OUTSIDE, NS_STYLE_LIST_STYLE_POSITION_OUTSIDE, + -1 +}; + +static PRInt32 kListStyleKTable[] = { + KEYWORD_NONE, NS_STYLE_LIST_STYLE_NONE, + KEYWORD_DISC, NS_STYLE_LIST_STYLE_DISC, + KEYWORD_CIRCLE, NS_STYLE_LIST_STYLE_CIRCLE, + KEYWORD_SQUARE, NS_STYLE_LIST_STYLE_SQUARE, + KEYWORD_DECIMAL, NS_STYLE_LIST_STYLE_DECIMAL, + KEYWORD_LOWER_ROMAN, NS_STYLE_LIST_STYLE_LOWER_ROMAN, + KEYWORD_UPPER_ROMAN, NS_STYLE_LIST_STYLE_UPPER_ROMAN, + KEYWORD_LOWER_ALPHA, NS_STYLE_LIST_STYLE_LOWER_ALPHA, + KEYWORD_UPPER_ALPHA, NS_STYLE_LIST_STYLE_UPPER_ALPHA, + -1 +}; + +static PRInt32 kMarginSizeKTable[] = { + KEYWORD_AUTO, NS_STYLE_MARGIN_SIZE_AUTO, + -1 +}; + +static PRInt32 kSpacingKTable[] = { + KEYWORD_NORMAL, NS_STYLE_SPACING_NORMAL, + -1 +}; + +static PRInt32 kOverflowKTable[] = { + KEYWORD_VISIBLE, NS_STYLE_OVERFLOW_VISIBLE, + KEYWORD_HIDDEN, NS_STYLE_OVERFLOW_HIDDEN, + KEYWORD_SCROLL, NS_STYLE_OVERFLOW_SCROLL, + KEYWORD_AUTO, NS_STYLE_OVERFLOW_AUTO, + -1 +}; + +static PRInt32 kPositionKTable[] = { + KEYWORD_STATIC, NS_STYLE_POSITION_STATIC, + KEYWORD_RELATIVE, NS_STYLE_POSITION_RELATIVE, + KEYWORD_ABSOLUTE, NS_STYLE_POSITION_ABSOLUTE, + -1 +}; + +static PRInt32 kTextAlignKTable[] = { + KEYWORD_LEFT, NS_STYLE_TEXT_ALIGN_LEFT, + KEYWORD_RIGHT, NS_STYLE_TEXT_ALIGN_RIGHT, + KEYWORD_CENTER, NS_STYLE_TEXT_ALIGN_CENTER, + KEYWORD_JUSTIFY, NS_STYLE_TEXT_ALIGN_JUSTIFY, + -1 +}; + +static PRInt32 kTextTransformKTable[] = { + KEYWORD_NONE, NS_STYLE_TEXT_TRANSFORM_NONE, + KEYWORD_CAPITALIZE, NS_STYLE_TEXT_TRANSFORM_CAPITALIZE, + KEYWORD_LOWERCASE, NS_STYLE_TEXT_TRANSFORM_LOWERCASE, + KEYWORD_UPPERCASE, NS_STYLE_TEXT_TRANSFORM_UPPERCASE, + -1 +}; + +static PRInt32 kTopKTable[] = { + KEYWORD_AUTO, NS_STYLE_TOP_AUTO, + -1 +}; + +static PRInt32 kVerticalAlignKTable[] = { + KEYWORD_BASELINE, NS_STYLE_VERTICAL_ALIGN_BASELINE, + KEYWORD_SUB, NS_STYLE_VERTICAL_ALIGN_SUB, + KEYWORD_SUPER, NS_STYLE_VERTICAL_ALIGN_SUPER, + KEYWORD_TOP, NS_STYLE_VERTICAL_ALIGN_TOP, + KEYWORD_TEXT_TOP, NS_STYLE_VERTICAL_ALIGN_TEXT_TOP, + KEYWORD_MIDDLE, NS_STYLE_VERTICAL_ALIGN_MIDDLE, + KEYWORD_BOTTOM, NS_STYLE_VERTICAL_ALIGN_BOTTOM, + KEYWORD_TEXT_BOTTOM, NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM, + -1 +}; + +static PRInt32 kVisibilityKTable[] = { + KEYWORD_INHERIT, NS_STYLE_VISIBILITY_INHERIT, + KEYWORD_VISIBLE, NS_STYLE_VISIBILITY_VISIBLE, + KEYWORD_HIDDEN, NS_STYLE_VISIBILITY_HIDDEN, + -1 +}; + +static PRInt32 kWhitespaceKTable[] = { + KEYWORD_NORMAL, NS_STYLE_WHITESPACE_NORMAL, + KEYWORD_PRE, NS_STYLE_WHITESPACE_PRE, + KEYWORD_NOWRAP, NS_STYLE_WHITESPACE_NOWRAP, + -1 +}; + +static PRInt32 kWidthKTable[] = { + KEYWORD_AUTO, NS_STYLE_WIDTH_AUTO, + -1 +}; + +static PRInt32 kZIndexKTable[] = { + KEYWORD_AUTO, NS_STYLE_WIDTH_AUTO, + -1 +}; + +static const char* kBorderTopNames[] = { + "border-top-width", + "border-top-style", + "border-top-color", +}; +static const char* kBorderRightNames[] = { + "border-right-width", + "border-right-style", + "border-right-color", +}; +static const char* kBorderBottomNames[] = { + "border-bottom-width", + "border-bottom-style", + "border-bottom-color", +}; +static const char* kBorderLeftNames[] = { + "border-left-width", + "border-left-style", + "border-left-color", +}; + +PRInt32 CSSParserImpl::SearchKeywordTable(PRInt32 aID, PRInt32 aTable[]) +{ + PRInt32 i = 0; + for (;;) { + if (aTable[i] < 0) { + break; + } + if (aID == aTable[i]) { + return i; + } + i += 2; + } + return -1; +} + +PRBool CSSParserImpl::ParseEnum(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName, PRInt32* aTable) +{ + nsString* ident = NextIdent(aErrorCode); + if (nsnull == ident) { + return PR_FALSE; + } + char cbuf[50]; + ident->ToCString(cbuf, sizeof(cbuf)); + PRInt32 id = nsCSSKeywords::LookupName(cbuf); + if (id >= 0) { + PRInt32 ix = SearchKeywordTable(id, aTable); + if (ix >= 0) { + aDeclaration->AddValue(aName, nsCSSValue(aTable[ix+1], eCSSUnit_Enumerated)); + return PR_TRUE; + } + } + + // Put the unknown identifier back and return + UngetToken(); + return PR_FALSE; +} + +PRBool CSSParserImpl::TranslateLength(nsICSSDeclaration* aDeclaration, + const char* aName, + float aNumber, + const nsString& aDimension) +{ + nsCSSUnit units; + if (0 != aDimension.Length()) { + char cbuf[50]; + aDimension.ToCString(cbuf, sizeof(cbuf)); + PRInt32 id = nsCSSKeywords::LookupName(cbuf); + switch (id) { + case KEYWORD_EM: units = eCSSUnit_EM; break; + case KEYWORD_EX: units = eCSSUnit_XHeight; break; + case KEYWORD_PX: units = eCSSUnit_Pixel; break; + case KEYWORD_IN: units = eCSSUnit_Inch; break; + case KEYWORD_CM: units = eCSSUnit_Centimeter; break; + case KEYWORD_MM: units = eCSSUnit_Millimeter; break; + case KEYWORD_PT: units = eCSSUnit_Point; break; + case KEYWORD_PC: units = eCSSUnit_Pica; break; + default: + // unknown dimension + return PR_FALSE; + } + } else { + // Must be a zero number... + units = eCSSUnit_Point; + } + aDeclaration->AddValue(aName, nsCSSValue(aNumber, units)); + return PR_TRUE; +} + + +PRBool CSSParserImpl::ParseVariant(PRInt32* aErrorCode, + nsICSSDeclaration* aDeclaration, + const char* aName, + PRInt32 aVariants, PRInt32* aTable) +{ + nsCSSToken* tk = &mToken; + if (!GetToken(aErrorCode, PR_TRUE)) { + return PR_FALSE; + } + if (((aVariants & VARIANT_KEYWORD) != 0) && + (eCSSToken_Ident == tk->mType)) { + char cbuf[50]; + tk->mIdent.ToCString(cbuf, sizeof(cbuf)); + PRInt32 sid = nsCSSKeywords::LookupName(cbuf); + if (sid >= 0) { + PRInt32 ix = SearchKeywordTable(sid, aTable); + if (ix >= 0) { + aDeclaration->AddValue(aName, nsCSSValue(aTable[ix+1], eCSSUnit_Enumerated)); + return PR_TRUE; + } + } + } + if (((aVariants & VARIANT_LENGTH) != 0) && tk->isDimension()) { + return TranslateLength(aDeclaration, aName, tk->mNumber, tk->mIdent); + } + if (((aVariants & VARIANT_PERCENT) != 0) && + (eCSSToken_Percentage == tk->mType)) { + aDeclaration->AddValue(aName, nsCSSValue(tk->mNumber, eCSSUnit_Percent)); + return PR_TRUE; + } + if (((aVariants & VARIANT_NUMBER) != 0) && + (eCSSToken_Number == tk->mType)) { + aDeclaration->AddValue(aName, nsCSSValue(tk->mNumber, eCSSUnit_Number)); + return PR_TRUE; + } + if (((aVariants & VARIANT_INTEGER) != 0) && + (eCSSToken_Number == tk->mType) && tk->mIntegerValid) { + aDeclaration->AddValue(aName, nsCSSValue(tk->mInteger, eCSSUnit_Absolute)); + return PR_TRUE; + } + if (((aVariants & VARIANT_URL) != 0) && + (eCSSToken_URL == tk->mType)) { + aDeclaration->AddValue(aName, nsCSSValue(tk->mIdent)); + return PR_TRUE; + } + if ((aVariants & VARIANT_COLOR) != 0) { + if ((eCSSToken_ID == tk->mType) || (eCSSToken_Ident == tk->mType)) { + // Put token back so that parse color can get it + UngetToken(); + nscolor rgba; + // XXX This loses the original input format (e.g. a name which + // should be preserved when editing) + if (ParseColor(aErrorCode, &rgba)) { + aDeclaration->AddValue(aName, nsCSSValue(rgba)); + return PR_TRUE; + } + return PR_FALSE; + } + } + UngetToken(); + return PR_FALSE; +} + +PRInt32 CSSParserImpl::ParseChoice(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aNames[], PRInt32 aNumNames) +{ + PRInt32 found = 0; + for (int i = 0; i < aNumNames; i++) { + // Try each property parser in order + for (int j = 0; j < aNumNames; j++) { + PRInt32 bit = 1 << j; + if ((found & bit) == 0) { + PRInt32 id = nsCSSProps::LookupName(aNames[j]); + if (ParseProperty(aErrorCode, aNames[j], aDeclaration, id)) { + found |= bit; + } + } + } + } + return found; +} + +/** + * Parse a "box" property. Box properties have 1 to 4 values. When less + * than 4 values are provided a standard mapping is used to replicate + * existing values. Note that the replication requires renaming the + * values. + */ +PRBool CSSParserImpl::ParseBoxProperties(PRInt32* aErrorCode, + nsICSSDeclaration* aDeclaration, + const char* aNames[]) +{ + // Get up to four values for the property + PRInt32 count = 0; + for (int i = 0; i < 4; i++) { + PRInt32 id = nsCSSProps::LookupName(aNames[i]); + if (!ParseProperty(aErrorCode, aNames[i], aDeclaration, id)) { + break; + } + count++; + } + if (count == 0) { + return PR_FALSE; + } + + // Provide missing values by replicating some of the values found + nsCSSValue value; + switch (count) { + case 1: // Make right == top + aDeclaration->GetValue(aNames[0], value); + aDeclaration->AddValue(aNames[1], value); + case 2: // Make bottom == top + aDeclaration->GetValue(aNames[0], value); + aDeclaration->AddValue(aNames[2], value); + case 3: // Make left == right + aDeclaration->GetValue(aNames[1], value); + aDeclaration->AddValue(aNames[3], value); + } + + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseProperty(PRInt32* aErrorCode, + const char* aName, + nsICSSDeclaration* aDeclaration) +{ + PRInt32 id = nsCSSProps::LookupName(aName); + if (id < 0) { + return PR_FALSE; + } + + // Strip out properties we use internally. These properties are used + // by compound property parsing routines (e.g. "background-position"). + switch (id) { + case PROP_BACKGROUND_X_POSITION: + case PROP_BACKGROUND_Y_POSITION: + case PROP_BORDER_TOP_COLOR: + case PROP_BORDER_RIGHT_COLOR: + case PROP_BORDER_BOTTOM_COLOR: + case PROP_BORDER_LEFT_COLOR: + case PROP_BORDER_TOP_STYLE: + case PROP_BORDER_RIGHT_STYLE: + case PROP_BORDER_BOTTOM_STYLE: + case PROP_BORDER_LEFT_STYLE: + case PROP_CLIP_BOTTOM: + case PROP_CLIP_LEFT: + case PROP_CLIP_RIGHT: + case PROP_CLIP_TOP: + // The user can't use these + return PR_FALSE; + } + + return ParseProperty(aErrorCode, aName, aDeclaration, id); +} + +PRBool CSSParserImpl::ParseProperty(PRInt32* aErrorCode, + const char* aName, + nsICSSDeclaration* aDeclaration, + PRInt32 aID) +{ + switch (aID) { + case PROP_BACKGROUND: + return ParseBackground(aErrorCode, aDeclaration); + case PROP_BACKGROUND_ATTACHMENT: + return ParseEnum(aErrorCode, aDeclaration, aName, kBackgroundAttachmentKTable); + case PROP_BACKGROUND_COLOR: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_CK, + kBackgroundColorKTable); + case PROP_BACKGROUND_FILTER: + return ParseBackgroundFilter(aErrorCode, aDeclaration, aName); + case PROP_BACKGROUND_IMAGE: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_UK, + kBackgroundImageKTable); + case PROP_BACKGROUND_POSITION: + return ParseBackgroundPosition(aErrorCode, aDeclaration, aName); + case PROP_BACKGROUND_REPEAT: + return ParseEnum(aErrorCode, aDeclaration, aName, kBackgroundRepeatKTable); + case PROP_BORDER: + return ParseBorder(aErrorCode, aDeclaration); + case PROP_BORDER_COLOR: + return ParseBorderColor(aErrorCode, aDeclaration); + case PROP_BORDER_STYLE: + return ParseBorderStyle(aErrorCode, aDeclaration); + case PROP_BORDER_BOTTOM: + return ParseBorderSide(aErrorCode, aDeclaration, kBorderBottomNames, 0); + case PROP_BORDER_LEFT: + return ParseBorderSide(aErrorCode, aDeclaration, kBorderLeftNames, 1); + case PROP_BORDER_RIGHT: + return ParseBorderSide(aErrorCode, aDeclaration, kBorderRightNames, 2); + case PROP_BORDER_TOP: + return ParseBorderSide(aErrorCode, aDeclaration, kBorderTopNames, 3); + case PROP_BORDER_BOTTOM_COLOR: + case PROP_BORDER_LEFT_COLOR: + case PROP_BORDER_RIGHT_COLOR: + case PROP_BORDER_TOP_COLOR: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_C, nsnull); + case PROP_BORDER_BOTTOM_STYLE: + case PROP_BORDER_LEFT_STYLE: + case PROP_BORDER_RIGHT_STYLE: + case PROP_BORDER_TOP_STYLE: + return ParseEnum(aErrorCode, aDeclaration, aName, kBorderStyleKTable); + case PROP_BORDER_BOTTOM_WIDTH: + case PROP_BORDER_LEFT_WIDTH: + case PROP_BORDER_RIGHT_WIDTH: + case PROP_BORDER_TOP_WIDTH: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KL, + kBorderWidthKTable); + case PROP_BORDER_WIDTH: + return ParseBorderWidth(aErrorCode, aDeclaration); + case PROP_CLEAR: + return ParseEnum(aErrorCode, aDeclaration, aName, kClearKTable); + case PROP_CLIP: + return ParseClip(aErrorCode, aDeclaration); + case PROP_COLOR: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_COLOR, nsnull); + case PROP_DISPLAY: + return ParseEnum(aErrorCode, aDeclaration, aName, kDisplayKTable); + case PROP_FILTER: + return ParseForegroundFilter(aErrorCode, aDeclaration, aName); + case PROP_FLOAT: + return ParseEnum(aErrorCode, aDeclaration, aName, kFloatKTable); + case PROP_FONT: + return ParseFont(aErrorCode, aDeclaration, aName); + case PROP_FONT_FAMILY: + return ParseFontFamily(aErrorCode, aDeclaration, aName); + case PROP_FONT_SIZE: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KLP, + kFontSizeKTable); + case PROP_FONT_STYLE: + return ParseEnum(aErrorCode, aDeclaration, aName, kFontStyleKTable); + case PROP_FONT_VARIANT: + return ParseEnum(aErrorCode, aDeclaration, aName, kFontVariantKTable); + case PROP_FONT_WEIGHT: + return ParseFontWeight(aErrorCode, aDeclaration, aName); + case PROP_HEIGHT: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KL, kHeightKTable); + case PROP_LEFT: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KLP, kLeftKTable); + case PROP_LINE_HEIGHT: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KLPN, + kLineHeightKTable); + case PROP_LIST_STYLE: + return ParseListStyle(aErrorCode, aDeclaration); + case PROP_LIST_STYLE_IMAGE: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_UK, + kListStyleImageKTable); + case PROP_LIST_STYLE_POSITION: + return ParseEnum(aErrorCode, aDeclaration, aName, kListStylePositionKTable); + case PROP_LIST_STYLE_TYPE: + return ParseEnum(aErrorCode, aDeclaration, aName, kListStyleKTable); + case PROP_MARGIN: + return ParseMargin(aErrorCode, aDeclaration); + case PROP_MARGIN_BOTTOM: + case PROP_MARGIN_LEFT: + case PROP_MARGIN_RIGHT: + case PROP_MARGIN_TOP: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KLP, + kMarginSizeKTable); + case PROP_PADDING: + return ParsePadding(aErrorCode, aDeclaration); + case PROP_PADDING_BOTTOM: + case PROP_PADDING_LEFT: + case PROP_PADDING_RIGHT: + case PROP_PADDING_TOP: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_LP, nsnull); + case PROP_OVERFLOW: + return ParseEnum(aErrorCode, aDeclaration, aName, kOverflowKTable); + case PROP_POSITION: + return ParseEnum(aErrorCode, aDeclaration, aName, kPositionKTable); + case PROP_TEXT_ALIGN: + return ParseEnum(aErrorCode, aDeclaration, aName, kTextAlignKTable); + case PROP_TEXT_DECORATION: + return ParseTextDecoration(aErrorCode, aDeclaration, aName); + case PROP_TEXT_INDENT: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_LP, nsnull); + case PROP_TEXT_TRANSFORM: + return ParseEnum(aErrorCode, aDeclaration, aName, kTextTransformKTable); + case PROP_TOP: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KLP, kTopKTable); + case PROP_VERTICAL_ALIGN: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KP, + kVerticalAlignKTable); + case PROP_VISIBILITY: + return ParseEnum(aErrorCode, aDeclaration, aName, kVisibilityKTable); + case PROP_WHITE_SPACE: + return ParseEnum(aErrorCode, aDeclaration, aName, kWhitespaceKTable); + case PROP_WIDTH: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KLP, kWidthKTable); + case PROP_LETTER_SPACING: + case PROP_WORD_SPACING: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KL, kSpacingKTable); + case PROP_Z_INDEX: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KI, kZIndexKTable); + } + return PR_FALSE; +} + +PRBool CSSParserImpl::ParseBackground(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + static const char* kBackgroundNames[] = { + "background-color", + "background-image", + "background-repeat", + "background-attachment", + "background-position", + "background-filter", + }; + + PRInt32 found = ParseChoice(aErrorCode, aDeclaration, kBackgroundNames, 6); + if (0 == found) { + return PR_FALSE; + } + + // Provide missing values + if ((found & 1) == 0) { + aDeclaration->AddValue(kBackgroundNames[0], + nsCSSValue(NS_STYLE_BG_COLOR_TRANSPARENT, + eCSSUnit_Enumerated)); + } + if ((found & 2) == 0) { + aDeclaration->AddValue(kBackgroundNames[1], + nsCSSValue(NS_STYLE_BG_IMAGE_NONE, + eCSSUnit_Enumerated)); + } + if ((found & 4) == 0) { + aDeclaration->AddValue(kBackgroundNames[2], + nsCSSValue(NS_STYLE_BG_REPEAT_XY, + eCSSUnit_Enumerated)); + } + if ((found & 8) == 0) { + aDeclaration->AddValue(kBackgroundNames[3], + nsCSSValue(NS_STYLE_BG_ATTACHMENT_SCROLL, + eCSSUnit_Enumerated)); + } + if ((found & 16) == 0) { + aDeclaration->AddValue("background-x-position", nsCSSValue(0.0f, eCSSUnit_Percent)); + aDeclaration->AddValue("background-y-position", nsCSSValue(0.0f, eCSSUnit_Percent)); + } + + // XXX Note: no default for filter (yet) + return PR_TRUE; +} + +// Bits used in determining which background position info we have +#define BG_CENTER 0 +#define BG_TOP 1 +#define BG_BOTTOM 2 +#define BG_LEFT 4 +#define BG_RIGHT 8 +#define BG_CENTER1 16 +#define BG_CENTER2 32 + +PRBool CSSParserImpl::ParseBackgroundPosition(PRInt32* aErrorCode, + nsICSSDeclaration* aDeclaration, + const char* aName) +{ + static PRInt32 kBackgroundPositionNames[] = { + PROP_BACKGROUND_X_POSITION, + PROP_BACKGROUND_Y_POSITION, + }; + + // Note: Don't change this table unless you update + // parseBackgroundPosition! + + static PRInt32 kBackgroundXYPositionKTable[] = { + KEYWORD_CENTER, BG_CENTER, + KEYWORD_TOP, BG_TOP, + KEYWORD_BOTTOM, BG_BOTTOM, + KEYWORD_LEFT, BG_LEFT, + KEYWORD_RIGHT, BG_RIGHT, + -1, + }; + + const char* bxp = "background-x-position"; + const char* byp = "background-y-position"; + + // First try a number or a length value + if (ParseVariant(aErrorCode, aDeclaration, bxp, VARIANT_LP, nsnull)) { + // We have one number/length. Get the optional second number/length. + if (ParseVariant(aErrorCode, aDeclaration, byp, VARIANT_LP, nsnull)) { + // We have two numbers + return PR_TRUE; + } + + // We have one number which is the x position. Create an value for + // the vertical position which is of value 50% + aDeclaration->AddValue(byp, nsCSSValue(0.5f, eCSSUnit_Percent)); + // XXX shouldn't this be CENTER enum instead? + return PR_TRUE; + } + + // Now try keywords. We do this manually to allow for the first + // appearance of "center" to apply to the either the x or y + // position (it's ambiguous so we have to disambiguate). Each + // allowed keyword value is assigned it's own bit. We don't allow + // any duplicate keywords other than center. We try to get two + // keywords but it's okay if there is only one. + PRInt32 mask = 0; + PRInt32 centerBit = BG_CENTER1; + for (PRInt32 i = 0; i < 2; i++) { + nsString* ident = NextIdent(aErrorCode); + if (nsnull == ident) { + break; + } + char cbuf[50]; + ident->ToCString(cbuf, sizeof(cbuf)); + PRInt32 ix = SearchKeywordTable(nsCSSKeywords::LookupName(cbuf), + kBackgroundXYPositionKTable); + if (ix >= 0) { + PRInt32 bit = kBackgroundXYPositionKTable[ix + 1]; + if (bit == 0) { + // Special hack for center bits: We can have two of them + mask |= centerBit; + centerBit <<= 1; + continue; + } else if ((mask & bit) != 0) { + // no duplicate values allowed (other than center) + return PR_FALSE; + } + mask |= bit; + } else { + UngetToken(); + break; + } + } + + // Check for bad input. Bad input consists of no matching keywords, + // or pairs of x keywords or pairs of y keywords. + if ((mask == 0) || (mask == (BG_TOP | BG_BOTTOM)) || + (mask == (BG_LEFT | BG_RIGHT))) { + return PR_FALSE; + } + + // Map good input + int xValue = 50; + if ((mask & (BG_LEFT | BG_RIGHT)) != 0) { + // We have an x value + xValue = ((mask & BG_LEFT) != 0) ? 0 : 100; + } + int yValue = 50; + if ((mask & (BG_TOP | BG_BOTTOM)) != 0) { + // We have a y value + yValue = ((mask & BG_TOP) != 0) ? 0 : 100; + } + + // Create style values + aDeclaration->AddValue(bxp, nsCSSValue(xValue, eCSSUnit_Enumerated)); + aDeclaration->AddValue(byp, nsCSSValue(yValue, eCSSUnit_Enumerated)); + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseBackgroundFilter(PRInt32* aErrorCode, + nsICSSDeclaration* aDeclaration, + const char* aName) +{ + // XXX not yet supported + return PR_FALSE; +} + +PRBool CSSParserImpl::ParseForegroundFilter(PRInt32* aErrorCode, + nsICSSDeclaration* aDeclaration, + const char* aName) +{ + // XXX not yet supported + return PR_FALSE; +} + +// These must be in alphabetical order for aWhich based indexing to work +static const char* kBorderStyleNames[] = { + "border-bottom-style", + "border-left-style", + "border-right-style", + "border-top-style", +}; +static const char* kBorderWidthNames[] = { + "border-bottom-width", + "border-left-width", + "border-right-width", + "border-top-width", +}; + + +PRBool CSSParserImpl::ParseBorder(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + static const char* kBorderNames[] = { + "border-width", + "border-style", + "border-color" + }; + PRInt32 found = ParseChoice(aErrorCode, aDeclaration, kBorderNames, 3); + if (0 == found) { + return PR_FALSE; + } + if (0 == (found & 1)) { + // provide missing border width's + for (int i = 0; i < 4; i++) { + aDeclaration->AddValue(kBorderWidthNames[i], + nsCSSValue(NS_STYLE_BORDER_WIDTH_MEDIUM, + eCSSUnit_Enumerated)); + } + } + if (0 == (found & 2)) { + // provide missing border style's + for (int i = 0; i < 4; i++) { + aDeclaration->AddValue(kBorderStyleNames[i], + nsCSSValue(NS_STYLE_BORDER_STYLE_NONE, + eCSSUnit_Enumerated)); + } + } + + // Do NOT provide a missing color value as the default is to be + // the color of the element itself which must be determined later. + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseBorderColor(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + static const char* kBoxBorderColorNames[] = { + "border-top-color", + "border-right-color", + "border-bottom-color", + "border-left-color", + }; + return ParseBoxProperties(aErrorCode, aDeclaration, kBoxBorderColorNames); +} + +PRBool CSSParserImpl::ParseBorderSide(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aNames[], PRInt32 aWhich) +{ + PRInt32 found = ParseChoice(aErrorCode, aDeclaration, aNames, 3); + if (found == 0) return PR_FALSE; + if ((found & 1) == 0) { + // Provide default border-width + aDeclaration->AddValue(kBorderWidthNames[aWhich], + nsCSSValue(NS_STYLE_BORDER_WIDTH_MEDIUM, eCSSUnit_Enumerated)); + } + if ((found & 2) == 0) { + // Provide default border-style + aDeclaration->AddValue(kBorderStyleNames[aWhich], + nsCSSValue(NS_STYLE_BORDER_STYLE_NONE, eCSSUnit_Enumerated)); + } + + // Do NOT provide a missing color value as the default is to be + // the color of the element itself which must be determined later. + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseBorderStyle(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + // in top, right, bottom, left order + static const char* kBoxBorderStyleNames[] = { + "border-top-style", + "border-right-style", + "border-bottom-style", + "border-left-style", + }; + return ParseBoxProperties(aErrorCode, aDeclaration, kBoxBorderStyleNames); +} + +PRBool CSSParserImpl::ParseBorderWidth(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + static const char* kBoxBorderWidthNames[] = { + "border-top-width", + "border-right-width", + "border-bottom-width", + "border-left-width", + }; + return ParseBoxProperties(aErrorCode, aDeclaration, kBoxBorderWidthNames); +} + +PRBool CSSParserImpl::ParseClip(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + static const char* kClipNames[] = { + "clip-top", + "clip-right", + "clip-bottom", + "clip-left", + }; + nsString* ident = NextIdent(aErrorCode); + if (nsnull == ident) { + return PR_FALSE; + } + if (ident->EqualsIgnoreCase("auto")) { + for (int i = 0; i < 4; i++) { + aDeclaration->AddValue(kClipNames[i], + nsCSSValue(NS_STYLE_CLIP_AUTO, eCSSUnit_Enumerated)); + } + return PR_TRUE; + } else if (ident->EqualsIgnoreCase("rect")) { + if (!ExpectSymbol(aErrorCode, '(', PR_TRUE)) { + return PR_FALSE; + } + for (int i = 0; i < 4; i++) { + if (!ParseVariant(aErrorCode, aDeclaration, kClipNames[i], VARIANT_KL, + kClipKTable)) { + return PR_FALSE; + } + } + if (!ExpectSymbol(aErrorCode, ')', PR_TRUE)) { + return PR_FALSE; + } + return PR_TRUE; + } else { + UngetToken(); + } + return PR_FALSE; +} + +PRBool CSSParserImpl::ParseFont(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName) +{ + static const char* fontNames[] = { + "font-style", + "font-variant", + "font-weight", + }; + + // Get optional font-style, font-variant and font-weight (in any order) + PRInt32 found = ParseChoice(aErrorCode, aDeclaration, fontNames, 3); + if ((found & 1) == 0) { + // Provide default font-style + aDeclaration->AddValue(fontNames[0], + nsCSSValue(NS_STYLE_FONT_STYLE_NORMAL, eCSSUnit_Enumerated)); + } + if ((found & 2) == 0) { + // Provide default font-variant + aDeclaration->AddValue(fontNames[1], + nsCSSValue(NS_STYLE_FONT_VARIANT_NORMAL, eCSSUnit_Enumerated)); + } + if ((found & 4) == 0) { + // Provide default font-weight + aDeclaration->AddValue(fontNames[2], + nsCSSValue(NS_STYLE_FONT_WEIGHT_NORMAL, eCSSUnit_Enumerated)); + } + + // Get mandatory font-size + if (!ParseVariant(aErrorCode, aDeclaration, "font-size", + VARIANT_KLP, kFontSizeKTable)) { + return PR_FALSE; + } + + // Get optional "/" line-height + if (ExpectSymbol(aErrorCode, '/', PR_TRUE)) { + if (!ParseVariant(aErrorCode, aDeclaration, "line-height", + VARIANT_KLPN, kLineHeightKTable)) { + return PR_FALSE; + } + } + + // Get final mandatory font-family + return ParseFontFamily(aErrorCode, aDeclaration, "font-family"); +} + +PRBool CSSParserImpl::ParseFontFamily(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName) +{ + nsCSSToken* tk = &mToken; + nsAutoString family; + PRBool firstOne = PR_TRUE; + for (;;) { + if (!GetToken(aErrorCode, PR_TRUE)) { + break; + } + if (eCSSToken_Ident == tk->mType) { + if (!firstOne) { + family.Append(PRUnichar(',')); + } + family.Append(PRUnichar('"')); + family.Append(tk->mIdent); + for (;;) { + if (!GetToken(aErrorCode, PR_FALSE)) { + break; + } + if (eCSSToken_Ident == tk->mType) { + family.Append(tk->mIdent); + } else if (eCSSToken_WhiteSpace == tk->mType) { + // Lookahead one token and drop whitespace if we ending the + // font name. + if (!GetToken(aErrorCode, PR_TRUE)) { + break; + } + if (eCSSToken_Ident != tk->mType) { + UngetToken(); + break; + } + UngetToken(); + family.Append(PRUnichar(' ')); + } else { + UngetToken(); + break; + } + } + family.Append(PRUnichar('"')); + firstOne = PR_FALSE; + } else if (eCSSToken_String == tk->mType) { + if (!firstOne) { + family.Append(PRUnichar(',')); + } + family.Append(PRUnichar('"')); + family.Append(tk->mIdent); + family.Append(PRUnichar('"')); + firstOne = PR_FALSE; + } else if (eCSSToken_Symbol == tk->mType) { + if (',' != tk->mSymbol) { + UngetToken(); + break; + } + } else { + UngetToken(); + break; + } + } + if (family.Length() == 0) { + return PR_FALSE; + } + aDeclaration->AddValue(aName, nsCSSValue(family)); + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseFontWeight(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName) +{ + static PRInt32 kFontWeightKTable[] = { + KEYWORD_NORMAL, NS_STYLE_FONT_WEIGHT_NORMAL, + KEYWORD_BOLD, NS_STYLE_FONT_WEIGHT_BOLD, + KEYWORD_BOLDER, NS_STYLE_FONT_WEIGHT_BOLDER, + KEYWORD_LIGHTER, NS_STYLE_FONT_WEIGHT_LIGHTER, + -1, + }; + nsCSSToken* tk = &mToken; + if (!GetToken(aErrorCode, PR_TRUE)) { + return PR_FALSE; + } + if (eCSSToken_Ident == tk->mType) { + char cbuf[50]; + tk->mIdent.ToCString(cbuf, sizeof(cbuf)); + PRInt32 kid = nsCSSKeywords::LookupName(cbuf); + PRInt32 ix = SearchKeywordTable(kid, kFontWeightKTable); + if (ix < 0) { + UngetToken(); + return PR_FALSE; + } + aDeclaration->AddValue(aName, nsCSSValue(kFontWeightKTable[ix+1], eCSSUnit_Enumerated)); + } else if (eCSSToken_Number == tk->mType) { + PRInt32 v = (PRInt32) tk->mNumber; + if (v < 100) v = 100; + else if (v > 900) v = 900; + v = v - (v % 100); + aDeclaration->AddValue(aName, nsCSSValue(v, eCSSUnit_Absolute)); + } else { + UngetToken(); + return PR_FALSE; + } + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseListStyle(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + const char* lst = "list-style-type"; + const char* lsp = "list-style-position"; + const char* lsi = "list-style-image"; + int found = 0; + for (int i = 0; i < 3; i++) { + if (((found & 1) == 0) && + ParseEnum(aErrorCode, aDeclaration, lst, kListStyleKTable)) { + found |= 1; + continue; + } + if (((found & 2) == 0) && + ParseEnum(aErrorCode, aDeclaration, lsp, kListStylePositionKTable)) { + found |= 2; + continue; + } + if ((found & 4) == 0) { + if (!GetToken(aErrorCode, PR_TRUE)) { + break; + } + if (eCSSToken_URL == mToken.mType) { + aDeclaration->AddValue(lsi, nsCSSValue(mToken.mIdent)); + found |= 4; + continue; + } else { + if (eCSSToken_Symbol == mToken.mType) { + PRUnichar symbol = mToken.mSymbol; + if ((';' == symbol) || ('}' == symbol)) { + UngetToken(); + break; + } + } + + // We got something strange. That's an error. + UngetToken(); + return PR_FALSE; + } + } + } + if (found == 0) { + return PR_FALSE; + } + + // Provide default values + if ((found & 1) == 0) { + aDeclaration->AddValue(lst, nsCSSValue(NS_STYLE_LIST_STYLE_DISC, eCSSUnit_Enumerated)); + } + if ((found & 2) == 0) { + aDeclaration->AddValue(lsp, nsCSSValue(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE, eCSSUnit_Enumerated)); + } + if ((found & 4) == 0) { + aDeclaration->AddValue(lsi, nsCSSValue(NS_STYLE_LIST_STYLE_IMAGE_NONE, eCSSUnit_Enumerated)); + } + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseMargin(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + static const char* kBoxMarginSideNames[] = { + "margin-top", + "margin-right", + "margin-bottom", + "margin-left", + }; + return ParseBoxProperties(aErrorCode, aDeclaration, kBoxMarginSideNames); +} + +PRBool CSSParserImpl::ParsePadding(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + static const char* kBoxPaddingSideNames[] = { + "padding-top", + "padding-right", + "padding-bottom", + "padding-left", + }; + return ParseBoxProperties(aErrorCode, aDeclaration, kBoxPaddingSideNames); +} + +PRBool CSSParserImpl::ParseTextDecoration(PRInt32* aErrorCode, + nsICSSDeclaration* aDeclaration, + const char* aName) +{ + static PRInt32 kTextDecorationNoneKTable[] = { + KEYWORD_NONE, NS_STYLE_TEXT_DECORATION_NONE, + -1 + }; + static PRInt32 kTextDecorationKTable[] = { + KEYWORD_UNDERLINE, NS_STYLE_TEXT_DECORATION_UNDERLINE, + KEYWORD_OVERLINE, NS_STYLE_TEXT_DECORATION_OVERLINE, + KEYWORD_LINE_THROUGH, NS_STYLE_TEXT_DECORATION_LINE_THROUGH, + KEYWORD_BLINK, NS_STYLE_TEXT_DECORATION_BLINK, + -1, + }; + + if (ParseEnum(aErrorCode, aDeclaration, aName, kTextDecorationNoneKTable)) { + return PR_TRUE; + } + + PRInt32 decoration = 0; + for (int i = 0; i < 4; i++) { + nsString* ident = NextIdent(aErrorCode); + if (nsnull == ident) { + break; + } + char cbuf[50]; + ident->ToCString(cbuf, sizeof(cbuf)); + PRInt32 id = nsCSSKeywords::LookupName(cbuf); + PRInt32 ix = SearchKeywordTable(id, kTextDecorationKTable); + if (ix < 0) { + UngetToken(); + break; + } + decoration |= kTextDecorationKTable[ix+1]; + } + if (0 == decoration) { + return PR_FALSE; + } + aDeclaration->AddValue(aName, nsCSSValue(decoration, eCSSUnit_Absolute)); + return PR_TRUE; +} diff --git a/mozilla/layout/html/style/src/nsCSSPropIDs.h b/mozilla/layout/html/style/src/nsCSSPropIDs.h new file mode 100644 index 00000000000..31ae495935f --- /dev/null +++ b/mozilla/layout/html/style/src/nsCSSPropIDs.h @@ -0,0 +1,78 @@ +/* Do not edit - generated by genhash.pl */ +#define PROP_BACKGROUND 0 +#define PROP_BACKGROUND_ATTACHMENT 1 +#define PROP_BACKGROUND_COLOR 2 +#define PROP_BACKGROUND_FILTER 3 +#define PROP_BACKGROUND_IMAGE 4 +#define PROP_BACKGROUND_POSITION 5 +#define PROP_BACKGROUND_X_POSITION 6 +#define PROP_BACKGROUND_Y_POSITION 7 +#define PROP_BACKGROUND_REPEAT 8 +#define PROP_BORDER 9 +#define PROP_BORDER_BOTTOM 10 +#define PROP_BORDER_BOTTOM_COLOR 11 +#define PROP_BORDER_BOTTOM_STYLE 12 +#define PROP_BORDER_BOTTOM_WIDTH 13 +#define PROP_BORDER_COLOR 14 +#define PROP_BORDER_LEFT 15 +#define PROP_BORDER_LEFT_COLOR 16 +#define PROP_BORDER_LEFT_STYLE 17 +#define PROP_BORDER_LEFT_WIDTH 18 +#define PROP_BORDER_RIGHT 19 +#define PROP_BORDER_RIGHT_COLOR 20 +#define PROP_BORDER_RIGHT_STYLE 21 +#define PROP_BORDER_RIGHT_WIDTH 22 +#define PROP_BORDER_STYLE 23 +#define PROP_BORDER_TOP 24 +#define PROP_BORDER_TOP_COLOR 25 +#define PROP_BORDER_TOP_STYLE 26 +#define PROP_BORDER_TOP_WIDTH 27 +#define PROP_BORDER_WIDTH 28 +#define PROP_CLEAR 29 +#define PROP_CLIP 30 +#define PROP_CLIP_BOTTOM 31 +#define PROP_CLIP_LEFT 32 +#define PROP_CLIP_RIGHT 33 +#define PROP_CLIP_TOP 34 +#define PROP_COLOR 35 +#define PROP_DISPLAY 36 +#define PROP_FILTER 37 +#define PROP_FLOAT 38 +#define PROP_FONT 39 +#define PROP_FONT_FAMILY 40 +#define PROP_FONT_SIZE 41 +#define PROP_FONT_STYLE 42 +#define PROP_FONT_VARIANT 43 +#define PROP_FONT_WEIGHT 44 +#define PROP_HEIGHT 45 +#define PROP_LEFT 46 +#define PROP_LETTER_SPACING 47 +#define PROP_LINE_HEIGHT 48 +#define PROP_LIST_STYLE 49 +#define PROP_LIST_STYLE_IMAGE 50 +#define PROP_LIST_STYLE_POSITION 51 +#define PROP_LIST_STYLE_TYPE 52 +#define PROP_MARGIN 53 +#define PROP_MARGIN_BOTTOM 54 +#define PROP_MARGIN_LEFT 55 +#define PROP_MARGIN_RIGHT 56 +#define PROP_MARGIN_TOP 57 +#define PROP_OVERFLOW 58 +#define PROP_PADDING 59 +#define PROP_PADDING_BOTTOM 60 +#define PROP_PADDING_LEFT 61 +#define PROP_PADDING_RIGHT 62 +#define PROP_PADDING_TOP 63 +#define PROP_POSITION 64 +#define PROP_TEXT_ALIGN 65 +#define PROP_TEXT_DECORATION 66 +#define PROP_TEXT_INDENT 67 +#define PROP_TEXT_TRANSFORM 68 +#define PROP_TOP 69 +#define PROP_VERTICAL_ALIGN 70 +#define PROP_VISIBILITY 71 +#define PROP_WHITE_SPACE 72 +#define PROP_WIDTH 73 +#define PROP_WORD_SPACING 74 +#define PROP_Z_INDEX 75 +#define PROP_MAX 76 diff --git a/mozilla/layout/html/style/src/nsCSSProps.cpp b/mozilla/layout/html/style/src/nsCSSProps.cpp new file mode 100644 index 00000000000..d6de955d6a3 --- /dev/null +++ b/mozilla/layout/html/style/src/nsCSSProps.cpp @@ -0,0 +1,347 @@ + +/* +** This is a generated file, do not edit it. This file is created by +** genhash.pl +*/ + +#include "plstr.h" +#include "nsCSSProps.h" +#define TOTAL_KEYWORDS 76 +#define MIN_WORD_LENGTH 3 +#define MAX_WORD_LENGTH 21 +#define MIN_HASH_VALUE 6 +#define MAX_HASH_VALUE 212 +/* maximum key range = 207, duplicates = 0 */ + + +struct StaticNameTable { + char* tag; + PRInt32 id; +}; + +static const unsigned char kLowerLookup[256] = { + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, + 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, + 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, + 64, + 97,98,99,100,101,102,103,104,105,106,107,108,109, + 110,111,112,113,114,115,116,117,118,119,120,121,122, + + 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, + + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 +}; + +#define MYLOWER(x) kLowerLookup[((x) & 0x7f)] + +/** + * Map a name to an ID or -1 + */ +PRInt32 nsCSSProps::LookupName(const char* str) +{ + static unsigned char asso_values[] = + { + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 30, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 45, 0, 85, + 45, 25, 5, 20, 80, 0, 213, 213, 25, 75, + 0, 0, 5, 213, 0, 65, 40, 213, 0, 65, + 10, 15, 10, 213, 213, 213, 213, 213, + }; + static unsigned char lengthtable[] = + { + 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 6, 12, 8, + 0, 10, 0, 0, 0, 19, 0, 0, 0, 0, 0, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, + 0, 0, 19, 0, 0, 17, 3, 4, 0, 11, 0, 0, 0, 0, + 0, 0, 18, 0, 0, 0, 12, 0, 0, 0, 11, 17, 0, 19, + 0, 0, 17, 0, 0, 5, 21, 7, 0, 0, 0, 21, 7, 18, + 14, 0, 16, 0, 13, 0, 5, 0, 12, 0, 4, 0, 0, 12, + 8, 19, 10, 16, 17, 0, 9, 10, 16, 0, 0, 0, 0, 0, + 7, 0, 19, 5, 11, 0, 0, 4, 10, 11, 0, 0, 14, 10, + 6, 17, 0, 0, 0, 16, 0, 0, 0, 10, 0, 0, 18, 0, + 0, 0, 12, 0, 0, 0, 16, 0, 0, 0, 5, 21, 0, 0, + 0, 0, 11, 0, 0, 0, 10, 16, 0, 8, 0, 15, 0, 0, + 0, 0, 15, 11, 12, 0, 0, 0, 0, 0, 0, 14, 0, 0, + 12, 13, 9, 0, 0, 0, 0, 0, 0, 6, 0, 0, 14, 0, + 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, + 0, 11, 12, + }; + static struct StaticNameTable wordlist[] = + { + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"border", 9}, + {"",}, {"",}, {"",}, {"",}, + {"filter", 37}, + {"border-color", 14}, + {"position", 64}, + {"",}, + {"border-top", 24}, + {"",}, {"",}, {"",}, + {"border-bottom-color", 11}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"visibility", 71}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, + {"font-family", 40}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"border-bottom-style", 12}, + {"",}, {"",}, + {"border-left-color", 16}, + {"top", 69}, + {"font", 39}, + {"",}, + {"border-left", 15}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"border-right-color", 20}, + {"",}, {"",}, {"",}, + {"border-style", 23}, + {"",}, {"",}, {"",}, + {"padding-top", 63}, + {"background-filter", 3}, + {"",}, + {"background-position", 5}, + {"",}, {"",}, + {"border-left-style", 17}, + {"",}, {"",}, + {"float", 38}, + {"background-x-position", 6}, + {"padding", 59}, + {"",}, {"",}, {"",}, + {"background-y-position", 7}, + {"z-index", 75}, + {"border-right-style", 21}, + {"letter-spacing", 47}, + {"",}, + {"background-image", 4}, + {"",}, + {"border-bottom", 10}, + {"",}, + {"color", 35}, + {"",}, + {"border-right", 19}, + {"",}, + {"left", 46}, + {"",}, {"",}, + {"font-variant", 43}, + {"overflow", 58}, + {"border-bottom-width", 13}, + {"background", 0}, + {"border-top-color", 25}, + {"background-repeat", 8}, + {"",}, + {"font-size", 41}, + {"font-style", 42}, + {"border-top-style", 26}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"display", 36}, + {"",}, + {"list-style-position", 51}, + {"clear", 29}, + {"text-indent", 67}, + {"",}, {"",}, + {"clip", 30}, + {"text-align", 65}, + {"font-weight", 44}, + {"",}, {"",}, + {"vertical-align", 70}, + {"list-style", 49}, + {"margin", 53}, + {"border-left-width", 18}, + {"",}, {"",}, {"",}, + {"list-style-image", 50}, + {"",}, {"",}, {"",}, + {"margin-top", 57}, + {"",}, {"",}, + {"border-right-width", 22}, + {"",}, {"",}, {"",}, + {"padding-left", 61}, + {"",}, {"",}, {"",}, + {"background-color", 2}, + {"",}, {"",}, {"",}, + {"width", 73}, + {"background-attachment", 1}, + {"",}, {"",}, {"",}, {"",}, + {"line-height", 48}, + {"",}, {"",}, {"",}, + {"clip-right", 33}, + {"border-top-width", 27}, + {"",}, + {"clip-top", 34}, + {"",}, + {"text-decoration", 66}, + {"",}, {"",}, {"",}, {"",}, + {"list-style-type", 52}, + {"margin-left", 55}, + {"border-width", 28}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"padding-bottom", 60}, + {"",}, {"",}, + {"word-spacing", 74}, + {"padding-right", 62}, + {"clip-left", 32}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"height", 45}, + {"",}, {"",}, + {"text-transform", 68}, + {"",}, + {"clip-bottom", 31}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, + {"margin-bottom", 54}, + {"",}, {"",}, + {"white-space", 72}, + {"margin-right", 56}, + }; + + if (str != NULL) { + int len = PL_strlen(str); + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) { + register int hval = len; + + switch (hval) + { + default: + case 12: + hval += asso_values[MYLOWER(str[11])]; + case 11: + case 10: + case 9: + case 8: + case 7: + case 6: + hval += asso_values[MYLOWER(str[5])]; + case 5: + case 4: + case 3: + case 2: + hval += asso_values[MYLOWER(str[1])]; + case 1: + hval += asso_values[MYLOWER(str[0])]; + break; + } + hval += asso_values[MYLOWER(str[len - 1])]; + if (hval <= MAX_HASH_VALUE && hval >= MIN_HASH_VALUE) { + if (len == lengthtable[hval]) { + register const char *tag = wordlist[hval].tag; + + /* + ** While not at the end of the string, if they ever differ + ** they are not equal. We know "tag" is already lower case. + */ + while ((*tag != '\0')&&(*str != '\0')) { + if (*tag != (char) MYLOWER(*str)) { + return -1; + } + tag++; + str++; + } + + /* + ** One of the strings has ended, if they are both ended, then they + ** are equal, otherwise not. + */ + if ((*tag == '\0')&&(*str == '\0')) { + return wordlist[hval].id; + } + } + } + } + } + return -1; +} + +const nsCSSProps::NameTableEntry nsCSSProps::kNameTable[] = { + { "background", 0 }, + { "background-attachment", 1 }, + { "background-color", 2 }, + { "background-filter", 3 }, + { "background-image", 4 }, + { "background-position", 5 }, + { "background-x-position", 6 }, + { "background-y-position", 7 }, + { "background-repeat", 8 }, + { "border", 9 }, + { "border-bottom", 10 }, + { "border-bottom-color", 11 }, + { "border-bottom-style", 12 }, + { "border-bottom-width", 13 }, + { "border-color", 14 }, + { "border-left", 15 }, + { "border-left-color", 16 }, + { "border-left-style", 17 }, + { "border-left-width", 18 }, + { "border-right", 19 }, + { "border-right-color", 20 }, + { "border-right-style", 21 }, + { "border-right-width", 22 }, + { "border-style", 23 }, + { "border-top", 24 }, + { "border-top-color", 25 }, + { "border-top-style", 26 }, + { "border-top-width", 27 }, + { "border-width", 28 }, + { "clear", 29 }, + { "clip", 30 }, + { "clip-bottom", 31 }, + { "clip-left", 32 }, + { "clip-right", 33 }, + { "clip-top", 34 }, + { "color", 35 }, + { "display", 36 }, + { "filter", 37 }, + { "float", 38 }, + { "font", 39 }, + { "font-family", 40 }, + { "font-size", 41 }, + { "font-style", 42 }, + { "font-variant", 43 }, + { "font-weight", 44 }, + { "height", 45 }, + { "left", 46 }, + { "letter-spacing", 47 }, + { "line-height", 48 }, + { "list-style", 49 }, + { "list-style-image", 50 }, + { "list-style-position", 51 }, + { "list-style-type", 52 }, + { "margin", 53 }, + { "margin-bottom", 54 }, + { "margin-left", 55 }, + { "margin-right", 56 }, + { "margin-top", 57 }, + { "overflow", 58 }, + { "padding", 59 }, + { "padding-bottom", 60 }, + { "padding-left", 61 }, + { "padding-right", 62 }, + { "padding-top", 63 }, + { "position", 64 }, + { "text-align", 65 }, + { "text-decoration", 66 }, + { "text-indent", 67 }, + { "text-transform", 68 }, + { "top", 69 }, + { "vertical-align", 70 }, + { "visibility", 71 }, + { "white-space", 72 }, + { "width", 73 }, + { "word-spacing", 74 }, + { "z-index", 75 }, +}; diff --git a/mozilla/layout/html/style/src/nsCSSProps.h b/mozilla/layout/html/style/src/nsCSSProps.h new file mode 100644 index 00000000000..29bd8de6945 --- /dev/null +++ b/mozilla/layout/html/style/src/nsCSSProps.h @@ -0,0 +1,40 @@ +/* -*- 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. + */ +#ifndef nsCSSProps_h___ +#define nsCSSProps_h___ + +#include "nslayout.h" +#include "nsCSSPropIDs.h" + +class NS_LAYOUT nsCSSProps { +public: + // Given a null terminated string of 7 bit characters, return the + // tag id (see nsCSSPropIDs.h) for the tag or -1 if the tag is not + // known. The lookup function uses a perfect hash. + static PRInt32 LookupName(const char* str); + + struct NameTableEntry { + const char* name; + PRInt32 id; + }; + + // A table whose index is the tag id (from nsCSSPropIDs) + static const NameTableEntry kNameTable[]; +}; + +#endif /* nsCSSProps_h___ */ diff --git a/mozilla/layout/html/style/src/nsCSSRendering.cpp b/mozilla/layout/html/style/src/nsCSSRendering.cpp new file mode 100644 index 00000000000..0657a084095 --- /dev/null +++ b/mozilla/layout/html/style/src/nsCSSRendering.cpp @@ -0,0 +1,785 @@ +/* -*- 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 "nsCSSRendering.h" +#include "nsStyleConsts.h" +#include "nsIPresContext.h" +#include "nsIImage.h" +#include "nsIFrame.h" +#include "nsPoint.h" +#include "nsRect.h" +#include "nsIViewManager.h" +#include "nsIPresShell.h" + +#define BORDER_FULL 0 //entire side +#define BORDER_INSIDE 1 //inside half +#define BORDER_OUTSIDE 2 //outside half + +//thickness of dashed line relative to dotted line +#define DOT_LENGTH 1 //square +#define DASH_LENGTH 3 //3 times longer than dot + +/** + * Special method to brighten a Color and have it shift to white when + * fully saturated. + */ +nscolor nsCSSRendering::Brighten(nscolor inColor) +{ + PRIntn r, g, b, max, over; + + r = NS_GET_R(inColor); + g = NS_GET_G(inColor); + b = NS_GET_B(inColor); + + //10% of max color increase across the board + r += 25; + g += 25; + b += 25; + + //figure out which color is largest + if (r > g) + { + if (b > r) + max = b; + else + max = r; + } + else + { + if (b > g) + max = b; + else + max = g; + } + + //if we overflowed on this max color, increase + //other components by the overflow amount + if (max > 255) + { + over = max - 255; + + if (max == r) + { + g += over; + b += over; + } + else if (max == g) + { + r += over; + b += over; + } + else + { + r += over; + g += over; + } + } + + //clamp + if (r > 255) + r = 255; + if (g > 255) + g = 255; + if (b > 255) + b = 255; + + return NS_RGBA(r, g, b, NS_GET_A(inColor)); +} + +/** + * Special method to darken a Color and have it shift to black when + * darkest component underflows + */ +nscolor nsCSSRendering::Darken(nscolor inColor) +{ + PRIntn r, g, b, max; + + r = NS_GET_R(inColor); + g = NS_GET_G(inColor); + b = NS_GET_B(inColor); + + //10% of max color decrease across the board + r -= 25; + g -= 25; + b -= 25; + + //figure out which color is largest + if (r > g) + { + if (b > r) + max = b; + else + max = r; + } + else + { + if (b > g) + max = b; + else + max = g; + } + + //if we underflowed on this max color, decrease + //other components by the underflow amount + if (max < 0) + { + if (max == r) + { + g += max; + b += max; + } + else if (max == g) + { + r += max; + b += max; + } + else + { + r += max; + g += max; + } + } + + //clamp + if (r < 0) + r = 0; + if (g < 0) + g = 0; + if (b < 0) + b = 0; + + return NS_RGBA(r, g, b, NS_GET_A(inColor)); +} + +/** + * Make a bevel color + */ +nscolor nsCSSRendering::MakeBevelColor(PRIntn whichSide, PRUint8 style, + nscolor baseColor) +{ + nscolor theColor = baseColor; + + if ((style == NS_STYLE_BORDER_STYLE_OUTSET) || + (style == NS_STYLE_BORDER_STYLE_RIDGE)) { + // Flip colors for these two border style + switch (whichSide) { + case NS_SIDE_BOTTOM: whichSide = NS_SIDE_TOP; break; + case NS_SIDE_RIGHT: whichSide = NS_SIDE_LEFT; break; + case NS_SIDE_TOP: whichSide = NS_SIDE_BOTTOM; break; + case NS_SIDE_LEFT: whichSide = NS_SIDE_RIGHT; break; + } + } + + switch (whichSide) { + case NS_SIDE_BOTTOM: + theColor = Brighten(Brighten(baseColor)); + break; + case NS_SIDE_RIGHT: + theColor = Brighten(baseColor); + break; + case NS_SIDE_TOP: + theColor = Darken(Darken(baseColor)); + break; + case NS_SIDE_LEFT: + theColor = Darken(baseColor); + break; + } + return theColor; +} + +// Maximum poly points in any of the polygons we generate below +#define MAX_POLY_POINTS 4 + +// a nifty helper function to create a polygon representing a +// particular side of a border. This helps localize code for figuring +// mitered edges. It is mainly used by the solid, inset, and outset +// styles... +PRIntn nsCSSRendering::MakeSide(nsPoint aPoints[], + nsIRenderingContext& aContext, + PRIntn whichSide, + const nsRect& inside, const nsRect& outside, + PRIntn borderPart, float borderFrac) +{ + float borderRest = 1.0f - borderFrac; + + // XXX QQQ We really should decide to do a bevel based on whether there + // is a side adjacent or not. This could let you join borders across + // block elements (paragraphs). + + PRIntn np = 0; + switch (whichSide) { + case NS_SIDE_TOP: + if (borderPart == BORDER_FULL) { + aPoints[np++].MoveTo(outside.x, outside.y); + aPoints[np++].MoveTo(outside.XMost(), outside.y); + aPoints[np++].MoveTo(inside.XMost(), inside.y); + aPoints[np++].MoveTo(inside.x, inside.y); + } else if (borderPart == BORDER_INSIDE) { + aPoints[np++].MoveTo(nscoord(outside.x * borderFrac + + inside.x * borderRest), + nscoord(outside.y * borderFrac + + inside.y * borderRest)); + aPoints[np++].MoveTo(nscoord(outside.XMost() * borderFrac + + inside.XMost() * borderRest), + nscoord(outside.y * borderFrac + + inside.y * borderRest)); + aPoints[np++].MoveTo(inside.XMost(), inside.y); + aPoints[np++].MoveTo(inside.x, inside.y); + } else { + aPoints[np++].MoveTo(outside.x, outside.y); + aPoints[np++].MoveTo(outside.XMost(), outside.y); + aPoints[np++].MoveTo(nscoord(inside.XMost() * borderFrac + + outside.XMost() * borderRest), + nscoord(inside.y * borderFrac + + outside.y * borderRest)); + aPoints[np++].MoveTo(nscoord(inside.x * borderFrac + + outside.x * borderRest), + nscoord(inside.y * borderFrac + + outside.y * borderRest)); + } + break; + + case NS_SIDE_LEFT: + if (borderPart == BORDER_FULL) { + aPoints[np++].MoveTo(outside.x, outside.y); + aPoints[np++].MoveTo(inside.x, inside.y); + aPoints[np++].MoveTo(inside.x, inside.YMost()); + aPoints[np++].MoveTo(outside.x, outside.YMost()); + } else if (borderPart == BORDER_INSIDE) { + aPoints[np++].MoveTo(nscoord(outside.x * borderFrac + + inside.x * borderRest), + nscoord(outside.y * borderFrac + + inside.y * borderRest)); + aPoints[np++].MoveTo(inside.x, inside.y); + aPoints[np++].MoveTo(inside.x, inside.YMost()); + aPoints[np++].MoveTo(nscoord(outside.x * borderFrac + + inside.x * borderRest), + nscoord(outside.YMost() * borderFrac + + inside.YMost() * borderRest)); + } else { + aPoints[np++].MoveTo(outside.x, outside.y); + aPoints[np++].MoveTo(nscoord(inside.x * borderFrac + + outside.x * borderRest), + nscoord(inside.y * borderFrac + + outside.y * borderRest)); + aPoints[np++].MoveTo(nscoord(inside.x * borderFrac + + outside.x * borderRest), + nscoord(inside.YMost() * borderFrac + + outside.YMost() * borderRest)); + aPoints[np++].MoveTo(outside.x, outside.YMost()); + } + break; + + case NS_SIDE_BOTTOM: + if (borderPart == BORDER_FULL) { + aPoints[np++].MoveTo(outside.x, outside.YMost()); + aPoints[np++].MoveTo(inside.x, inside.YMost()); + aPoints[np++].MoveTo(inside.XMost(), inside.YMost()); + aPoints[np++].MoveTo(outside.XMost(), outside.YMost()); + } else if (borderPart == BORDER_INSIDE) { + aPoints[np++].MoveTo(nscoord(outside.x * borderFrac + + inside.x * borderRest), + nscoord(outside.YMost() * borderFrac + + inside.YMost() * borderRest)); + aPoints[np++].MoveTo(inside.x, inside.YMost()); + aPoints[np++].MoveTo(inside.XMost(), inside.YMost()); + aPoints[np++].MoveTo(nscoord(outside.XMost() * borderFrac + + inside.XMost() * borderRest), + nscoord(outside.YMost() * borderFrac + + inside.YMost() * borderRest)); + } else { + aPoints[np++].MoveTo(outside.x, outside.YMost()); + aPoints[np++].MoveTo(nscoord(inside.x * borderFrac + + outside.x * borderRest), + nscoord(inside.YMost() * borderFrac + + outside.YMost() * borderRest)); + aPoints[np++].MoveTo(nscoord(inside.XMost() * borderFrac + + outside.XMost() * borderRest), + nscoord(inside.YMost() * borderFrac + + outside.YMost() * borderRest)); + aPoints[np++].MoveTo(outside.XMost(), outside.YMost()); + } + break; + + case NS_SIDE_RIGHT: + if (borderPart == BORDER_FULL) { + aPoints[np++].MoveTo(inside.XMost(), inside.y); + aPoints[np++].MoveTo(outside.XMost(), outside.y); + aPoints[np++].MoveTo(outside.XMost(), outside.YMost()); + aPoints[np++].MoveTo(inside.XMost(), inside.YMost()); + } else if (borderPart == BORDER_INSIDE) { + aPoints[np++].MoveTo(inside.XMost(), inside.y); + aPoints[np++].MoveTo(nscoord(outside.XMost() * borderFrac + + inside.XMost() * borderRest), + nscoord(outside.y * borderFrac + + inside.y * borderRest)); + aPoints[np++].MoveTo(nscoord(outside.XMost() * borderFrac + + inside.XMost() * borderRest), + nscoord(outside.YMost() * borderFrac + + inside.YMost() * borderRest)); + aPoints[np++].MoveTo(inside.XMost(), inside.YMost()); + } else { + aPoints[np++].MoveTo(nscoord(inside.XMost() * borderFrac + + outside.XMost() * borderRest), + nscoord(inside.y * borderFrac + + outside.y * borderRest)); + aPoints[np++].MoveTo(outside.XMost(), outside.y); + aPoints[np++].MoveTo(outside.XMost(), outside.YMost()); + aPoints[np++].MoveTo(nscoord(inside.XMost() * borderFrac + + outside.XMost() * borderRest), + nscoord(inside.YMost() * borderFrac + + outside.YMost() * borderRest)); + } + break; + } + return np; +} + +void nsCSSRendering::DrawSide(nsIRenderingContext& aContext, + PRIntn whichSide, + const PRUint8 borderStyles[], + const nscolor borderColors[], + const nsRect& borderOutside, + const nsRect& borderInside) +{ + nsPoint theSide[MAX_POLY_POINTS]; + nscolor theColor = borderColors[whichSide]; + PRUint8 theStyle = borderStyles[whichSide]; + PRInt32 np; + switch (theStyle) { + case NS_STYLE_BORDER_STYLE_NONE: + case NS_STYLE_BORDER_STYLE_BLANK: + return; + + case NS_STYLE_BORDER_STYLE_DOTTED: //handled a special case elsewhere + case NS_STYLE_BORDER_STYLE_DASHED: //handled a special case elsewhere + break; // That was easy... + + case NS_STYLE_BORDER_STYLE_GROOVE: + case NS_STYLE_BORDER_STYLE_RIDGE: + np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside, + BORDER_INSIDE, 0.5f); + aContext.SetColor ( MakeBevelColor (whichSide, theStyle, theColor)); + aContext.FillPolygon (theSide, np); + np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside, + BORDER_OUTSIDE, 0.5f); + aContext.SetColor ( MakeBevelColor (whichSide, + (theStyle == NS_STYLE_BORDER_STYLE_RIDGE) + ? NS_STYLE_BORDER_STYLE_GROOVE + : NS_STYLE_BORDER_STYLE_RIDGE, theColor)); + aContext.FillPolygon (theSide, np); + break; + + case NS_STYLE_BORDER_STYLE_SOLID: + np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside, + BORDER_FULL, 1.0f); + aContext.SetColor (borderColors[whichSide]); + aContext.FillPolygon (theSide, np); + break; + + case NS_STYLE_BORDER_STYLE_DOUBLE: + np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside, + BORDER_INSIDE, 0.333333f); + aContext.SetColor (borderColors[whichSide]); + aContext.FillPolygon (theSide, np); + np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside, + BORDER_OUTSIDE, 0.333333f); + aContext.FillPolygon (theSide, np); + break; + + case NS_STYLE_BORDER_STYLE_OUTSET: + case NS_STYLE_BORDER_STYLE_INSET: + np = MakeSide (theSide, aContext, whichSide, borderOutside, borderInside, + BORDER_FULL, 1.0f); + aContext.SetColor ( MakeBevelColor (whichSide, theStyle, theColor)); + aContext.FillPolygon (theSide, np); + break; + } +} + +/** + * Draw a dotted/dashed sides of a box + */ +//XXX dashes which span more than two edges are not handled properly MMP +void nsCSSRendering::DrawDashedSides(PRIntn startSide, + nsIRenderingContext& aContext, + const PRUint8 borderStyles[], + const nscolor borderColors[], + const nsRect& borderOutside, + const nsRect& borderInside, + PRIntn aSkipSides) +{ + PRIntn dashLength; + nsRect dashRect, firstRect, currRect; + + PRBool bSolid = PR_TRUE; + float over = 0.0f; + PRUint8 style = borderStyles[startSide]; + PRBool skippedSide = PR_FALSE; + for (PRIntn whichSide = startSide; whichSide < 4; whichSide++) { + PRUint8 prevStyle = style; + style = borderStyles[whichSide]; + if ((1< 0.0f) { + firstRect.x = dashRect.x; + firstRect.width = dashRect.width; + firstRect.height = nscoord(dashRect.height * over); + firstRect.y = dashRect.y + (dashRect.height - firstRect.height); + over = 0.0f; + currRect = firstRect; + } else { + currRect = dashRect; + } + + while (currRect.YMost() > borderInside.y) { + //clip if necessary + if (currRect.y < borderInside.y) { + over = float(borderInside.y - dashRect.y) / + float(dashRect.height); + currRect.height = currRect.height - (borderInside.y - currRect.y); + currRect.y = borderInside.y; + } + + //draw if necessary + if (bSolid) { + aContext.FillRect(currRect); + } + + //setup for next iteration + if (over == 0.0f) { + bSolid = PRBool(!bSolid); + } + dashRect.y = dashRect.y - currRect.height; + currRect = dashRect; + } + break; + + case NS_SIDE_TOP: + //if we are continuing a solid rect, fill in the corner first + if (bSolid) { + aContext.FillRect(borderOutside.x, borderOutside.y, + borderInside.x - borderOutside.x, + borderInside.y - borderOutside.y); + } + + dashRect.height = borderInside.y - borderOutside.y; + dashRect.width = dashRect.height * dashLength; + dashRect.x = borderInside.x; + dashRect.y = borderOutside.y; + + if (over > 0.0f) { + firstRect.x = dashRect.x; + firstRect.y = dashRect.y; + firstRect.width = nscoord(dashRect.width * over); + firstRect.height = dashRect.height; + over = 0.0f; + currRect = firstRect; + } else { + currRect = dashRect; + } + + while (currRect.x < borderInside.XMost()) { + //clip if necessary + if (currRect.XMost() > borderInside.XMost()) { + over = float(dashRect.XMost() - borderInside.XMost()) / + float(dashRect.width); + currRect.width = currRect.width - + (currRect.XMost() - borderInside.XMost()); + } + + //draw if necessary + if (bSolid) { + aContext.FillRect(currRect); + } + + //setup for next iteration + if (over == 0.0f) { + bSolid = PRBool(!bSolid); + } + dashRect.x = dashRect.x + currRect.width; + currRect = dashRect; + } + break; + + case NS_SIDE_RIGHT: + //if we are continuing a solid rect, fill in the corner first + if (bSolid) { + aContext.FillRect(borderInside.XMost(), borderOutside.y, + borderOutside.XMost() - borderInside.XMost(), + borderInside.y - borderOutside.y); + } + + dashRect.width = borderOutside.XMost() - borderInside.XMost(); + dashRect.height = nscoord(dashRect.width * dashLength); + dashRect.x = borderInside.XMost(); + dashRect.y = borderInside.y; + + if (over > 0.0f) { + firstRect.x = dashRect.x; + firstRect.y = dashRect.y; + firstRect.width = dashRect.width; + firstRect.height = nscoord(dashRect.height * over); + over = 0.0f; + currRect = firstRect; + } else { + currRect = dashRect; + } + + while (currRect.y < borderInside.YMost()) { + //clip if necessary + if (currRect.YMost() > borderInside.YMost()) { + over = float(dashRect.YMost() - borderInside.YMost()) / + float(dashRect.height); + currRect.height = currRect.height - + (currRect.YMost() - borderInside.YMost()); + } + + //draw if necessary + if (bSolid) { + aContext.FillRect(currRect); + } + + //setup for next iteration + if (over == 0.0f) { + bSolid = PRBool(!bSolid); + } + dashRect.y = dashRect.y + currRect.height; + currRect = dashRect; + } + break; + + case NS_SIDE_BOTTOM: + //if we are continuing a solid rect, fill in the corner first + if (bSolid) { + aContext.FillRect(borderInside.XMost(), borderInside.YMost(), + borderOutside.XMost() - borderInside.XMost(), + borderOutside.YMost() - borderInside.YMost()); + } + + dashRect.height = borderOutside.YMost() - borderInside.YMost(); + dashRect.width = nscoord(dashRect.height * dashLength); + dashRect.x = borderInside.XMost() - dashRect.width; + dashRect.y = borderInside.YMost(); + + if (over > 0.0f) { + firstRect.y = dashRect.y; + firstRect.width = nscoord(dashRect.width * over); + firstRect.height = dashRect.height; + firstRect.x = dashRect.x + (dashRect.width - firstRect.width); + over = 0.0f; + currRect = firstRect; + } else { + currRect = dashRect; + } + + while (currRect.XMost() > borderInside.x) { + //clip if necessary + if (currRect.x < borderInside.x) { + over = float(borderInside.x - dashRect.x) / float(dashRect.width); + currRect.width = currRect.width - (borderInside.x - currRect.x); + currRect.x = borderInside.x; + } + + //draw if necessary + if (bSolid) { + aContext.FillRect(currRect); + } + + //setup for next iteration + if (over == 0.0f) { + bSolid = PRBool(!bSolid); + } + dashRect.x = dashRect.x - currRect.width; + currRect = dashRect; + } + break; + } + } + skippedSide = PR_FALSE; + } +} + +// XXX improve this to constrain rendering to the damaged area +void nsCSSRendering::PaintBorder(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + nsIFrame* aForFrame, + const nsRect& aDirtyRect, + const nsRect& aBounds, + const nsStyleMolecule& aMolecule, + PRIntn aSkipSides) +{ + const nsMargin& border = aMolecule.border; + if ((0 == border.left) && (0 == border.right) && + (0 == border.top) && (0 == border.bottom)) { + // Empty border area + return; + } + + nsRect inside(0, 0, aBounds.width, aBounds.height); + nsRect outside(inside); + outside.Deflate(border); + + //see if any sides are dotted or dashed + for (PRIntn cnt = 0; cnt < 4; cnt++) { + if ((aMolecule.borderStyle[cnt] == NS_STYLE_BORDER_STYLE_DOTTED) || + (aMolecule.borderStyle[cnt] == NS_STYLE_BORDER_STYLE_DASHED)) { + break; + } + } + if (cnt < 4) { + // Draw the dashed/dotted lines first + DrawDashedSides(cnt, aRenderingContext, aMolecule.borderStyle, + aMolecule.borderColor, inside, outside, + aSkipSides); + } + + // Draw all the other sides + if (0 == (aSkipSides & (1<NeedsBlend()) { + if (0 == (aColor.mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT)) { + aRenderingContext.SetColor(aColor.mBackgroundColor); + aRenderingContext.FillRect(0, 0, aBounds.width, aBounds.height); + } + } +#endif + + // Convert image dimensions into nscoord's + float p2t = aPresContext.GetPixelsToTwips(); + nscoord tileWidth = nscoord(p2t * image->GetWidth()); + nscoord tileHeight = nscoord(p2t * image->GetHeight()); + + PRIntn repeat = aColor.mBackgroundRepeat; + PRIntn xcount, ycount; + switch (aColor.mBackgroundRepeat) { + case NS_STYLE_BG_REPEAT_OFF: + default: + xcount = 0; + ycount = 0; + break; + case NS_STYLE_BG_REPEAT_X: + xcount = (PRIntn) (aBounds.width / tileWidth); + ycount = 0; + break; + case NS_STYLE_BG_REPEAT_Y: + xcount = 0; + ycount = (PRIntn) (aBounds.height / tileHeight); + break; + case NS_STYLE_BG_REPEAT_XY: + xcount = (PRIntn) (aBounds.width / tileWidth); + ycount = (PRIntn) (aBounds.height / tileHeight); + break; + } + + // Tile the background + nscoord xpos = 0, ypos = 0; + nscoord xpos0 = 0; +#if XXX + // XXX support offset positioning + PRIntn xPos = aColor.mBackgroundXPosition; + PRIntn yPos = aColor.mBackgroundXPosition; +#endif + aRenderingContext.PushState(); + aRenderingContext.SetClipRect(aDirtyRect, PR_TRUE); + PRIntn x, y; + for (y = 0; y <= ycount; ++y, ypos += tileHeight) { + for (x = 0, xpos = xpos0; x <= xcount; ++x, xpos += tileWidth) { + aRenderingContext.DrawImage(image, xpos, ypos); + } + } + aRenderingContext.PopState(); + } else { + if (0 == (aColor.mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT)) { + // XXX This step can be avoided if we have an image and it doesn't + // have any transparent pixels and the image is tiled in both + // the x and the y + aRenderingContext.SetColor(aColor.mBackgroundColor); + aRenderingContext.FillRect(0, 0, aBounds.width, aBounds.height); + } + } +} diff --git a/mozilla/layout/html/style/src/nsCSSRendering.h b/mozilla/layout/html/style/src/nsCSSRendering.h new file mode 100644 index 00000000000..e1b80fa7b17 --- /dev/null +++ b/mozilla/layout/html/style/src/nsCSSRendering.h @@ -0,0 +1,89 @@ +/* -*- 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. + */ +#ifndef nsCSSRendering_h___ +#define nsCSSRendering_h___ + +#include "nsIRenderingContext.h" +#include "nsIStyleContext.h" +struct nsPoint; + +class nsCSSRendering { +public: + /** + * Render the border for an element using css rendering rules + * for borders. aSkipSides is a bitmask of the sides to skip + * when rendering. If 0 then no sides are skipped. + */ + static void PaintBorder(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + nsIFrame* aForFrame, + const nsRect& aDirtyRect, + const nsRect& aBounds, + const nsStyleMolecule& aMolecule, + PRIntn aSkipSides); + + /** + * Render the background for an element using css rendering rules + * for backgrounds. + */ + static void PaintBackground(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + nsIFrame* aForFrame, + const nsRect& aDirtyRect, + const nsRect& aBounds, + const nsStyleColor& aColor); + + /** + * Special method to brighten a Color and have it shift to white when + * fully saturated. + */ + static nscolor Brighten(nscolor inColor); + + /** + * Special method to darken a Color and have it shift to black when + * darkest component underflows + */ + static nscolor Darken(nscolor inColor); + +protected: + static nscolor MakeBevelColor(PRIntn whichSide, PRUint8 style, + nscolor baseColor); + + static PRIntn MakeSide(nsPoint aPoints[], + nsIRenderingContext& aContext, + PRIntn whichSide, + const nsRect& inside, const nsRect& outside, + PRIntn borderPart, float borderFrac); + + static void DrawSide(nsIRenderingContext& aContext, + PRIntn whichSide, + const PRUint8 borderStyles[], + const nscolor borderColors[], + const nsRect& borderOutside, + const nsRect& borderInside); + + static void DrawDashedSides(PRIntn startSide, + nsIRenderingContext& aContext, + const PRUint8 borderStyles[], + const nscolor borderColors[], + const nsRect& borderOutside, + const nsRect& borderInside, + PRIntn aSkipSides); +}; + +#endif /* nsCSSRendering_h___ */ diff --git a/mozilla/layout/html/style/src/nsCSSScanner.cpp b/mozilla/layout/html/style/src/nsCSSScanner.cpp new file mode 100644 index 00000000000..50f64a93f29 --- /dev/null +++ b/mozilla/layout/html/style/src/nsCSSScanner.cpp @@ -0,0 +1,585 @@ +/* -*- 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 "nsCSSScanner.h" +#include "nsIInputStream.h" +#include "nsIUnicharInputStream.h" +#include "nsString.h" +#include "nsCRT.h" + +#ifdef NS_DEBUG +static char* kNullPointer = "null pointer"; +#endif + +// Don't bother collecting whitespace characters in token's mIdent buffer +#undef COLLECT_WHITESPACE + +#define BUFFER_SIZE 256 + +static const PRUnichar CSS_ESCAPE = PRUnichar('\\'); + +static const PRUint8 IS_LATIN1 = 0x01; +static const PRUint8 IS_DIGIT = 0x02; +static const PRUint8 IS_HEX_DIGIT = 0x04; +static const PRUint8 IS_ALPHA = 0x08; +static const PRUint8 START_IDENT = 0x10; +static const PRUint8 IS_IDENT = 0x20; +static const PRUint8 IS_WHITESPACE = 0x40; + +static PRUint8* gLexTable; + +static void BuildLexTable() +{ + PRUint8* lt = new PRUint8[256]; + nsCRT::zero(lt, 256); + gLexTable = lt; + + int i; + lt[CSS_ESCAPE] = START_IDENT; + lt['-'] |= IS_IDENT; + // XXX add in other whitespace chars + lt[' '] |= IS_WHITESPACE; + lt['\t'] |= IS_WHITESPACE; + lt['\r'] |= IS_WHITESPACE; + lt['\n'] |= IS_WHITESPACE; + for (i = 161; i <= 255; i++) { + lt[i] |= IS_LATIN1 | IS_IDENT | START_IDENT; + } + for (i = '0'; i <= '9'; i++) { + lt[i] |= IS_DIGIT | IS_HEX_DIGIT | IS_IDENT; + } + for (i = 'A'; i <= 'Z'; i++) { + if ((i >= 'A') && (i <= 'F')) { + lt[i] |= IS_HEX_DIGIT; + lt[i+32] |= IS_HEX_DIGIT; + } + lt[i] |= IS_ALPHA | IS_IDENT | START_IDENT; + lt[i+32] |= IS_ALPHA | IS_IDENT | START_IDENT; + } +} + +nsCSSToken::nsCSSToken() +{ + mType = eCSSToken_Symbol; +} + +nsCSSScanner::nsCSSScanner() +{ + if (nsnull == gLexTable) { + // XXX need a monitor + BuildLexTable(); + } + mInput = nsnull; + mBuffer = new PRUnichar[BUFFER_SIZE]; + mOffset = 0; + mCount = 0; + mLookAhead = -1; +} + +nsCSSScanner::~nsCSSScanner() +{ + Close(); + if (nsnull != mBuffer) { + delete mBuffer; + mBuffer = nsnull; + } +} + +void nsCSSScanner::Init(nsIUnicharInputStream* aInput) +{ + NS_PRECONDITION(nsnull != aInput, kNullPointer); + Close(); + mInput = aInput; + if (nsnull != aInput) { + aInput->AddRef(); + } +} + +void nsCSSScanner::Close() +{ + NS_IF_RELEASE(mInput); +} + +// Returns -1 on error or eof +PRInt32 nsCSSScanner::Read(PRInt32* aErrorCode) +{ + PRInt32 rv; + if (mLookAhead >= 0) { + rv = mLookAhead; + mLookAhead = -1; + } else { + if (mCount < 0) { + return -1; + } + if (mOffset == mCount) { + mOffset = 0; + mCount = mInput->Read(aErrorCode, mBuffer, 0, BUFFER_SIZE); + if (mCount <= 0) { + return -1; + } + } + rv = PRInt32(mBuffer[mOffset++]); + } + mLastRead = rv; +//printf("Read => %x\n", rv); + return rv; +} + +PRInt32 nsCSSScanner::Peek(PRInt32* aErrorCode) +{ + if (mLookAhead < 0) { + mLookAhead = Read(aErrorCode); + if (mLookAhead < 0) { + return -1; + } + } +//printf("Peek => %x\n", mLookAhead); + return mLookAhead; +} + +void nsCSSScanner::Unread() +{ + NS_PRECONDITION((mLastRead >= 0) && (mLookAhead < 0), "double pushback"); + mLookAhead = mLastRead; + mLastRead = -1; +} + +PRBool nsCSSScanner::LookAhead(PRInt32* aErrorCode, PRUnichar aChar) +{ + PRInt32 ch = Read(aErrorCode); + if (ch < 0) { + return PR_FALSE; + } + if (ch == aChar) { + return PR_TRUE; + } + Unread(); + return PR_FALSE; +} + +PRBool nsCSSScanner::EatWhiteSpace(PRInt32* aErrorCode) +{ + PRBool eaten = PR_FALSE; + for (;;) { + PRInt32 ch = Read(aErrorCode); + if (ch < 0) { + break; + } + if ((ch == ' ') || (ch == '\n') || (ch == '\r') || (ch == '\t')) { + eaten = PR_TRUE; + continue; + } + Unread(); + break; + } + return eaten; +} + +PRBool nsCSSScanner::EatNewline(PRInt32* aErrorCode) +{ + PRInt32 ch = Read(aErrorCode); + if (ch < 0) { + return PR_FALSE; + } + PRBool eaten = PR_FALSE; + if (ch == '\r') { + eaten = PR_TRUE; + ch = Peek(aErrorCode); + if (ch == '\n') { + (void) Read(aErrorCode); + } + } else if (ch == '\n') { + eaten = PR_TRUE; + } else { + Unread(); + } + return eaten; +} + +PRBool nsCSSScanner::Next(PRInt32* aErrorCode, nsCSSToken* aToken) +{ + PRInt32 ch = Read(aErrorCode); + if (ch < 0) { + return PR_FALSE; + } + if (ch < 256) { + PRUint8* lexTable = gLexTable; + + // IDENT + if ((lexTable[ch] & START_IDENT) != 0) { + return ParseIdent(aErrorCode, ch, aToken); + } + + // AT_KEYWORD + if (ch == '@') { + PRInt32 nextChar = Peek(aErrorCode); + if ((nextChar >= 0) && (nextChar <= 255)) { + if ((lexTable[nextChar] & START_IDENT) != 0) { + return ParseAtKeyword(aErrorCode, ch, aToken); + } + } + } + + // NUMBER or DIM + if ((ch == '.') || (ch == '+') || (ch == '-')) { + PRInt32 nextChar = Peek(aErrorCode); + if ((nextChar >= 0) && (nextChar <= 255)) { + if ((lexTable[nextChar] & IS_DIGIT) != 0) { + return ParseNumber(aErrorCode, ch, aToken); + } + } + } + if ((lexTable[ch] & IS_DIGIT) != 0) { + return ParseNumber(aErrorCode, ch, aToken); + } + + // ID + if (ch == '#') { + return ParseID(aErrorCode, ch, aToken); + } + + // STRING + if ((ch == '"') || (ch == '\'')) { + return ParseString(aErrorCode, ch, aToken); + } + + // WS + if ((lexTable[ch] & IS_WHITESPACE) != 0) { + aToken->mType = eCSSToken_WhiteSpace; + aToken->mIdent.SetLength(0); + aToken->mIdent.Append(PRUnichar(ch)); + (void) EatWhiteSpace(aErrorCode); + return PR_TRUE; + } + if (ch == '/') { + PRInt32 nextChar = Peek(aErrorCode); + if (nextChar == '/') { + (void) Read(aErrorCode); + aToken->mIdent.SetLength(0); + aToken->mIdent.Append(PRUnichar(ch)); + aToken->mIdent.Append(PRUnichar(ch)); + return ParseEOLComment(aErrorCode, aToken); + } else if (nextChar == '*') { + (void) Read(aErrorCode); + aToken->mIdent.SetLength(0); + aToken->mIdent.Append(PRUnichar(ch)); + aToken->mIdent.Append(PRUnichar(nextChar)); + return ParseCComment(aErrorCode, aToken); + } + } + } + aToken->mType = eCSSToken_Symbol; + aToken->mSymbol = ch; + return PR_TRUE; +} + +PRInt32 nsCSSScanner::ParseEscape(PRInt32* aErrorCode) +{ + PRUint8* lexTable = gLexTable; + PRInt32 ch = Peek(aErrorCode); + if (ch < 0) { + return CSS_ESCAPE; + } + if ((ch <= 255) && ((lexTable[ch] & IS_HEX_DIGIT) != 0)) { + PRInt32 rv = 0; + for (int i = 0; i < 4; i++) { + ch = Read(aErrorCode); + if (ch < 0) { + // Whoops: error or premature eof + break; + } + if ((lexTable[ch] & IS_HEX_DIGIT) != 0) { + if ((lexTable[ch] & IS_DIGIT) != 0) { + rv = rv * 16 + (ch - '0'); + } else { + // Note: c&7 just keeps the low three bits which causes + // upper and lower case alphabetics to both yield their + // "relative to 10" value for computing the hex value. + rv = rv * 16 + (ch & 0x7) + 10; + } + } else { + Unread(); + break; + } + } + return rv; + } else { + // "Any character except a hexidecimal digit can be escaped to + // remove its special meaning by putting a backslash in front" + // -- CSS1 spec section 7.1 + (void) Read(aErrorCode); + return ch; + } +} + +/** + * Gather up the characters in an identifier. The identfier was + * started by "aChar" which will be appended to aIdent. The result + * will be aIdent with all of the identifier characters appended + * until the first non-identifier character is seen. The termination + * character is unread for the future re-reading. + */ +PRBool nsCSSScanner::GatherIdent(PRInt32* aErrorCode, PRInt32 aChar, + nsString& aIdent) +{ + if (aChar == CSS_ESCAPE) { + aChar = ParseEscape(aErrorCode); + } + for (;;) { + aChar = Read(aErrorCode); + if (aChar < 0) break; + if (aChar == CSS_ESCAPE) { + aChar = ParseEscape(aErrorCode); + aIdent.Append(PRUnichar(aChar)); + } else if ((aChar <= 255) && ((gLexTable[aChar] & IS_IDENT) != 0)) { + aIdent.Append(PRUnichar(aChar)); + } else { + Unread(); + break; + } + } + return PR_TRUE; +} + +PRBool nsCSSScanner::ParseID(PRInt32* aErrorCode, + PRInt32 aChar, + nsCSSToken* aToken) +{ + aToken->mIdent.SetLength(0); + aToken->mType = eCSSToken_ID; + return GatherIdent(aErrorCode, aChar, aToken->mIdent); +} + +PRBool nsCSSScanner::ParseIdent(PRInt32* aErrorCode, + PRInt32 aChar, + nsCSSToken* aToken) +{ + nsString& ident = aToken->mIdent; + ident.SetLength(0); + ident.Append(PRUnichar(aChar)); + if (!GatherIdent(aErrorCode, aChar, ident)) { + return PR_FALSE; + } + + // Process a url lexical token. A CSS1 url token can contain + // characters beyond identifier characters (e.g. '/', ':', etc.) + // Because of this the normal rules for tokenizing the input don't + // apply very well. To simplify the parser and relax some of the + // requirements on the scanner we parse url's here. If we find a + // malformed URL then we emit a token of type "InvalidURL" so that + // the CSS1 parser can ignore the invalid input. We attempt to eat + // the right amount of input data when an invalid URL is presented. + nsCSSTokenType tokenType = eCSSToken_Ident; + if (ident.EqualsIgnoreCase("url")) { + tokenType = eCSSToken_InvalidURL; + if (LookAhead(aErrorCode, '(')) { + // Skip leading whitespace + (void) EatWhiteSpace(aErrorCode); + ident.SetLength(0); + + PRInt32 c = Read(aErrorCode); + if (c == ')') { + // empty url spec: this is invalid + } else if ((c == '"') || (c == '\'')) { + // start of a quoted url + if (!GatherString(aErrorCode, c, ident)) { + return PR_FALSE; + } + if (!EatWhiteSpace(aErrorCode)) { + return PR_FALSE; + } + if (LookAhead(aErrorCode, ')')) { + tokenType = eCSSToken_URL; + } + } else { + // start of a non-quoted url + Unread(); + PRBool ok = PR_TRUE; + for (;;) { + c = Read(aErrorCode); + if (c < 0) break; + if (c == CSS_ESCAPE) { + c = ParseEscape(aErrorCode); + ident.Append(PRUnichar(c)); + } else if ((c == '"') || (c == '\'') || (c == '(')) { + // This is an invalid URL spec + ok = PR_FALSE; + } else if ((256 >= c) && ((gLexTable[c] & IS_WHITESPACE) != 0)) { + // Whitespace is allowed at the end of the URL + (void) EatWhiteSpace(aErrorCode); + if (LookAhead(aErrorCode, ')')) { + // done! + break; + } + // Whitespace is followed by something other than a + // ")". This is an invalid url spec. + ok = PR_FALSE; + } else if (c == ')') { + // All done + break; + } else { + // A regular url character. + ident.Append(PRUnichar(c)); + } + } + + // If the result of the above scanning is ok then change the token + // type to a useful one. + if (ok) { + tokenType = eCSSToken_URL; + } + } + } + } + aToken->mType = tokenType; + return PR_TRUE; +} + +PRBool nsCSSScanner::ParseAtKeyword(PRInt32* aErrorCode, PRInt32 aChar, + nsCSSToken* aToken) +{ + aToken->mIdent.SetLength(0); + aToken->mType = eCSSToken_AtKeyword; + return GatherIdent(aErrorCode, aChar, aToken->mIdent); +} + +PRBool nsCSSScanner::ParseNumber(PRInt32* aErrorCode, PRInt32 c, + nsCSSToken* aToken) +{ + nsString& ident = aToken->mIdent; + ident.SetLength(0); + PRBool gotDot = (c == '.') ? PR_TRUE : PR_FALSE; + if (c != '+') { + ident.Append(PRUnichar(c)); + } + + // Gather up characters that make up the number + PRUint8* lexTable = gLexTable; + for (;;) { + c = Read(aErrorCode); + if (c < 0) break; + if (!gotDot && (c == '.')) { + gotDot = PR_TRUE; + } else if ((c > 255) || ((lexTable[c] & IS_DIGIT) == 0)) { + break; + } + ident.Append(PRUnichar(c)); + } + + // Convert number to floating point + nsCSSTokenType type = eCSSToken_Number; + PRInt32 ec; + float value = ident.ToFloat(&ec); + + // Look at character that terminated the number + aToken->mIntegerValid = PR_FALSE; + if (c >= 0) { + if ((c <= 255) && ((lexTable[c] & START_IDENT) != 0)) { + ident.SetLength(0); + ident.Append(PRUnichar(c)); + if (!GatherIdent(aErrorCode, c, ident)) { + return PR_FALSE; + } + type = eCSSToken_Dimension; + } else if ('%' == c) { + type = eCSSToken_Percentage; + value = value / 100.0f; + } else { + // Put back character that stopped numeric scan + Unread(); + if (!gotDot) { + aToken->mInteger = ident.ToInteger(&ec); + aToken->mIntegerValid = PR_TRUE; + } + ident.SetLength(0); + } + } + aToken->mNumber = value; + aToken->mType = type; + return PR_TRUE; +} + +PRBool nsCSSScanner::ParseCComment(PRInt32* aErrorCode, nsCSSToken* aToken) +{ + nsString& ident = aToken->mIdent; + for (;;) { + PRInt32 ch = Read(aErrorCode); + if (ch < 0) break; + if (ch == '*') { + if (LookAhead(aErrorCode, '/')) { + ident.Append(PRUnichar(ch)); + ident.Append('/'); + break; + } + } +#ifdef COLLECT_WHITESPACE + ident.Append(PRUnichar(ch)); +#endif + } + aToken->mType = eCSSToken_WhiteSpace; + return PR_TRUE; +} + +PRBool nsCSSScanner::ParseEOLComment(PRInt32* aErrorCode, nsCSSToken* aToken) +{ + nsString& ident = aToken->mIdent; + ident.SetLength(0); + for (;;) { + if (EatNewline(aErrorCode)) { + break; + } + PRInt32 ch = Read(aErrorCode); + if (ch < 0) { + break; + } +#ifdef COLLECT_WHITESPACE + ident.Append(PRUnichar(ch)); +#endif + } + aToken->mType = eCSSToken_WhiteSpace; + return PR_TRUE; +} + +PRBool nsCSSScanner::GatherString(PRInt32* aErrorCode, PRInt32 aStop, + nsString& aBuffer) +{ + for (;;) { + PRInt32 ch = Read(aErrorCode); + if (ch < 0) { + return PR_FALSE; + } + if (ch == aStop) { + break; + } + if (ch == CSS_ESCAPE) { + ch = ParseEscape(aErrorCode); + if (ch < 0) { + return PR_FALSE; + } + } + aBuffer.Append(PRUnichar(ch)); + } + return PR_TRUE; +} + +PRBool nsCSSScanner::ParseString(PRInt32* aErrorCode, PRInt32 aStop, + nsCSSToken* aToken) +{ + aToken->mIdent.SetLength(0); + aToken->mType = eCSSToken_String; + return GatherString(aErrorCode, aStop, aToken->mIdent); +} diff --git a/mozilla/layout/html/style/src/nsCSSScanner.h b/mozilla/layout/html/style/src/nsCSSScanner.h new file mode 100644 index 00000000000..afbe1da67fd --- /dev/null +++ b/mozilla/layout/html/style/src/nsCSSScanner.h @@ -0,0 +1,118 @@ +/* -*- 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. + */ +#ifndef nsCSSScanner_h___ +#define nsCSSScanner_h___ + +#include "nsString.h" +class nsIUnicharInputStream; + +// Token types +enum nsCSSTokenType { + // A css identifier (e.g. foo) + eCSSToken_Ident = 0, + + // A css at keyword (e.g. @foo) + eCSSToken_AtKeyword = 1, + + // A css number without a percentage or dimension; with percentage; + // without percentage but with a dimension + eCSSToken_Number = 2, + eCSSToken_Percentage = 3, + eCSSToken_Dimension = 4, + + // A css string (e.g. "foo" or 'foo') + eCSSToken_String = 5, + + // Whitespace (e.g. " " or "/* abc */" or "// foo ") + eCSSToken_WhiteSpace = 6, + + // A css symbol (e.g. ':', ';', '+', etc.) + eCSSToken_Symbol = 7, + + eCSSToken_URL = 8, // use getString + eCSSToken_InvalidURL = 9, // doesn't matter + + // A css1 id (e.g. #foo3) + eCSSToken_ID = 10, // use getString() +}; + +struct nsCSSToken { + nsCSSTokenType mType; + nsAutoString mIdent; + float mNumber; + PRInt32 mInteger; + PRUnichar mSymbol; + PRBool mIntegerValid; + + nsCSSToken(); + + PRBool isDimension() { + return (PRBool) + ((eCSSToken_Dimension == mType) || + ((eCSSToken_Number == mType) && (mNumber == 0.0f))); + } +}; + +// CSS Scanner API. Used to tokenize an input stream using the CSS +// forward compatible tokenization rules. This implementation is +// private to this package and is only used internally by the css +// parser. +class nsCSSScanner { + public: + nsCSSScanner(); + ~nsCSSScanner(); + + // Init the scanner. + void Init(nsIUnicharInputStream* aInput); + + // Get the next token. Return nsfalse on EOF or ERROR. aTokenResult + // is filled in with the data for the token. + PRBool Next(PRInt32* aErrorCode, nsCSSToken* aTokenResult); + +protected: + void Close(); + PRInt32 Read(PRInt32* aErrorCode); + PRInt32 Peek(PRInt32* aErrorCode); + void Unread(); + PRBool LookAhead(PRInt32* aErrorCode, PRUnichar aChar); + PRBool EatWhiteSpace(PRInt32* aErrorCode); + PRBool EatNewline(PRInt32* aErrorCode); + + PRInt32 ParseEscape(PRInt32* aErrorCode); + PRBool ParseIdent(PRInt32* aErrorCode, PRInt32 aChar, nsCSSToken* aResult); + PRBool ParseAtKeyword(PRInt32* aErrorCode, PRInt32 aChar, + nsCSSToken* aResult); + PRBool ParseNumber(PRInt32* aErrorCode, PRInt32 aChar, nsCSSToken* aResult); + PRBool ParseID(PRInt32* aErrorCode, PRInt32 aChar, nsCSSToken* aResult); + PRBool ParseString(PRInt32* aErrorCode, PRInt32 aChar, nsCSSToken* aResult); + PRBool ParseEOLComment(PRInt32* aErrorCode, nsCSSToken* aResult); + PRBool ParseCComment(PRInt32* aErrorCode, nsCSSToken* aResult); + + PRBool GatherString(PRInt32* aErrorCode, PRInt32 aStop, + nsString& aString); + PRBool GatherIdent(PRInt32* aErrorCode, PRInt32 aChar, nsString& aIdent); + + nsIUnicharInputStream* mInput; + PRUnichar* mBuffer; + PRInt32 mOffset; + PRInt32 mCount; + PRInt32 mLookAhead; + PRInt32 mLastRead; +}; + +#endif /* nsCSSScanner_h___ */ diff --git a/mozilla/layout/html/style/src/nsCSSStyleRule.cpp b/mozilla/layout/html/style/src/nsCSSStyleRule.cpp new file mode 100644 index 00000000000..c19372058b9 --- /dev/null +++ b/mozilla/layout/html/style/src/nsCSSStyleRule.cpp @@ -0,0 +1,683 @@ +/* -*- 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 "nsICSSStyleRule.h" +#include "nsICSSDeclaration.h" +#include "nsIStyleContext.h" +#include "nsIPresContext.h" +#include "nsIArena.h" +#include "nsIAtom.h" +#include "nsCRT.h" +#include "nsString.h" +#include "nsStyleConsts.h" +#include "nsUnitConversion.h" + +static NS_DEFINE_IID(kIStyleRuleIID, NS_ISTYLE_RULE_IID); +static NS_DEFINE_IID(kICSSDeclarationIID, NS_ICSS_DECLARATION_IID); +static NS_DEFINE_IID(kICSSStyleRuleIID, NS_ICSS_STYLE_RULE_IID); + +static NS_DEFINE_IID(kStyleFontSID, NS_STYLEFONT_SID); +static NS_DEFINE_IID(kStyleColorSID, NS_STYLECOLOR_SID); +static NS_DEFINE_IID(kStyleListSID, NS_STYLELIST_SID); + +static NS_DEFINE_IID(kCSSFontSID, NS_CSS_FONT_SID); +static NS_DEFINE_IID(kCSSColorSID, NS_CSS_COLOR_SID); +static NS_DEFINE_IID(kCSSTextSID, NS_CSS_TEXT_SID); +static NS_DEFINE_IID(kCSSMarginSID, NS_CSS_MARGIN_SID); +static NS_DEFINE_IID(kCSSPositionSID, NS_CSS_POSITION_SID); +static NS_DEFINE_IID(kCSSListSID, NS_CSS_LIST_SID); + + +// -- nsCSSSelector ------------------------------- + +nsCSSSelector::nsCSSSelector() + : mTag(nsnull), mID(nsnull), mClass(nsnull), mPseudoClass(nsnull), + mNext(nsnull) +{ +} + +nsCSSSelector::nsCSSSelector(nsIAtom* aTag, nsIAtom* aID, nsIAtom* aClass, nsIAtom* aPseudoClass) + : mTag(aTag), mID(aID), mClass(aClass), mPseudoClass(aPseudoClass), + mNext(nsnull) +{ + NS_IF_ADDREF(mTag); + NS_IF_ADDREF(mID); + NS_IF_ADDREF(mClass); + NS_IF_ADDREF(mPseudoClass); +} + +nsCSSSelector::nsCSSSelector(const nsCSSSelector& aCopy) + : mTag(aCopy.mTag), mID(aCopy.mID), mClass(aCopy.mClass), mPseudoClass(aCopy.mPseudoClass), + mNext(nsnull) +{ // implmented to support extension to CSS2 (when we have to copy the array) + NS_IF_ADDREF(mTag); + NS_IF_ADDREF(mID); + NS_IF_ADDREF(mClass); + NS_IF_ADDREF(mPseudoClass); +} + +nsCSSSelector::~nsCSSSelector() +{ + NS_IF_RELEASE(mTag); + NS_IF_RELEASE(mID); + NS_IF_RELEASE(mClass); + NS_IF_RELEASE(mPseudoClass); +} + +nsCSSSelector& nsCSSSelector::operator=(const nsCSSSelector& aCopy) +{ + NS_IF_RELEASE(mTag); + NS_IF_RELEASE(mID); + NS_IF_RELEASE(mClass); + NS_IF_RELEASE(mPseudoClass); + mTag = aCopy.mTag; + mID = aCopy.mID; + mClass = aCopy.mClass; + mPseudoClass = aCopy.mPseudoClass; + NS_IF_ADDREF(mTag); + NS_IF_ADDREF(mID); + NS_IF_ADDREF(mClass); + NS_IF_ADDREF(mPseudoClass); + return *this; +} + +PRBool nsCSSSelector::Equals(const nsCSSSelector* aOther) const +{ + if (nsnull != aOther) { + return (PRBool)((aOther->mTag == mTag) && (aOther->mID == mID) && + (aOther->mClass == mClass) && (aOther->mPseudoClass == mPseudoClass)); + } + return PR_FALSE; +} + + +void nsCSSSelector::Set(const nsString& aTag, const nsString& aID, + const nsString& aClass, const nsString& aPseudoClass) +{ + NS_IF_RELEASE(mTag); + NS_IF_RELEASE(mID); + NS_IF_RELEASE(mClass); + NS_IF_RELEASE(mPseudoClass); + if (0 < aTag.Length()) { + mTag = NS_NewAtom(aTag); + } + if (0 < aID.Length()) { + mID = NS_NewAtom(aID); + } + if (0 < aClass.Length()) { + mClass = NS_NewAtom(aClass); + } + if (0 < aPseudoClass.Length()) { + mPseudoClass = NS_NewAtom(aPseudoClass); + } +} + +// -- nsCSSStyleRule ------------------------------- + +class CSSStyleRuleImpl : public nsICSSStyleRule { +public: + void* operator new(size_t size); + void* operator new(size_t size, nsIArena* aArena); + void operator delete(void* ptr); + + CSSStyleRuleImpl(const nsCSSSelector& aSelector); + + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + + virtual PRBool Equals(const nsIStyleRule* aRule) const; + virtual PRUint32 HashValue(void) const; + + virtual nsCSSSelector* FirstSelector(void); + virtual void AddSelector(const nsCSSSelector& aSelector); + virtual void DeleteSelector(nsCSSSelector* aSelector); + + virtual nsICSSDeclaration* GetDeclaration(void) const; + virtual void SetDeclaration(nsICSSDeclaration* aDeclaration); + + virtual PRInt32 GetWeight(void) const; + virtual void SetWeight(PRInt32 aWeight); + + virtual nscoord CalcLength(const nsCSSValue& aValue, nsStyleFont* aFont, + nsIPresContext* aPresContext); + virtual void MapStyleInto(nsIStyleContext* aContext, nsIPresContext* aPresContext); + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + +private: + // These are not supported and are not implemented! + CSSStyleRuleImpl(const CSSStyleRuleImpl& aCopy); + CSSStyleRuleImpl& operator=(const CSSStyleRuleImpl& aCopy); + +protected: + virtual ~CSSStyleRuleImpl(); + +protected: + PRUint32 mInHeap : 1; + PRUint32 mRefCnt : 31; + + nsCSSSelector mSelector; + nsICSSDeclaration* mDeclaration; + PRInt32 mWeight; +}; + + +void* CSSStyleRuleImpl::operator new(size_t size) +{ + CSSStyleRuleImpl* rv = (CSSStyleRuleImpl*) ::operator new(size); +#ifdef NS_DEBUG + if (nsnull != rv) { + nsCRT::memset(rv, 0xEE, size); + } +#endif + rv->mInHeap = 1; + return (void*) rv; +} + +void* CSSStyleRuleImpl::operator new(size_t size, nsIArena* aArena) +{ + CSSStyleRuleImpl* rv = (CSSStyleRuleImpl*) aArena->Alloc(PRInt32(size)); +#ifdef NS_DEBUG + if (nsnull != rv) { + nsCRT::memset(rv, 0xEE, size); + } +#endif + rv->mInHeap = 0; + return (void*) rv; +} + +void CSSStyleRuleImpl::operator delete(void* ptr) +{ + CSSStyleRuleImpl* rule = (CSSStyleRuleImpl*) ptr; + if (nsnull != rule) { + if (rule->mInHeap) { + ::delete ptr; + } + } +} + + + +CSSStyleRuleImpl::CSSStyleRuleImpl(const nsCSSSelector& aSelector) + : mSelector(aSelector), mDeclaration(nsnull), mWeight(0) +{ + NS_INIT_REFCNT(); +} + +CSSStyleRuleImpl::~CSSStyleRuleImpl() +{ + nsCSSSelector* next = mSelector.mNext; + + while (nsnull != next) { + nsCSSSelector* selector = next; + next = selector->mNext; + delete selector; + } + NS_IF_RELEASE(mDeclaration); +} + +NS_IMPL_ADDREF(CSSStyleRuleImpl) +NS_IMPL_RELEASE(CSSStyleRuleImpl) + +nsresult CSSStyleRuleImpl::QueryInterface(const nsIID& aIID, + void** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + if (aIID.Equals(kICSSStyleRuleIID)) { + *aInstancePtrResult = (void*) ((nsICSSStyleRule*)this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIStyleRuleIID)) { + *aInstancePtrResult = (void*) ((nsIStyleRule*)this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kISupportsIID)) { + *aInstancePtrResult = (void*) ((nsISupports*)this); + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + + +PRBool CSSStyleRuleImpl::Equals(const nsIStyleRule* aRule) const +{ + nsICSSStyleRule* iCSSRule; + + if (this == aRule) { + return PR_TRUE; + } + + if ((nsnull != aRule) && + (NS_OK == ((nsIStyleRule*)aRule)->QueryInterface(kICSSStyleRuleIID, (void**) &iCSSRule))) { + + CSSStyleRuleImpl* rule = (CSSStyleRuleImpl*)iCSSRule; + const nsCSSSelector* local = &mSelector; + const nsCSSSelector* other = &(rule->mSelector); + PRBool result = PR_TRUE; + + while ((PR_TRUE == result) && (nsnull != local) && (nsnull != other)) { + if (! local->Equals(other)) { + result = PR_FALSE; + } + local = local->mNext; + other = other->mNext; + } + if ((nsnull != local) || (nsnull != other)) { // more were left + result = PR_FALSE; + } + if ((rule->mDeclaration != mDeclaration) || + (rule->mWeight != mWeight)) { + result = PR_FALSE; + } + NS_RELEASE(iCSSRule); + return result; + } + return PR_FALSE; +} + +PRUint32 CSSStyleRuleImpl::HashValue(void) const +{ + return (PRUint32)this; +} + +nsCSSSelector* CSSStyleRuleImpl::FirstSelector(void) +{ + return &mSelector; +} + +void CSSStyleRuleImpl::AddSelector(const nsCSSSelector& aSelector) +{ + nsCSSSelector* selector = new nsCSSSelector(aSelector); + nsCSSSelector* last = &mSelector; + + while (nsnull != last->mNext) { + last = last->mNext; + } + last->mNext = selector; +} + + +void CSSStyleRuleImpl::DeleteSelector(nsCSSSelector* aSelector) +{ + if (nsnull != aSelector) { + if (&mSelector == aSelector) { // handle first selector + mSelector = *aSelector; // assign value + mSelector.mNext = aSelector->mNext; + delete aSelector; + } + else { + nsCSSSelector* selector = &mSelector; + + while (nsnull != selector->mNext) { + if (aSelector == selector->mNext) { + selector->mNext = aSelector->mNext; + delete aSelector; + return; + } + selector = selector->mNext; + } + } + } +} + +nsICSSDeclaration* CSSStyleRuleImpl::GetDeclaration(void) const +{ + NS_IF_ADDREF(mDeclaration); + return mDeclaration; +} + +void CSSStyleRuleImpl::SetDeclaration(nsICSSDeclaration* aDeclaration) +{ + NS_IF_RELEASE(mDeclaration); + mDeclaration = aDeclaration; + NS_IF_ADDREF(mDeclaration); +} + +PRInt32 CSSStyleRuleImpl::GetWeight(void) const +{ + return mWeight; +} + +void CSSStyleRuleImpl::SetWeight(PRInt32 aWeight) +{ + mWeight = aWeight; +} + +nscoord CSSStyleRuleImpl::CalcLength(const nsCSSValue& aValue, nsStyleFont* aFont, + nsIPresContext* aPresContext) +{ + NS_ASSERTION(aValue.IsLengthUnit(), "not a length unit"); + if (aValue.IsFixedLengthUnit()) { + return aValue.GetLengthTwips(); + } + nsCSSUnit unit = aValue.GetUnit(); + switch (unit) { + case eCSSUnit_EM: + return aFont->mFont.size; + case eCSSUnit_EN: + return (aFont->mFont.size / 2); + case eCSSUnit_XHeight: + NS_NOTYETIMPLEMENTED("x height unit"); + return ((aFont->mFont.size / 3) * 2); // XXX HACK! + case eCSSUnit_CapHeight: + NS_NOTYETIMPLEMENTED("cap height unit"); + return ((aFont->mFont.size / 3) * 2); // XXX HACK! + + case eCSSUnit_Pixel: + return (nscoord)(aPresContext->GetPixelsToTwips() * aValue.GetFloatValue()); + } + return 0; +} + +void CSSStyleRuleImpl::MapStyleInto(nsIStyleContext* aContext, nsIPresContext* aPresContext) +{ + if (nsnull != mDeclaration) { + nsStyleFont* font = (nsStyleFont*)aContext->GetData(kStyleFontSID); + + nsCSSFont* ourFont; + if (NS_OK == mDeclaration->GetData(kCSSFontSID, (nsCSSStruct**)&ourFont)) { + if (nsnull != ourFont) { + nsStyleFont* parentFont = font; + nsIStyleContext* parentContext = aContext->GetParent(); + if (nsnull != parentContext) { + parentFont = (nsStyleFont*)parentContext->GetData(kStyleFontSID); + } + + // font-family: string list + if (ourFont->mFamily.GetUnit() == eCSSUnit_String) { + nsAutoString familyList; + ourFont->mFamily.GetStringValue(familyList); + // XXX meeds font support to determine usable fonts + // parse up the CSS string & remove the quotes + // XXX only does first until we can tell what are installed fonts + nsAutoString family; + PRInt32 index = familyList.Find(PRUnichar(',')); + if (-1 < index) { + familyList.Left(family, index); + } + else { + family.Append(familyList); + } + family.StripChars("\""); + family.StripWhitespace(); + + font->mFont.name = family; + } + + // font-style: enum + if (ourFont->mStyle.GetUnit() == eCSSUnit_Enumerated) { + font->mFont.style = ourFont->mStyle.GetIntValue(); + } + + // font-variant: enum + if (ourFont->mVariant.GetUnit() == eCSSUnit_Enumerated) { + font->mFont.variant = ourFont->mVariant.GetIntValue(); + } + + // font-weight: abs, enum + if (ourFont->mWeight.GetUnit() == eCSSUnit_Absolute) { + font->mFont.style = ourFont->mWeight.GetIntValue(); + } + else if (ourFont->mWeight.GetUnit() == eCSSUnit_Enumerated) { + PRInt32 value = ourFont->mWeight.GetIntValue(); + switch (value) { + case NS_STYLE_FONT_WEIGHT_NORMAL: + case NS_STYLE_FONT_WEIGHT_BOLD: + font->mFont.weight = value; + break; + case NS_STYLE_FONT_WEIGHT_BOLDER: + case NS_STYLE_FONT_WEIGHT_LIGHTER: + font->mFont.weight = (parentFont->mFont.weight + value); + break; + } + } + + // font-size: enum, length, percent + if (ourFont->mSize.GetUnit() == eCSSUnit_Enumerated) { + static float kFontScale[7] = { + 0.5f, // xx-small + 0.666667f, // x-small + 0.833333f, // small + 1.0f, // medium + 1.5f, // large + 1.5f * 1.5f, // x-large + 1.5f * 1.5f * 1.5f, // xx-large + }; + PRInt32 value = ourFont->mSize.GetIntValue(); + + const nsFont& normal = aPresContext->GetDefaultFont(); // use normal font or body font?? + if ((NS_STYLE_FONT_SIZE_XXSMALL <= value) && + (value <= NS_STYLE_FONT_SIZE_XXLARGE)) { + font->mFont.size = (nscoord)((float)normal.size * kFontScale[value]); + } + else if (NS_STYLE_FONT_SIZE_LARGER == value) { + PRInt32 index; + for (index = NS_STYLE_FONT_SIZE_XXSMALL; + index < NS_STYLE_FONT_SIZE_XXLARGE; index++) + if (parentFont->mFont.size < (nscoord)((float)normal.size * kFontScale[index])) + break; + font->mFont.size = (nscoord)((float)normal.size * kFontScale[index]); + } + else if (NS_STYLE_FONT_SIZE_SMALLER == value) { + PRInt32 index; + for (index = NS_STYLE_FONT_SIZE_XXLARGE; + index > NS_STYLE_FONT_SIZE_XXSMALL; index--) + if (parentFont->mFont.size > (nscoord)((float)normal.size * kFontScale[index])) + break; + font->mFont.size = (nscoord)((float)normal.size * kFontScale[index]); + } + } + else if (ourFont->mSize.IsLengthUnit()) { + font->mFont.size = CalcLength(ourFont->mSize, parentFont, aPresContext); + } + else if (ourFont->mSize.GetUnit() == eCSSUnit_Percent) { + font->mFont.size = (nscoord)((float)(parentFont->mFont.size) * ourFont->mSize.GetFloatValue()); + } + + NS_IF_RELEASE(parentContext); + } + } + + nsCSSText* ourText; + if (NS_OK == mDeclaration->GetData(kCSSTextSID, (nsCSSStruct**)&ourText)) { + if (nsnull != ourText) { + + // text-decoration: enum, absolute (bit field) + if (ourText->mDecoration.GetUnit() == eCSSUnit_Enumerated) { + font->mFont.decorations = ourText->mDecoration.GetIntValue(); + } + else if (ourText->mDecoration.GetUnit() == eCSSUnit_Absolute) { + font->mFont.decorations = ourText->mDecoration.GetIntValue(); + } + } + } + + + nsCSSColor* ourColor; + if (NS_OK == mDeclaration->GetData(kCSSColorSID, (nsCSSStruct**)&ourColor)) { + if (nsnull != ourColor) { + nsStyleColor* color = (nsStyleColor*)aContext->GetData(kStyleColorSID); + + // color: color + if (ourColor->mColor.GetUnit() == eCSSUnit_Color) { + color->mColor = ourColor->mColor.GetColorValue(); + } + + // background-color: color, enum (flags) + if (ourColor->mBackColor.GetUnit() == eCSSUnit_Color) { + color->mBackgroundColor = ourColor->mBackColor.GetColorValue(); + color->mBackgroundFlags &= ~NS_STYLE_BG_COLOR_TRANSPARENT; + } + else if (ourColor->mBackColor.GetUnit() == eCSSUnit_Enumerated) { + color->mBackgroundFlags |= NS_STYLE_BG_COLOR_TRANSPARENT; + } + + // background-image: string, enum (flags) + if (ourColor->mBackImage.GetUnit() == eCSSUnit_String) { + ourColor->mBackImage.GetStringValue(color->mBackgroundImage); + color->mBackgroundFlags &= ~NS_STYLE_BG_IMAGE_NONE; + } + else if (ourColor->mBackImage.GetUnit() == eCSSUnit_Enumerated) { + color->mBackgroundFlags |= NS_STYLE_BG_IMAGE_NONE; + } + + // background-repeat: enum + if (ourColor->mBackRepeat.GetUnit() == eCSSUnit_Enumerated) { + color->mBackgroundRepeat = ourColor->mBackRepeat.GetIntValue(); + } + + // background-attachment: enum + if (ourColor->mBackAttachment.GetUnit() == eCSSUnit_Enumerated) { + color->mBackgroundAttachment = ourColor->mBackAttachment.GetIntValue(); + } + + // background-position: length, percent (flags) + if (ourColor->mBackPositionX.GetUnit() == eCSSUnit_Percent) { + color->mBackgroundXPosition = (nscoord)(TWIPS_CONST_FLOAT * ourColor->mBackPositionX.GetFloatValue()); + color->mBackgroundFlags |= NS_STYLE_BG_X_POSITION_PCT; + color->mBackgroundFlags &= ~NS_STYLE_BG_X_POSITION_LENGTH; + } + else if (ourColor->mBackPositionX.IsLengthUnit()) { + color->mBackgroundXPosition = CalcLength(ourColor->mBackPositionX, + font, aPresContext); + color->mBackgroundFlags |= NS_STYLE_BG_X_POSITION_LENGTH; + color->mBackgroundFlags &= ~NS_STYLE_BG_X_POSITION_PCT; + } + if (ourColor->mBackPositionY.GetUnit() == eCSSUnit_Percent) { + color->mBackgroundYPosition = (nscoord)(TWIPS_CONST_FLOAT * ourColor->mBackPositionY.GetFloatValue()); + color->mBackgroundFlags |= NS_STYLE_BG_Y_POSITION_PCT; + color->mBackgroundFlags &= ~NS_STYLE_BG_Y_POSITION_LENGTH; + } + else if (ourColor->mBackPositionY.IsLengthUnit()) { + color->mBackgroundYPosition = CalcLength(ourColor->mBackPositionY, + font, aPresContext); + color->mBackgroundFlags |= NS_STYLE_BG_Y_POSITION_LENGTH; + color->mBackgroundFlags &= ~NS_STYLE_BG_Y_POSITION_PCT; + } + + // XXX: NYI nsCSSValue mBackFilter; + } + } + + + nsCSSList* ourList; + if (NS_OK == mDeclaration->GetData(kCSSListSID, (nsCSSStruct**)&ourList)) { + if (nsnull != ourList) { + nsStyleList* list = (nsStyleList*)aContext->GetData(kStyleListSID); + + // list-style-type: enum + if (ourList->mType.GetUnit() == eCSSUnit_Enumerated) { + list->mListStyleType = ourList->mType.GetIntValue(); + } + + // list-style-image: string + if (ourList->mImage.GetUnit() == eCSSUnit_String) { + ourList->mImage.GetStringValue(list->mListStyleImage); + } + else if (ourList->mImage.GetUnit() == eCSSUnit_Enumerated) { // handle "none" + list->mListStyleImage = ""; + } + + // list-style-position: enum + if (ourList->mPosition.GetUnit() == eCSSUnit_Enumerated) { + list->mListStyleType = ourList->mPosition.GetIntValue(); + } + } + } + + } + +} + + + +static void ListSelector(FILE* out, const nsCSSSelector* aSelector) +{ + nsAutoString buffer; + + if (nsnull != aSelector->mTag) { + aSelector->mTag->ToString(buffer); + fputs(buffer, out); + } + if (nsnull != aSelector->mID) { + aSelector->mID->ToString(buffer); + fputs("#", out); + fputs(buffer, out); + } + if (nsnull != aSelector->mClass) { + aSelector->mClass->ToString(buffer); + fputs(".", out); + fputs(buffer, out); + } + if (nsnull != aSelector->mPseudoClass) { + aSelector->mPseudoClass->ToString(buffer); + fputs(":", out); + fputs(buffer, out); + } +} + +void CSSStyleRuleImpl::List(FILE* out, PRInt32 aIndent) const +{ + // Indent + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + const nsCSSSelector* selector = &mSelector; + + while (nsnull != selector) { + ListSelector(out, selector); + fputs(" ", out); + selector = selector->mNext; + } + + nsAutoString buffer; + + buffer.Append("weight: "); + buffer.Append(mWeight, 10); + buffer.Append(" "); + fputs(buffer, out); + if (nsnull != mDeclaration) { + mDeclaration->List(out); + } + else { + fputs("{ null declaration }", out); + } + fputs("\n", out); +} + +NS_HTML nsresult + NS_NewCSSStyleRule(nsICSSStyleRule** aInstancePtrResult, const nsCSSSelector& aSelector) +{ + if (aInstancePtrResult == nsnull) { + return NS_ERROR_NULL_POINTER; + } + + CSSStyleRuleImpl *it = new CSSStyleRuleImpl(aSelector); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(kICSSStyleRuleIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/layout/html/style/src/nsCSSStyleSheet.cpp b/mozilla/layout/html/style/src/nsCSSStyleSheet.cpp new file mode 100644 index 00000000000..14d80e149fe --- /dev/null +++ b/mozilla/layout/html/style/src/nsCSSStyleSheet.cpp @@ -0,0 +1,364 @@ +/* -*- 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 "nsICSSStyleSheet.h" +#include "nsIArena.h" +#include "nsCRT.h" +#include "nsIAtom.h" +#include "nsIURL.h" +#include "nsISupportsArray.h" +#include "nsICSSStyleRule.h" +#include "nsIHTMLContent.h" +#include "nsIFrame.h" +#include "nsString.h" + +static NS_DEFINE_IID(kICSSStyleSheetIID, NS_ICSS_STYLE_SHEET_IID); +static NS_DEFINE_IID(kIStyleSheetIID, NS_ISTYLE_SHEET_IID); +static NS_DEFINE_IID(kIStyleRuleIID, NS_ISTYLE_RULE_IID); +static NS_DEFINE_IID(kIHTMLContentIID, NS_IHTMLCONTENT_IID); + + +class CSSStyleSheetImpl : public nsICSSStyleSheet { +public: + void* operator new(size_t size); + void* operator new(size_t size, nsIArena* aArena); + void operator delete(void* ptr); + + CSSStyleSheetImpl(nsIURL* aURL); + + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + + virtual PRBool SelectorMatches(nsCSSSelector* aSelector, + nsIContent* aContent); + virtual PRInt32 RulesMatching(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsISupportsArray* aResults); + + virtual nsIURL* GetURL(void); + + virtual PRBool ContainsStyleSheet(nsIURL* aURL); + + virtual void AppendStyleSheet(nsICSSStyleSheet* aSheet); + + // XXX do these belong here or are they generic? + virtual void PrependStyleRule(nsICSSStyleRule* aRule); + virtual void AppendStyleRule(nsICSSStyleRule* aRule); + + // XXX style rule enumerations + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + +private: + // These are not supported and are not implemented! + CSSStyleSheetImpl(const CSSStyleSheetImpl& aCopy); + CSSStyleSheetImpl& operator=(const CSSStyleSheetImpl& aCopy); + +protected: + virtual ~CSSStyleSheetImpl(); + +protected: + PRUint32 mInHeap : 1; + PRUint32 mRefCnt : 31; + + nsIURL* mURL; + CSSStyleSheetImpl* mFirstChild; + nsISupportsArray* mRules; + CSSStyleSheetImpl* mNext; +}; + + +void* CSSStyleSheetImpl::operator new(size_t size) +{ + CSSStyleSheetImpl* rv = (CSSStyleSheetImpl*) ::operator new(size); +#ifdef NS_DEBUG + if (nsnull != rv) { + nsCRT::memset(rv, 0xEE, size); + } +#endif + rv->mInHeap = 1; + return (void*) rv; +} + +void* CSSStyleSheetImpl::operator new(size_t size, nsIArena* aArena) +{ + CSSStyleSheetImpl* rv = (CSSStyleSheetImpl*) aArena->Alloc(PRInt32(size)); +#ifdef NS_DEBUG + if (nsnull != rv) { + nsCRT::memset(rv, 0xEE, size); + } +#endif + rv->mInHeap = 0; + return (void*) rv; +} + +void CSSStyleSheetImpl::operator delete(void* ptr) +{ + CSSStyleSheetImpl* sheet = (CSSStyleSheetImpl*) ptr; + if (nsnull != sheet) { + if (sheet->mInHeap) { + ::delete ptr; + } + } +} + + + +CSSStyleSheetImpl::CSSStyleSheetImpl(nsIURL* aURL) + : nsICSSStyleSheet(), + mURL(aURL), mFirstChild(nsnull), mRules(nsnull), mNext(nsnull) +{ + NS_INIT_REFCNT(); + NS_ADDREF(mURL); +} + +CSSStyleSheetImpl::~CSSStyleSheetImpl() +{ + NS_RELEASE(mURL); + NS_IF_RELEASE(mFirstChild); + NS_IF_RELEASE(mRules); + NS_IF_RELEASE(mNext); +} + +NS_IMPL_ADDREF(CSSStyleSheetImpl) +NS_IMPL_RELEASE(CSSStyleSheetImpl) + +nsresult CSSStyleSheetImpl::QueryInterface(const nsIID& aIID, + void** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + if (aIID.Equals(kICSSStyleSheetIID)) { + *aInstancePtrResult = (void*) ((nsICSSStyleSheet*)this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIStyleSheetIID)) { + *aInstancePtrResult = (void*) ((nsIStyleSheet*)this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kISupportsIID)) { + *aInstancePtrResult = (void*) ((nsISupports*)this); + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +PRBool CSSStyleSheetImpl::SelectorMatches(nsCSSSelector* aSelector, nsIContent* aContent) +{ + PRBool result = PR_FALSE; + + if ((nsnull == aSelector->mTag) || (aSelector->mTag == aContent->GetTag())) { + if ((nsnull != aSelector->mClass) || (nsnull != aSelector->mTag)) { + nsIHTMLContent* htmlContent; + if (NS_OK == aContent->QueryInterface(kIHTMLContentIID, (void**)&htmlContent)) { + if ((nsnull == aSelector->mClass) || (aSelector->mClass == htmlContent->GetClass())) { + if ((nsnull == aSelector->mID) || (aSelector->mID == htmlContent->GetID())) { + result = PR_TRUE; + } + } + NS_RELEASE(htmlContent); + } + } + else { + result = PR_TRUE; + } + } + return result; +} + +PRInt32 CSSStyleSheetImpl::RulesMatching(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsISupportsArray* aResults) +{ + NS_PRECONDITION(nsnull != aPresContext, "null arg"); + NS_PRECONDITION(nsnull != aContent, "null arg"); +// NS_PRECONDITION(nsnull != aParentFrame, "null arg"); + NS_PRECONDITION(nsnull != aResults, "null arg"); + + PRInt32 matchCount = 0; + CSSStyleSheetImpl* child = mFirstChild; + while (nsnull != child) { + matchCount += child->RulesMatching(aPresContext, aContent, aParentFrame, aResults); + child = child->mNext; + } + + PRInt32 count = ((nsnull != mRules) ? mRules->Count() : 0); + + for (PRInt32 index = 0; index < count; index++) { + nsICSSStyleRule* rule = (nsICSSStyleRule*)mRules->ElementAt(index); + + nsCSSSelector* selector = rule->FirstSelector(); + if (SelectorMatches(selector, aContent)) { + selector = selector->mNext; + nsIFrame* frame = aParentFrame; + while ((nsnull != selector) && (nsnull != frame)) { // check compound selectors + nsIContent* content = frame->GetContent(); + if (SelectorMatches(selector, content)) { + selector = selector->mNext; + } + frame = frame->GetGeometricParent(); + NS_RELEASE(content); + } + if (nsnull == selector) { // ran out, it matched + nsIStyleRule* iRule; + if (NS_OK == rule->QueryInterface(kIStyleRuleIID, (void**)&iRule)) { + aResults->AppendElement(iRule); + NS_RELEASE(iRule); + matchCount++; + } + } + } + NS_RELEASE(rule); + } + return matchCount; +} + +nsIURL* CSSStyleSheetImpl::GetURL(void) +{ + NS_ADDREF(mURL); + return mURL; +} + +PRBool CSSStyleSheetImpl::ContainsStyleSheet(nsIURL* aURL) +{ + NS_PRECONDITION(nsnull != aURL, "null arg"); + + PRBool result = (*mURL == *aURL); + + CSSStyleSheetImpl* child = mFirstChild; + while ((PR_FALSE == result) && (nsnull != child)) { + result = child->ContainsStyleSheet(aURL); + child = child->mNext; + } + return result; +} + +void CSSStyleSheetImpl::AppendStyleSheet(nsICSSStyleSheet* aSheet) +{ + NS_PRECONDITION(nsnull != aSheet, "null arg"); + + if (nsnull == mFirstChild) { + mFirstChild = (CSSStyleSheetImpl*)aSheet; + } + else { + CSSStyleSheetImpl* child = mFirstChild; + while (nsnull != child->mNext) { + child = child->mNext; + } + child->mNext = (CSSStyleSheetImpl*)aSheet; + } + NS_ADDREF(aSheet); +} + +void CSSStyleSheetImpl::PrependStyleRule(nsICSSStyleRule* aRule) +{ + NS_PRECONDITION(nsnull != aRule, "null arg"); + NS_ADDREF(aRule); + //XXX replace this with a binary search? + PRInt32 weight = aRule->GetWeight(); + if (nsnull == mRules) { + if (NS_OK != NS_NewISupportsArray(&mRules)) + return; + } + PRInt32 index = mRules->Count(); + while (0 <= --index) { + nsICSSStyleRule* rule = (nsICSSStyleRule*)mRules->ElementAt(index); + if (rule->GetWeight() > weight) { // insert before rules with equal or lesser weight + NS_RELEASE(rule); + break; + } + NS_RELEASE(rule); + } + mRules->InsertElementAt(aRule, index + 1); +} + +void CSSStyleSheetImpl::AppendStyleRule(nsICSSStyleRule* aRule) +{ + NS_PRECONDITION(nsnull != aRule, "null arg"); + NS_ADDREF(aRule); + + //XXX replace this with a binary search? + PRInt32 weight = aRule->GetWeight(); + if (nsnull == mRules) { + if (NS_OK != NS_NewISupportsArray(&mRules)) + return; + } + PRInt32 count = mRules->Count(); + PRInt32 index = -1; + while (++index < count) { + nsICSSStyleRule* rule = (nsICSSStyleRule*)mRules->ElementAt(index); + if (rule->GetWeight() < weight) { // insert after rules with equal or greater weight (before lower weight) + NS_RELEASE(rule); + break; + } + NS_RELEASE(rule); + } + mRules->InsertElementAt(aRule, index); +} + +void CSSStyleSheetImpl::List(FILE* out, PRInt32 aIndent) const +{ + nsAutoString buffer; + PRInt32 index; + + // Indent + for (index = aIndent; --index >= 0; ) fputs(" ", out); + + fputs("CSS Style Sheet: ", out); + mURL->ToString(buffer); + fputs(buffer, out); + fputs("\n", out); + + CSSStyleSheetImpl* child = mFirstChild; + while (nsnull != child) { + child->List(out, aIndent + 1); + child = child->mNext; + } + + PRInt32 count = ((nsnull != mRules) ? mRules->Count() : 0); + + for (index = 0; index < count; index++) { + nsICSSStyleRule* rule = (nsICSSStyleRule*)mRules->ElementAt(index); + rule->List(out, aIndent); + NS_RELEASE(rule); + } +} + +NS_HTML nsresult + NS_NewCSSStyleSheet(nsICSSStyleSheet** aInstancePtrResult, nsIURL* aURL) +{ + if (aInstancePtrResult == nsnull) { + return NS_ERROR_NULL_POINTER; + } + + CSSStyleSheetImpl *it = new CSSStyleSheetImpl(aURL); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(kICSSStyleSheetIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/layout/html/style/src/nsHTMLAttributes.cpp b/mozilla/layout/html/style/src/nsHTMLAttributes.cpp new file mode 100644 index 00000000000..895e98e277c --- /dev/null +++ b/mozilla/layout/html/style/src/nsHTMLAttributes.cpp @@ -0,0 +1,672 @@ +/* -*- 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 "nsIHTMLAttributes.h" +#include "nsIStyleRule.h" +#include "nsString.h" +#include "nsISupportsArray.h" +#include "nsCRT.h" +#include "nsIArena.h" +#include "nsIStyleContext.h" +#include "nsHTMLAtoms.h" +#include "nsIHTMLContent.h" + +static NS_DEFINE_IID(kIHTMLAttributesIID, NS_IHTML_ATTRIBUTES_IID); +static NS_DEFINE_IID(kIStyleRuleIID, NS_ISTYLE_RULE_IID); + + +struct HTMLAttribute { + HTMLAttribute(nsIAtom* aAttribute, const nsString& aValue) + : mAttribute(aAttribute), + mValue(aValue), + mNext(nsnull) + { + NS_IF_ADDREF(mAttribute); + } + + HTMLAttribute(nsIAtom* aAttribute, const nsHTMLValue& aValue) + : mAttribute(aAttribute), + mValue(aValue), + mNext(nsnull) + { + NS_IF_ADDREF(mAttribute); + } + + HTMLAttribute(const HTMLAttribute& aCopy) + : mAttribute(aCopy.mAttribute), + mValue(aCopy.mValue), + mNext(nsnull) + { + NS_IF_ADDREF(mAttribute); + } + + ~HTMLAttribute(void) + { + NS_IF_RELEASE(mAttribute); + } + + HTMLAttribute& operator=(const HTMLAttribute& aCopy) + { + NS_IF_RELEASE(mAttribute); + mAttribute = aCopy.mAttribute; + NS_IF_ADDREF(mAttribute); + mValue = aCopy.mValue; + return *this; + } + + PRBool operator==(const HTMLAttribute& aOther) const + { + return PRBool((mAttribute == aOther.mAttribute) && + (mValue == aOther.mValue)); + } + + void Reset(void) + { + NS_IF_RELEASE(mAttribute); + mValue.Reset(); + } + + void AppendToString(nsString& aBuffer) const + { + if (nsnull != mAttribute) { + nsAutoString temp; + mAttribute->ToString(temp); + aBuffer.Append(temp); + if (eHTMLUnit_Null != mValue.GetUnit()) { + aBuffer.Append(" = "); + mValue.AppendToString(aBuffer); + } + } + else { + aBuffer.Append("null"); + } + } + + void ToString(nsString& aBuffer) const + { + if (nsnull != mAttribute) { + mAttribute->ToString(aBuffer); + if (eHTMLUnit_Null != mValue.GetUnit()) { + aBuffer.Append(" = "); + mValue.AppendToString(aBuffer); + } + } + else { + aBuffer.SetLength(0); + aBuffer.Append("null"); + } + } + + nsIAtom* mAttribute; + nsHTMLValue mValue; + HTMLAttribute* mNext; +}; + +// ---------------- + + +class HTMLAttributesImpl: public nsIHTMLAttributes, public nsIStyleRule { +public: + void* operator new(size_t size); + void* operator new(size_t size, nsIArena* aArena); + void operator delete(void* ptr); + + HTMLAttributesImpl(nsIHTMLContent* aContent); + ~HTMLAttributesImpl(void); + + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + + virtual PRBool Equals(const nsIStyleRule* aRule) const; + virtual PRUint32 HashValue(void) const; + + virtual PRInt32 SetAttribute(nsIAtom* aAttribute, const nsString& aValue); + virtual PRInt32 SetAttribute(nsIAtom* aAttribute, + const nsHTMLValue& aValue = nsHTMLValue::kNull); + virtual PRInt32 UnsetAttribute(nsIAtom* aAttribute); + virtual nsContentAttr GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aValue) const; + virtual PRInt32 GetAllAttributeNames(nsISupportsArray* aArray) const; + virtual PRInt32 Count(void) const; + + virtual PRInt32 SetID(nsIAtom* aID); + virtual nsIAtom* GetID(void) const; + virtual PRInt32 SetClass(nsIAtom* aClass); // XXX this will have to change for CSS2 + virtual nsIAtom* GetClass(void) const; // XXX this will have to change for CSS2 + + virtual void MapStyleInto(nsIStyleContext* aContext, nsIPresContext* aPresContext); + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + +private: + HTMLAttributesImpl(const HTMLAttributesImpl& aCopy); + HTMLAttributesImpl& operator=(const HTMLAttributesImpl& aCopy); + PRBool operator==(const HTMLAttributesImpl& aCopy) const; + +protected: + PRUint32 mInHeap : 1; + PRUint32 mRefCnt : 31; + + nsIHTMLContent* mContent; + PRInt32 mCount; + HTMLAttribute* mFirst; + nsIAtom* mID; + nsIAtom* mClass; +}; + +void* HTMLAttributesImpl::operator new(size_t size) +{ + HTMLAttributesImpl* rv = (HTMLAttributesImpl*) ::operator new(size); +#ifdef NS_DEBUG + if (nsnull != rv) { + nsCRT::memset(rv, 0xEE, size); + } +#endif + rv->mInHeap = 1; + return (void*) rv; +} + +void* HTMLAttributesImpl::operator new(size_t size, nsIArena* aArena) +{ + HTMLAttributesImpl* rv = (HTMLAttributesImpl*) aArena->Alloc(PRInt32(size)); +#ifdef NS_DEBUG + if (nsnull != rv) { + nsCRT::memset(rv, 0xEE, size); + } +#endif + rv->mInHeap = 0; + return (void*) rv; +} + +void HTMLAttributesImpl::operator delete(void* ptr) +{ + HTMLAttributesImpl* attr = (HTMLAttributesImpl*) ptr; + if (nsnull != attr) { + if (attr->mInHeap) { + ::delete ptr; + } + } +} + + +HTMLAttributesImpl::HTMLAttributesImpl(nsIHTMLContent* aContent) + : mContent(aContent), // weak ref + mFirst(nsnull), + mCount(0), + mID(nsnull), + mClass(nsnull) +{ + NS_INIT_REFCNT(); +} + +HTMLAttributesImpl::~HTMLAttributesImpl(void) +{ + HTMLAttribute* next = mFirst; + while (nsnull != next) { + HTMLAttribute* attr = next; + next = next->mNext; + delete attr; + } + NS_IF_RELEASE(mID); + NS_IF_RELEASE(mClass); +} + +NS_IMPL_ADDREF(HTMLAttributesImpl) +NS_IMPL_RELEASE(HTMLAttributesImpl) + +nsresult HTMLAttributesImpl::QueryInterface(const nsIID& aIID, + void** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + if (aIID.Equals(kIHTMLAttributesIID)) { + *aInstancePtrResult = (void*) ((nsIHTMLAttributes*)this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIStyleRuleIID)) { + *aInstancePtrResult = (void*) ((nsIStyleRule*)this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kISupportsIID)) { + *aInstancePtrResult = (void*) ((nsISupports*)(nsIHTMLAttributes*)this); + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + + +PRBool HTMLAttributesImpl::Equals(const nsIStyleRule* aRule) const +{ + nsIHTMLAttributes* iHTMLAttr; + + if (this == aRule) { + return PR_TRUE; + } + + if ((nsnull != aRule) && + (NS_OK == ((nsIStyleRule*)aRule)->QueryInterface(kIHTMLAttributesIID, (void**) &iHTMLAttr))) { + + const HTMLAttributesImpl* other = (HTMLAttributesImpl*)iHTMLAttr; + PRBool result = PR_FALSE; + + if (mCount == other->mCount) { + if ((mID == other->mID) && (mClass == other->mClass)) { + const HTMLAttribute* attr = mFirst; + const HTMLAttribute* otherAttr = other->mFirst; + + result = PR_TRUE; + while (nsnull != attr) { + if (! ((*attr) == (*otherAttr))) { + result = PR_FALSE; + break; + } + attr = attr->mNext; + otherAttr = otherAttr->mNext; + } + } + } + + NS_RELEASE(iHTMLAttr); + return result; + } + return PR_FALSE; +} + +PRUint32 HTMLAttributesImpl::HashValue(void) const +{ + return (PRUint32)this; +} + +PRInt32 HTMLAttributesImpl::SetAttribute(nsIAtom* aAttribute, const nsString& aValue) +{ + if (nsHTMLAtoms::id == aAttribute) { + nsIAtom* id = NS_NewAtom(aValue); + PRInt32 result = SetID (id); + NS_RELEASE(id); + return result; + } + if (nsHTMLAtoms::kClass == aAttribute) { + nsIAtom* classA = NS_NewAtom(aValue); + PRInt32 result = SetClass (classA); + NS_RELEASE(classA); + return result; + } + + HTMLAttribute* last = nsnull; + HTMLAttribute* attr = mFirst; + + while (nsnull != attr) { + if (attr->mAttribute == aAttribute) { + attr->mValue.Set (aValue); + return mCount; + } + last = attr; + attr = attr->mNext; + } + + attr = new HTMLAttribute(aAttribute, aValue); + if (nsnull == last) { + mFirst = attr; + } + else { + last->mNext = attr; + } + return ++mCount; +} + +PRInt32 HTMLAttributesImpl::SetAttribute(nsIAtom* aAttribute, const nsHTMLValue& aValue) +{ + if (nsHTMLAtoms::id == aAttribute) { + nsAutoString buffer; + nsIAtom* id = NS_NewAtom(aValue.GetStringValue(buffer)); + PRInt32 result = SetID (id); + NS_RELEASE(id); + return result; + } + if (nsHTMLAtoms::kClass == aAttribute) { + nsAutoString buffer; + nsIAtom* classA = NS_NewAtom(aValue.GetStringValue(buffer)); + PRInt32 result = SetClass (classA); + NS_RELEASE(classA); + return result; + } + + HTMLAttribute* last = nsnull; + HTMLAttribute* attr = mFirst; + + while (nsnull != attr) { + if (attr->mAttribute == aAttribute) { + attr->mValue = aValue; + return mCount; + } + last = attr; + attr = attr->mNext; + } + + attr = new HTMLAttribute(aAttribute, aValue); + if (nsnull == last) { + mFirst = attr; + } + else { + last->mNext = attr; + } + return ++mCount; +} + +PRInt32 HTMLAttributesImpl::UnsetAttribute(nsIAtom* aAttribute) +{ + if (nsHTMLAtoms::id == aAttribute) { + return SetID (nsnull); + } + if (nsHTMLAtoms::kClass == aAttribute) { + return SetClass (nsnull); + } + + HTMLAttribute* prev = nsnull; + HTMLAttribute* attr = mFirst; + + while (nsnull != attr) { + if (attr->mAttribute == aAttribute) { + if (nsnull == prev) { + mFirst = attr->mNext; + } + else { + prev->mNext = attr->mNext; + } + delete attr; + mCount--; + break; + } + prev = attr; + attr = attr->mNext; + } + return mCount; +} + +nsContentAttr HTMLAttributesImpl::GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aValue) const +{ + aValue.Reset(); + if (nsHTMLAtoms::id == aAttribute) { + nsIAtom* id = GetID(); + if (nsnull != id) { + nsAutoString buffer; + id->ToString(buffer); + aValue.Set(buffer); + NS_RELEASE(id); + return eContentAttr_HasValue; + } + return eContentAttr_NotThere; + } + if (nsHTMLAtoms::kClass == aAttribute) { + nsIAtom* classA = GetClass(); + if (nsnull != classA) { + nsAutoString buffer; + classA->ToString(buffer); + aValue.Set(buffer); + NS_RELEASE(classA); + return eContentAttr_HasValue; + } + return eContentAttr_NotThere; + } + + HTMLAttribute* attr = mFirst; + + while (nsnull != attr) { + if (attr->mAttribute == aAttribute) { + aValue = attr->mValue; + return ((attr->mValue.GetUnit() == eHTMLUnit_Null) ? eContentAttr_NoValue : eContentAttr_HasValue); + } + attr = attr->mNext; + } + return eContentAttr_NotThere; +} + +PRInt32 HTMLAttributesImpl::GetAllAttributeNames(nsISupportsArray* aArray) const +{ + NS_ASSERTION(nsnull != aArray, "null arg"); + + if (nsnull == aArray) { + return 0; + } + + if (nsnull != mID) { + aArray->AppendElement((nsIAtom*)nsHTMLAtoms::id); + } + if (nsnull != mClass) { + aArray->AppendElement((nsIAtom*)nsHTMLAtoms::kClass); + } + + HTMLAttribute* attr = mFirst; + + while (nsnull != attr) { + aArray->AppendElement(attr->mAttribute); + attr = attr->mNext; + } + return mCount; +} + +PRInt32 HTMLAttributesImpl::Count(void) const +{ + return mCount; +} + +PRInt32 HTMLAttributesImpl::SetID(nsIAtom* aID) +{ + if (aID != mID) { + if (nsnull != mID) { + NS_RELEASE(mID); + mCount--; + } + mID = aID; + if (nsnull != mID) { + NS_ADDREF(mID); + mCount++; + } + } + return mCount; +} + +nsIAtom* HTMLAttributesImpl::GetID(void) const +{ + NS_IF_ADDREF(mID); + return mID; +} + +PRInt32 HTMLAttributesImpl::SetClass(nsIAtom* aClass) +{ + if (aClass != mClass) { + if (nsnull != mClass) { + NS_RELEASE(mClass); + mCount--; + } + mClass = aClass; + if (nsnull != mClass) { + NS_ADDREF(mClass); + mCount++; + } + } + return mCount; +} + +nsIAtom* HTMLAttributesImpl::GetClass(void) const +{ + NS_IF_ADDREF(mClass); + return mClass; +} + +void HTMLAttributesImpl::MapStyleInto(nsIStyleContext* aContext, nsIPresContext* aPresContext) +{ + if (nsnull != mContent) { + mContent->MapAttributesInto(aContext, aPresContext); + } +} + + +void HTMLAttributesImpl::List(FILE* out, PRInt32 aIndent) const +{ + HTMLAttribute* attr = mFirst; + nsString buffer; + + while (nsnull != attr) { + fputs("\n", out); + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + attr->ToString(buffer); + fputs(buffer, out); + attr = attr->mNext; + } +} + +extern NS_HTML nsresult + NS_NewHTMLAttributes(nsIHTMLAttributes** aInstancePtrResult, nsIHTMLContent* aContent) +{ + if (aInstancePtrResult == nsnull) { + return NS_ERROR_NULL_POINTER; + } + + HTMLAttributesImpl *it = new HTMLAttributesImpl(aContent); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(kIHTMLAttributesIID, (void **) aInstancePtrResult); +} + + +#if 0 + + +marginwidth; marginheight: px + +border: px + +align(DIV): left, right, center, justify +align: left, right, center, abscenter +valign: baseline, top, bottom, middle, center +align(image): abscenter, left, right, texttop, absbottom, baseline, center, bottom, top, middle, absmiddle + +dir: rtl, ltr + +width: px, % +height: px, % + +vspace; hspace: px + +type(list): none, disc, (circle | round), square, decimal, lower-roman, upper-roman, lower-alpha, upper-alpha + +href: url +target: string +src: url(string?) +color: color +face: string +suppress: bool + +style: string +class: string (list) +id: string +name: string + +//a +link; vlink; alink: color + +//body +background: url +bgcolor: color +text: color + +//frameset +bordercolor: color + +//layer +background: url +bgcolor: color + +//q +lang: string + +//table +background: url +bgcolor: color +bordercolor: color +cellspacing: px +cellpadding: px +toppadding; leftpadding; bottompadding; rightpadding: px +cols: int + +//td +background: url +bgcolor: color +nowrap: bool +colspan; rowspan: int + +//tr +background: url +bgcolor: color + +//colgroup +span: int + +//col +repeat: int + +//ul;ol +compact: bool +start: int + +//li +value: int + +//hr;spacer +size: px + +//multicol +cols: int +gutter: px + +//input +type: string +value: string + +//factory methods: +GetStringData +GetBoolData +GetInvBoolData +GetPixelIntData +GetValueOrPctData +GetValueData + +//tag methods +getAttribute +getIntAttribute +getKeywordAttribute +getSignedAttribute +getValueOrPctAttribute + + +//notes +nsIAtom->value table + +#endif diff --git a/mozilla/layout/html/style/src/nsHTMLStyleSheet.cpp b/mozilla/layout/html/style/src/nsHTMLStyleSheet.cpp new file mode 100644 index 00000000000..687a1030ee4 --- /dev/null +++ b/mozilla/layout/html/style/src/nsHTMLStyleSheet.cpp @@ -0,0 +1,214 @@ +/* -*- 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 "nsIHTMLStyleSheet.h" +#include "nsIArena.h" +#include "nsCRT.h" +#include "nsIAtom.h" +#include "nsIURL.h" +#include "nsISupportsArray.h" +#include "nsIHTMLContent.h" +#include "nsIStyleRule.h" + +static NS_DEFINE_IID(kIHTMLStyleSheetIID, NS_IHTML_STYLE_SHEET_IID); +static NS_DEFINE_IID(kIStyleSheetIID, NS_ISTYLE_SHEET_IID); +static NS_DEFINE_IID(kIHTMLContentIID, NS_IHTMLCONTENT_IID); + + +class HTMLStyleSheetImpl : public nsIHTMLStyleSheet { +public: + void* operator new(size_t size); + void* operator new(size_t size, nsIArena* aArena); + void operator delete(void* ptr); + + HTMLStyleSheetImpl(nsIURL* aURL); + + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + + virtual PRInt32 RulesMatching(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsISupportsArray* aResults); + + virtual nsIURL* GetURL(void); + + // XXX style rule enumerations + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + +private: + // These are not supported and are not implemented! + HTMLStyleSheetImpl(const HTMLStyleSheetImpl& aCopy); + HTMLStyleSheetImpl& operator=(const HTMLStyleSheetImpl& aCopy); + +protected: + virtual ~HTMLStyleSheetImpl(); + +protected: + PRUint32 mInHeap : 1; + PRUint32 mRefCnt : 31; + + nsIURL* mURL; +}; + + +void* HTMLStyleSheetImpl::operator new(size_t size) +{ + HTMLStyleSheetImpl* rv = (HTMLStyleSheetImpl*) ::operator new(size); +#ifdef NS_DEBUG + if (nsnull != rv) { + nsCRT::memset(rv, 0xEE, size); + } +#endif + rv->mInHeap = 1; + return (void*) rv; +} + +void* HTMLStyleSheetImpl::operator new(size_t size, nsIArena* aArena) +{ + HTMLStyleSheetImpl* rv = (HTMLStyleSheetImpl*) aArena->Alloc(PRInt32(size)); +#ifdef NS_DEBUG + if (nsnull != rv) { + nsCRT::memset(rv, 0xEE, size); + } +#endif + rv->mInHeap = 0; + return (void*) rv; +} + +void HTMLStyleSheetImpl::operator delete(void* ptr) +{ + HTMLStyleSheetImpl* sheet = (HTMLStyleSheetImpl*) ptr; + if (nsnull != sheet) { + if (sheet->mInHeap) { + ::delete ptr; + } + } +} + + + +HTMLStyleSheetImpl::HTMLStyleSheetImpl(nsIURL* aURL) + : nsIHTMLStyleSheet(), + mURL(aURL) +{ + NS_INIT_REFCNT(); + NS_ADDREF(mURL); +} + +HTMLStyleSheetImpl::~HTMLStyleSheetImpl() +{ + NS_RELEASE(mURL); +} + +NS_IMPL_ADDREF(HTMLStyleSheetImpl) +NS_IMPL_RELEASE(HTMLStyleSheetImpl) + +nsresult HTMLStyleSheetImpl::QueryInterface(const nsIID& aIID, + void** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + if (aIID.Equals(kIHTMLStyleSheetIID)) { + *aInstancePtrResult = (void*) ((nsIHTMLStyleSheet*)this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIStyleSheetIID)) { + *aInstancePtrResult = (void*) ((nsIStyleSheet*)this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kISupportsIID)) { + *aInstancePtrResult = (void*) ((nsISupports*)this); + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +PRInt32 HTMLStyleSheetImpl::RulesMatching(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsISupportsArray* aResults) +{ + NS_PRECONDITION(nsnull != aPresContext, "null arg"); + NS_PRECONDITION(nsnull != aContent, "null arg"); +// NS_PRECONDITION(nsnull != aParentFrame, "null arg"); + NS_PRECONDITION(nsnull != aResults, "null arg"); + + PRInt32 matchCount = 0; + + nsIHTMLContent* htmlContent; + + // for now, just get the one and only style rule from the content + // this may need some special handling for pseudo-frames + if (NS_OK == aContent->QueryInterface(kIHTMLContentIID, (void**)&htmlContent)) { + nsIStyleRule* rule = htmlContent->GetStyleRule(); + + if (nsnull != rule) { + aResults->AppendElement(rule); + NS_RELEASE(rule); + matchCount++; + } + + NS_RELEASE(htmlContent); + } + + return matchCount; +} + +nsIURL* HTMLStyleSheetImpl::GetURL(void) +{ + NS_ADDREF(mURL); + return mURL; +} + +void HTMLStyleSheetImpl::List(FILE* out, PRInt32 aIndent) const +{ + nsAutoString buffer; + + // Indent + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + fputs("HTML Style Sheet: ", out); + mURL->ToString(buffer); + fputs(buffer, out); + fputs("\n", out); + +} + +NS_HTML nsresult + NS_NewHTMLStyleSheet(nsIHTMLStyleSheet** aInstancePtrResult, nsIURL* aURL) +{ + if (aInstancePtrResult == nsnull) { + return NS_ERROR_NULL_POINTER; + } + + HTMLStyleSheetImpl *it = new HTMLStyleSheetImpl(aURL); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(kIHTMLStyleSheetIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/layout/html/style/src/nsHTMLValue.cpp b/mozilla/layout/html/style/src/nsHTMLValue.cpp new file mode 100644 index 00000000000..ed2df9aaab5 --- /dev/null +++ b/mozilla/layout/html/style/src/nsHTMLValue.cpp @@ -0,0 +1,257 @@ +/* -*- 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 "nsHTMLValue.h" +#include "nsString.h" +#include "nsCRT.h" + +const nsHTMLValue nsHTMLValue::kNull; + +nsHTMLValue::nsHTMLValue(void) + : mUnit(eHTMLUnit_Null) +{ + mValue.mString = nsnull; +} + +nsHTMLValue::nsHTMLValue(PRInt32 aValue, nsHTMLUnit aUnit) + : mUnit(aUnit) +{ + mValue.mInt = aValue; +} + +nsHTMLValue::nsHTMLValue(float aValue, nsHTMLUnit aUnit) + : mUnit(aUnit) +{ + mValue.mFloat = aValue; +} + +nsHTMLValue::nsHTMLValue(const nsString& aValue) + : mUnit(eHTMLUnit_String) +{ + mValue.mString = aValue.ToNewString(); +} + +nsHTMLValue::nsHTMLValue(nsISupports* aValue) + : mUnit(eHTMLUnit_ISupports) +{ + mValue.mISupports = aValue; + NS_IF_ADDREF(mValue.mISupports); +} + +nsHTMLValue::nsHTMLValue(nscolor aValue) + : mUnit(eHTMLUnit_Color) +{ + mValue.mColor = aValue; +} + +nsHTMLValue::nsHTMLValue(const nsHTMLValue& aCopy) + : mUnit(aCopy.mUnit) +{ + if (eHTMLUnit_String == mUnit) { + if (nsnull != aCopy.mValue.mString) { + mValue.mString = aCopy.mValue.mString->ToNewString(); + } + else { + mValue.mString = nsnull; + } + } + else if (eHTMLUnit_ISupports == mUnit) { + mValue.mISupports = aCopy.mValue.mISupports; + NS_IF_ADDREF(mValue.mISupports); + } + else if (eHTMLUnit_Color == mUnit){ + mValue.mColor = aCopy.mValue.mColor; + } + else if (eHTMLUnit_Percent == mUnit) { + mValue.mFloat = aCopy.mValue.mFloat; + } + else { + mValue.mInt = aCopy.mValue.mInt; + } +} + +nsHTMLValue::~nsHTMLValue(void) +{ + Reset(); +} + +nsHTMLValue& nsHTMLValue::operator=(const nsHTMLValue& aCopy) +{ + Reset(); + mUnit = aCopy.mUnit; + if (eHTMLUnit_String == mUnit) { + if (nsnull != aCopy.mValue.mString) { + mValue.mString = aCopy.mValue.mString->ToNewString(); + } + } + else if (eHTMLUnit_ISupports == mUnit) { + mValue.mISupports = aCopy.mValue.mISupports; + NS_IF_ADDREF(mValue.mISupports); + } + else if (eHTMLUnit_Color == mUnit){ + mValue.mColor = aCopy.mValue.mColor; + } + else if (eHTMLUnit_Percent == mUnit) { + mValue.mFloat = aCopy.mValue.mFloat; + } + else { + mValue.mInt = aCopy.mValue.mInt; + } + return *this; +} + +PRBool nsHTMLValue::operator==(const nsHTMLValue& aOther) const +{ + if (mUnit == aOther.mUnit) { + if (eHTMLUnit_String == mUnit) { + if (nsnull == mValue.mString) { + if (nsnull == aOther.mValue.mString) { + return PR_TRUE; + } + } + else if (nsnull != aOther.mValue.mString) { + return mValue.mString->Equals(*(aOther.mValue.mString)); + } + } + else if (eHTMLUnit_ISupports == mUnit) { + return PRBool(mValue.mISupports == aOther.mValue.mISupports); + } + else if (eHTMLUnit_Color == mUnit){ + return PRBool(mValue.mColor == aOther.mValue.mColor); + } + else if (eHTMLUnit_Percent == mUnit) { + return PRBool(mValue.mFloat == aOther.mValue.mFloat); + } + else { + return PRBool(mValue.mInt == aOther.mValue.mInt); + } + } + return PR_FALSE; +} + +void nsHTMLValue::Reset(void) +{ + if (eHTMLUnit_String == mUnit) { + if (nsnull != mValue.mString) { + delete mValue.mString; + } + } + else if (eHTMLUnit_ISupports == mUnit) { + NS_IF_RELEASE(mValue.mISupports); + } + mUnit = eHTMLUnit_Null; + mValue.mString = nsnull; +} + + +void nsHTMLValue::Set(PRInt32 aValue, nsHTMLUnit aUnit) +{ + Reset(); + mUnit = aUnit; + mValue.mInt = aValue; +} + +void nsHTMLValue::Set(float aValue, nsHTMLUnit aUnit) +{ + Reset(); + mUnit = aUnit; + mValue.mFloat = aValue; +} + +void nsHTMLValue::Set(const nsString& aValue) +{ + Reset(); + mUnit = eHTMLUnit_String; + mValue.mString = aValue.ToNewString(); +} + +void nsHTMLValue::Set(nsISupports* aValue) +{ + Reset(); + mUnit = eHTMLUnit_ISupports; + mValue.mISupports = aValue; + NS_IF_ADDREF(mValue.mISupports); +} + +void nsHTMLValue::Set(nscolor aValue) +{ + Reset(); + mUnit = eHTMLUnit_Color; + mValue.mColor = aValue; +} + +void nsHTMLValue::AppendToString(nsString& aBuffer) const +{ + if (eHTMLUnit_Null == mUnit) { + return; + } + + if (eHTMLUnit_String == mUnit) { + if (nsnull != mValue.mString) { + aBuffer.Append('"'); + aBuffer.Append(*(mValue.mString)); + aBuffer.Append('"'); + } + else { + aBuffer.Append("null str"); + } + } + else if (eHTMLUnit_ISupports == mUnit) { + aBuffer.Append("0x"); + aBuffer.Append((PRInt32)mValue.mISupports, 16); + } + else if (eHTMLUnit_Color == mUnit){ + aBuffer.Append("(0x"); + aBuffer.Append(NS_GET_R(mValue.mColor), 16); + aBuffer.Append(" 0x"); + aBuffer.Append(NS_GET_G(mValue.mColor), 16); + aBuffer.Append(" 0x"); + aBuffer.Append(NS_GET_B(mValue.mColor), 16); + aBuffer.Append(" 0x"); + aBuffer.Append(NS_GET_A(mValue.mColor), 16); + aBuffer.Append(')'); + } + else if (eHTMLUnit_Percent == mUnit) { + aBuffer.Append(mValue.mFloat); + } + else { + aBuffer.Append(mValue.mInt, 10); + aBuffer.Append("[0x"); + aBuffer.Append(mValue.mInt, 16); + aBuffer.Append(']'); + } + + switch (mUnit) { + case eHTMLUnit_Null: break; + case eHTMLUnit_String: break; + case eHTMLUnit_ISupports: aBuffer.Append("ptr"); break; + case eHTMLUnit_Absolute: break; + case eHTMLUnit_Enumerated: aBuffer.Append("enum"); break; + case eHTMLUnit_Color: aBuffer.Append("rbga"); break; + case eHTMLUnit_Percent: aBuffer.Append("%"); break; + case eHTMLUnit_Pixel: aBuffer.Append("px"); break; + } + aBuffer.Append(' '); +} + +void nsHTMLValue::ToString(nsString& aBuffer) const +{ + aBuffer.SetLength(0); + AppendToString(aBuffer); +} + diff --git a/mozilla/layout/html/style/src/nsHTMLValue.h b/mozilla/layout/html/style/src/nsHTMLValue.h new file mode 100644 index 00000000000..a2f5309e614 --- /dev/null +++ b/mozilla/layout/html/style/src/nsHTMLValue.h @@ -0,0 +1,138 @@ +/* -*- 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. + */ +#ifndef nsHTMLValue_h___ +#define nsHTMLValue_h___ + +#include "nscore.h" +#include "nsColor.h" +#include "nsString.h" +#include "nsISupports.h" + + +enum nsHTMLUnit { + eHTMLUnit_Null = 0, // (n/a) null unit, value is not specified + eHTMLUnit_String = 10, // (nsString) a string value + eHTMLUnit_ISupports = 20, // (nsISupports*) a ref counted interface + eHTMLUnit_Absolute = 50, // (int) simple value + eHTMLUnit_Enumerated = 51, // (int) value has enumerated meaning + eHTMLUnit_Color = 80, // (color) an RGBA value + eHTMLUnit_Percent = 90, // (float) 1.0 == 100%) value is percentage of something + + // Screen relative measure + eHTMLUnit_Pixel = 600, // (int) screen pixels +}; + +class nsHTMLValue { +public: + nsHTMLValue(void); + nsHTMLValue(PRInt32 aValue, nsHTMLUnit aUnit = eHTMLUnit_Absolute); + nsHTMLValue(float aValue, nsHTMLUnit aUnit = eHTMLUnit_Pixel); + nsHTMLValue(const nsString& aValue); + nsHTMLValue(nsISupports* aValue); + nsHTMLValue(nscolor aValue); + nsHTMLValue(const nsHTMLValue& aCopy); + ~nsHTMLValue(void); + + nsHTMLValue& operator=(const nsHTMLValue& aCopy); + PRBool operator==(const nsHTMLValue& aOther) const; + + nsHTMLUnit GetUnit(void) const { return mUnit; } + PRInt32 GetIntValue(void) const; + float GetFloatValue(void) const; + nsString& GetStringValue(nsString& aBuffer) const; + nsISupports* GetISupportsValue(void) const; + nscolor GetColorValue(void) const; + + void Reset(void); + void Set(PRInt32 aValue, nsHTMLUnit aUnit = eHTMLUnit_Absolute); + void Set(float aValue, nsHTMLUnit aUnit = eHTMLUnit_Pixel); + void Set(const nsString& aValue); + void Set(nsISupports* aValue); + void Set(nscolor aValue); + + void AppendToString(nsString& aBuffer) const; + void ToString(nsString& aBuffer) const; + +protected: + nsHTMLUnit mUnit; + union { + PRInt32 mInt; + float mFloat; + nsString* mString; + nsISupports* mISupports; + nscolor mColor; + } mValue; + +public: + static const nsHTMLValue kNull; +}; + +inline PRInt32 nsHTMLValue::GetIntValue(void) const +{ + NS_ASSERTION((mUnit == eHTMLUnit_Absolute) || + (mUnit == eHTMLUnit_Enumerated) || + (mUnit == eHTMLUnit_Pixel), "not an int value"); + if ((mUnit == eHTMLUnit_Absolute) || + (mUnit == eHTMLUnit_Enumerated) || + (mUnit == eHTMLUnit_Pixel)) { + return mValue.mInt; + } + return 0; +} + +inline float nsHTMLValue::GetFloatValue(void) const +{ + NS_ASSERTION(mUnit == eHTMLUnit_Percent, "not a float value"); + if (mUnit == eHTMLUnit_Percent) { + return mValue.mFloat; + } + return 0.0f; +} + +inline nsString& nsHTMLValue::GetStringValue(nsString& aBuffer) const +{ + NS_ASSERTION((mUnit == eHTMLUnit_String) || (mUnit == eHTMLUnit_Null), "not a string value"); + aBuffer.SetLength(0); + if ((mUnit == eHTMLUnit_String) && (nsnull != mValue.mString)) { + aBuffer.Append(*(mValue.mString)); + } + return aBuffer; +} + +inline nsISupports* nsHTMLValue::GetISupportsValue(void) const +{ + NS_ASSERTION(mUnit == eHTMLUnit_ISupports, "not an ISupports value"); + if (mUnit == eHTMLUnit_ISupports) { + NS_IF_ADDREF(mValue.mISupports); + return mValue.mISupports; + } + return nsnull; +} + +inline nscolor nsHTMLValue::GetColorValue(void) const +{ + NS_ASSERTION(mUnit == eHTMLUnit_Color, "not a color value"); + if (mUnit == eHTMLUnit_Color) { + return mValue.mColor; + } + return NS_RGB(0,0,0); +} + + +#endif /* nsHTMLValue_h___ */ + diff --git a/mozilla/layout/html/style/src/nsICSSDeclaration.h b/mozilla/layout/html/style/src/nsICSSDeclaration.h new file mode 100644 index 00000000000..62e8bceb61a --- /dev/null +++ b/mozilla/layout/html/style/src/nsICSSDeclaration.h @@ -0,0 +1,305 @@ +/* -*- 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. + */ +#ifndef nsICSSDeclaration_h___ +#define nsICSSDeclaration_h___ + +#include "nslayout.h" +#include "nsISupports.h" +#include "nsColor.h" +#include "stdio.h" +#include "nsString.h" +#include "nsCoord.h" + + +enum nsCSSUnit { + eCSSUnit_Null = 0, // (n/a) null unit, value is not specified + eCSSUnit_Auto = 1, // (n/a) value is algorithmic + eCSSUnit_String = 10, // (nsString) a string value + eCSSUnit_Absolute = 50, // (int) simple value + eCSSUnit_Enumerated = 51, // (int) value has enumerated meaning + eCSSUnit_Color = 80, // (color) an RGBA value + eCSSUnit_Percent = 90, // (float) 1.0 == 100%) value is percentage of something + eCSSUnit_Number = 91, // (float) value is numeric (usually multiplier, different behavior that percent) + + // US English + eCSSUnit_Inch = 100, // (float) Standard length + eCSSUnit_Foot = 101, // (float) 12 inches + eCSSUnit_Mile = 102, // (float) 5280 feet + + // Metric + eCSSUnit_Millimeter = 207, // (float) 1/1000 meter + eCSSUnit_Centimeter = 208, // (float) 1/100 meter + eCSSUnit_Meter = 210, // (float) Standard length + eCSSUnit_Kilometer = 213, // (float) 1000 meters + + // US Typographic + eCSSUnit_Point = 300, // (float) 1/72 inch + eCSSUnit_Pica = 301, // (float) 12 points == 1/6 inch + + // European Typographic + eCSSUnit_Didot = 400, // (float) 15 didots == 16 points + eCSSUnit_Cicero = 401, // (float) 12 didots + + // relative units + // Font relative measure + eCSSUnit_EM = 800, // (float) == current font size + eCSSUnit_EN = 801, // (float) .5 em + eCSSUnit_XHeight = 802, // (float) distance from top of lower case x to baseline + eCSSUnit_CapHeight = 803, // (float) distance from top of uppercase case H to baseline + + // Screen relative measure + eCSSUnit_Pixel = 900 // (float) +}; + +struct nsCSSStruct { + virtual const nsID& GetID(void) = 0; +}; + +class nsCSSValue { +public: + nsCSSValue(void); + nsCSSValue(PRInt32 aValue, nsCSSUnit aUnit); + nsCSSValue(float aValue, nsCSSUnit aUnit); + nsCSSValue(const nsString& aValue); + nsCSSValue(nscolor aValue); + nsCSSValue(const nsCSSValue& aCopy); + ~nsCSSValue(void); + + nsCSSValue& operator=(const nsCSSValue& aCopy); + PRBool operator==(const nsCSSValue& aOther) const; + + nsCSSUnit GetUnit(void) const { return mUnit; }; + PRBool IsLengthUnit(void) const + { return PRBool(eCSSUnit_Inch <= mUnit); } + PRBool IsFixedLengthUnit(void) const + { return PRBool((eCSSUnit_Inch <= mUnit) && (mUnit < eCSSUnit_EM)); } + PRBool IsRelativeLengthUnit(void) const + { return PRBool(eCSSUnit_EM <= mUnit); } + + PRInt32 GetIntValue(void) const; + float GetFloatValue(void) const; + nsString& GetStringValue(nsString& aBuffer) const; + nscolor GetColorValue(void) const; + nscoord GetLengthTwips(void) const; + + void Reset(void); + void Set(PRInt32 aValue, nsCSSUnit aUnit); + void Set(float aValue, nsCSSUnit aUnit); + void Set(const nsString& aValue); + void Set(nscolor aValue); + + void AppendToString(nsString& aBuffer, PRInt32 aPropID = -1) const; + void ToString(nsString& aBuffer, PRInt32 aPropID = -1) const; + +protected: + nsCSSUnit mUnit; + union { + PRInt32 mInt; + float mFloat; + nsString* mString; + nscolor mColor; + } mValue; +}; + +inline PRInt32 nsCSSValue::GetIntValue(void) const +{ + NS_ASSERTION((mUnit == eCSSUnit_Absolute) || + (mUnit == eCSSUnit_Enumerated), "not an int value"); + if ((mUnit == eCSSUnit_Absolute) || + (mUnit == eCSSUnit_Enumerated)) { + return mValue.mInt; + } + return 0; +} + +inline float nsCSSValue::GetFloatValue(void) const +{ + NS_ASSERTION((mUnit != eCSSUnit_Null) && + (mUnit != eCSSUnit_Absolute) && + (mUnit != eCSSUnit_Enumerated) && + (mUnit != eCSSUnit_String) && + (mUnit != eCSSUnit_Color), "not a float value"); + if ((mUnit != eCSSUnit_Null) && + (mUnit != eCSSUnit_Absolute) && + (mUnit != eCSSUnit_Enumerated) && + (mUnit != eCSSUnit_String) && + (mUnit != eCSSUnit_Color)) { + return mValue.mFloat; + } + return 0.0f; +} + +inline nsString& nsCSSValue::GetStringValue(nsString& aBuffer) const +{ + NS_ASSERTION((mUnit == eCSSUnit_String), "not a string value"); + aBuffer.Truncate(); + if ((mUnit == eCSSUnit_String) && (nsnull != mValue.mString)) { + aBuffer.Append(*(mValue.mString)); + } + return aBuffer; +} + +inline nscolor nsCSSValue::GetColorValue(void) const +{ + NS_ASSERTION((mUnit == eCSSUnit_Color), "not a color value"); + if (mUnit == eCSSUnit_Color) { + return mValue.mColor; + } + return NS_RGB(0,0,0); +} + +// SID for the nsCSSFont struct {f645dbf8-b48a-11d1-9ca5-0060088f9ff7} +#define NS_CSS_FONT_SID \ +{0xf645dbf8, 0xb48a, 0x11d1, {0x9c, 0xa5, 0x00, 0x60, 0x08, 0x8f, 0x9f, 0xf7}} + +// SID for the nsCSSColor struct {fd825f22-b48a-11d1-9ca5-0060088f9ff7} +#define NS_CSS_COLOR_SID \ +{0xfd825f22, 0xb48a, 0x11d1, {0x9c, 0xa5, 0x00, 0x60, 0x08, 0x8f, 0x9f, 0xf7}} + +// SID for the nsCSSText struct {fe13ce94-b48a-11d1-9ca5-0060088f9ff7} +#define NS_CSS_TEXT_SID \ +{0xfe13ce94, 0xb48a, 0x11d1, {0x9c, 0xa5, 0x00, 0x60, 0x08, 0x8f, 0x9f, 0xf7}} + +// SID for the nsCSSMargin struct {fe6019d4-b48a-11d1-9ca5-0060088f9ff7} +#define NS_CSS_MARGIN_SID \ +{0xfe6019d4, 0xb48a, 0x11d1, {0x9c, 0xa5, 0x00, 0x60, 0x08, 0x8f, 0x9f, 0xf7}} + +// SID for the nsCSSPosition struct {fee33b2a-b48a-11d1-9ca5-0060088f9ff7} +#define NS_CSS_POSITION_SID \ +{0xfee33b2a, 0xb48a, 0x11d1, {0x9c, 0xa5, 0x00, 0x60, 0x08, 0x8f, 0x9f, 0xf7}} + +// SID for the nsCSSList struct {603f8266-b48b-11d1-9ca5-0060088f9ff7} +#define NS_CSS_LIST_SID \ +{0x603f8266, 0xb48b, 0x11d1, {0x9c, 0xa5, 0x00, 0x60, 0x08, 0x8f, 0x9f, 0xf7}} + +// IID for the nsICSSDeclaration interface {7b36b9ac-b48d-11d1-9ca5-0060088f9ff7} +#define NS_ICSS_DECLARATION_IID \ +{0x7b36b9ac, 0xb48d, 0x11d1, {0x9c, 0xa5, 0x00, 0x60, 0x08, 0x8f, 0x9f, 0xf7}} + +struct nsCSSFont : public nsCSSStruct { + const nsID& GetID(void); + void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + + nsCSSValue mFamily; + nsCSSValue mStyle; + nsCSSValue mVariant; + nsCSSValue mWeight; + nsCSSValue mSize; +}; + +struct nsCSSColor : public nsCSSStruct { + const nsID& GetID(void); + void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + + nsCSSValue mColor; + nsCSSValue mBackColor; + nsCSSValue mBackImage; + nsCSSValue mBackRepeat; + nsCSSValue mBackAttachment; + nsCSSValue mBackPositionX; + nsCSSValue mBackPositionY; + nsCSSValue mBackFilter; +}; + +struct nsCSSText : public nsCSSStruct { + const nsID& GetID(void); + void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + + nsCSSValue mWordSpacing; + nsCSSValue mLetterSpacing; + nsCSSValue mDecoration; + nsCSSValue mVertAlign; + nsCSSValue mTransform; + nsCSSValue mHorzAlign; + nsCSSValue mIndent; + nsCSSValue mLineHeight; + nsCSSValue mWhiteSpace; +}; + +struct nsCSSRect { + void List(FILE* out = 0, PRInt32 aPropID = -1, PRInt32 aIndent = 0) const; + + nsCSSValue mTop; + nsCSSValue mRight; + nsCSSValue mBottom; + nsCSSValue mLeft; +}; + +struct nsCSSMargin : public nsCSSStruct { + nsCSSMargin(void); + ~nsCSSMargin(void); + const nsID& GetID(void); + void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + + nsCSSRect* mMargin; + nsCSSRect* mPadding; + nsCSSRect* mBorder; + nsCSSRect* mColor; + nsCSSRect* mStyle; +}; + +struct nsCSSPosition : public nsCSSStruct { + nsCSSPosition(void); + ~nsCSSPosition(void); + const nsID& GetID(void); + void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + + nsCSSValue mPosition; + nsCSSValue mWidth; + nsCSSValue mHeight; + nsCSSValue mLeft; + nsCSSValue mTop; + nsCSSRect* mClip; + nsCSSValue mOverflow; + nsCSSValue mZIndex; + nsCSSValue mVisibility; + nsCSSValue mFloat; + nsCSSValue mClear; + nsCSSValue mDisplay; + nsCSSValue mFilter; +}; + +struct nsCSSList : public nsCSSStruct { + const nsID& GetID(void); + void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + + nsCSSValue mType; + nsCSSValue mImage; + nsCSSValue mPosition; +}; + + +class nsICSSDeclaration : public nsISupports { +public: + virtual nsresult GetData(const nsID& aIID, nsCSSStruct** aData) = 0; + virtual nsresult EnsureData(const nsID& aSID, nsCSSStruct** aData) = 0; + + virtual nsresult AddValue(const char* aProperty, const nsCSSValue& aValue) = 0; + virtual nsresult AddValue(PRInt32 aProperty, const nsCSSValue& aValue) = 0; +// XXX make nscolor a struct to avoid type conflicts + virtual nsresult GetValue(const char* aProperty, nsCSSValue& aValue) = 0; + virtual nsresult GetValue(PRInt32 aProperty, nsCSSValue& aValue) = 0; + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const = 0; +}; + +extern NS_HTML nsresult + NS_NewCSSDeclaration(nsICSSDeclaration** aInstancePtrResult); + +#endif /* nsICSSDeclaration_h___ */ + diff --git a/mozilla/layout/html/style/src/nsICSSStyleRule.h b/mozilla/layout/html/style/src/nsICSSStyleRule.h new file mode 100644 index 00000000000..153397fe876 --- /dev/null +++ b/mozilla/layout/html/style/src/nsICSSStyleRule.h @@ -0,0 +1,76 @@ +/* -*- 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. + */ +#ifndef nsICSSStyleRule_h___ +#define nsICSSStyleRule_h___ + +#include +#include "nslayout.h" +#include "nsIStyleRule.h" +class nsIAtom; +class nsIArena; +class nsString; +class nsICSSDeclaration; + + +struct nsCSSSelector { +public: + nsCSSSelector(); + nsCSSSelector(nsIAtom* aTag, nsIAtom* aID, nsIAtom* aClass, nsIAtom* aPseudoClass); + nsCSSSelector(const nsCSSSelector& aCopy); + ~nsCSSSelector(); + + nsCSSSelector& operator=(const nsCSSSelector& aCopy); + PRBool Equals(const nsCSSSelector* aOther) const; + + void Set(const nsString& aTag, const nsString& aID, const nsString& aClass, const nsString& aPseudoClass); + +public: + nsIAtom* mTag; + nsIAtom* mID; + nsIAtom* mClass; // this'll have to be an array for CSS2 + nsIAtom* mPseudoClass; + + nsCSSSelector* mNext; +}; + +// IID for the nsICSSStyleRule interface {7c277af0-af19-11d1-8031-006008159b5a} +#define NS_ICSS_STYLE_RULE_IID \ +{0x7c277af0, 0xaf19, 0x11d1, {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}} + +class nsICSSStyleRule : public nsIStyleRule { +public: + virtual PRBool Equals(const nsIStyleRule* aRule) const = 0; + virtual PRUint32 HashValue(void) const = 0; + + virtual nsCSSSelector* FirstSelector(void) = 0; + virtual void AddSelector(const nsCSSSelector& aSelector) = 0; + virtual void DeleteSelector(nsCSSSelector* aSelector) = 0; + + virtual nsICSSDeclaration* GetDeclaration(void) const = 0; + virtual void SetDeclaration(nsICSSDeclaration* aDeclaration) = 0; + + virtual PRInt32 GetWeight(void) const = 0; + virtual void SetWeight(PRInt32 aWeight) = 0; + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const = 0; +}; + +extern NS_HTML nsresult + NS_NewCSSStyleRule(nsICSSStyleRule** aInstancePtrResult, const nsCSSSelector& aSelector); + +#endif /* nsICSSStyleRule_h___ */ diff --git a/mozilla/layout/html/style/src/nsICSSStyleSheet.h b/mozilla/layout/html/style/src/nsICSSStyleSheet.h new file mode 100644 index 00000000000..f16ed263ed6 --- /dev/null +++ b/mozilla/layout/html/style/src/nsICSSStyleSheet.h @@ -0,0 +1,45 @@ +/* -*- 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. + */ +#ifndef nsICSSStyleSheet_h___ +#define nsICSSStyleSheet_h___ + +#include "nslayout.h" +#include "nsIStyleSheet.h" + +class nsICSSStyleRule; + +// IID for the nsICSSStyleSheet interface {8f83b0f0-b21a-11d1-8031-006008159b5a} +#define NS_ICSS_STYLE_SHEET_IID \ +{0x8f83b0f0, 0xb21a, 0x11d1, {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}} + +class nsICSSStyleSheet : public nsIStyleSheet { +public: + virtual PRBool ContainsStyleSheet(nsIURL* aURL) = 0; + + virtual void AppendStyleSheet(nsICSSStyleSheet* aSheet) = 0; + + // XXX do these belong here or are they generic? + virtual void PrependStyleRule(nsICSSStyleRule* aRule) = 0; + virtual void AppendStyleRule(nsICSSStyleRule* aRule) = 0; + +}; + +extern NS_HTML nsresult + NS_NewCSSStyleSheet(nsICSSStyleSheet** aInstancePtrResult, nsIURL* aURL); + +#endif /* nsICSSStyleSheet_h___ */ diff --git a/mozilla/layout/html/style/src/nsIHTMLAttributes.h b/mozilla/layout/html/style/src/nsIHTMLAttributes.h new file mode 100644 index 00000000000..f3f2428401e --- /dev/null +++ b/mozilla/layout/html/style/src/nsIHTMLAttributes.h @@ -0,0 +1,59 @@ +/* -*- 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. + */ +#ifndef nsIHTMLAttributes_h___ +#define nsIHTMLAttributes_h___ + +#include "nslayout.h" +#include "nsISupports.h" +#include "nsHTMLValue.h" +#include "nsIContent.h" +class nsIAtom; +class nsISupportsArray; +class nsIHTMLContent; + + +// IID for the nsIHTMLAttributes interface {a18f85f0-c058-11d1-8031-006008159b5a} +#define NS_IHTML_ATTRIBUTES_IID \ +{0xa18f85f0, 0xc058, 0x11d1, \ + {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}} + +class nsIHTMLAttributes : public nsISupports { +public: + virtual PRInt32 SetAttribute(nsIAtom* aAttribute, const nsString& aValue) = 0; + virtual PRInt32 SetAttribute(nsIAtom* aAttribute, + const nsHTMLValue& aValue = nsHTMLValue::kNull) = 0; + virtual PRInt32 UnsetAttribute(nsIAtom* aAttribute) = 0; + virtual nsContentAttr GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aValue) const = 0; + virtual PRInt32 GetAllAttributeNames(nsISupportsArray* aArray) const = 0; + + virtual PRInt32 Count(void) const = 0; + + virtual PRInt32 SetID(nsIAtom* aID) = 0; + virtual nsIAtom* GetID(void) const = 0; + virtual PRInt32 SetClass(nsIAtom* aClass) = 0; // XXX this will have to change for CSS2 + virtual nsIAtom* GetClass(void) const = 0; // XXX this will have to change for CSS2 + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const = 0; +}; + +extern NS_HTML nsresult + NS_NewHTMLAttributes(nsIHTMLAttributes** aInstancePtrResult, nsIHTMLContent* aContent); + +#endif /* nsIHTMLAttributes_h___ */ + diff --git a/mozilla/layout/html/style/src/nsIHTMLStyleSheet.h b/mozilla/layout/html/style/src/nsIHTMLStyleSheet.h new file mode 100644 index 00000000000..3e85e75c6b5 --- /dev/null +++ b/mozilla/layout/html/style/src/nsIHTMLStyleSheet.h @@ -0,0 +1,36 @@ +/* -*- 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. + */ +#ifndef nsIHTMLStyleSheet_h___ +#define nsIHTMLStyleSheet_h___ + +#include "nslayout.h" +#include "nsIStyleSheet.h" + +// IID for the nsIHTMLStyleSheet interface {bddbd1b0-c5cc-11d1-8031-006008159b5a} +#define NS_IHTML_STYLE_SHEET_IID \ +{0xbddbd1b0, 0xc5cc, 0x11d1, {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}} + +class nsIHTMLStyleSheet : public nsIStyleSheet { +public: + // no methods for now +}; + +extern NS_HTML nsresult + NS_NewHTMLStyleSheet(nsIHTMLStyleSheet** aInstancePtrResult, nsIURL* aURL); + +#endif /* nsIHTMLStyleSheet_h___ */ diff --git a/mozilla/layout/html/table/Makefile b/mozilla/layout/html/table/Makefile new file mode 100644 index 00000000000..b0ff7c06fd4 --- /dev/null +++ b/mozilla/layout/html/table/Makefile @@ -0,0 +1,24 @@ +#!gmake +# +# 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. + +DEPTH = ../../.. + +DIRS = src + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/layout/html/table/makefile.win b/mozilla/layout/html/table/makefile.win new file mode 100644 index 00000000000..d4bfe31b9cf --- /dev/null +++ b/mozilla/layout/html/table/makefile.win @@ -0,0 +1,23 @@ +#!nmake +# +# 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. + +DEPTH=..\..\.. +IGNORE_MANIFEST=1 + +DIRS=src + +include <$(DEPTH)\config\rules.mak> diff --git a/mozilla/layout/html/table/src/Makefile b/mozilla/layout/html/table/src/Makefile new file mode 100644 index 00000000000..7ae36b25652 --- /dev/null +++ b/mozilla/layout/html/table/src/Makefile @@ -0,0 +1,54 @@ +#!gmake +# +# 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. + +DEPTH=../../../.. + +include $(DEPTH)/config/config.mk + +LIBRARY_NAME = raptorhtmltable_s + +# Note the sophisticated alphabetical ordering :-| +CPPSRCS = \ + nsCellLayoutData.cpp \ + nsCellMap.cpp \ + nsColLayoutData.cpp \ + nsTableCaption.cpp \ + nsTableCaptionFrame.cpp \ + nsTableCell.cpp \ + nsTableCellFrame.cpp \ + nsTableCol.cpp \ + nsTableColGroup.cpp \ + nsTableColGroupFrame.cpp \ + nsTableContent.cpp \ + nsTableFrame.cpp \ + nsTableOuterFrame.cpp \ + nsTablePart.cpp \ + nsTableRow.cpp \ + nsTableRowFrame.cpp \ + nsTableRowGroup.cpp \ + nsTableRowGroupFrame.cpp \ + $(NULL) + +MODULE = raptor + +REQUIRES = xpcom raptor dom + +INCLUDES += -I../../base/src -I../../style/src + +LCFLAGS += -D_IMPL_NS_HTML + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/layout/html/table/src/makefile.win b/mozilla/layout/html/table/src/makefile.win new file mode 100644 index 00000000000..35fedf9dc72 --- /dev/null +++ b/mozilla/layout/html/table/src/makefile.win @@ -0,0 +1,58 @@ +#!nmake +# +# 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. + +DEPTH=..\..\..\.. +IGNORE_MANIFEST=1 + +LIBRARY_NAME=raptorhtmltable_s +MODULE=raptor +REQUIRES=xpcom raptor + +DEFINES=-D_IMPL_NS_HTML -I..\..\base\src -I..\..\style\src \ + -I$(PUBLIC)\dom + +CPPSRCS=nsCellLayoutData.cpp nsCellMap.cpp nsColLayoutData.cpp \ + nsTableCaption.cpp nsTableCaptionFrame.cpp nsTableCell.cpp \ + nsTableCellFrame.cpp nsTableCol.cpp nsTableColGroup.cpp \ + nsTableColGroupFrame.cpp nsTableContent.cpp nsTableFrame.cpp \ + nsTableOuterFrame.cpp nsTablePart.cpp nsTableRow.cpp \ + nsTableRowFrame.cpp nsTableRowGroup.cpp nsTableRowGroupFrame.cpp + +CPP_OBJS=.\$(OBJDIR)\nsCellLayoutData.obj .\$(OBJDIR)\nsCellMap.obj \ + .\$(OBJDIR)\nsColLayoutData.obj .\$(OBJDIR)\nsTableCaption.obj \ + .\$(OBJDIR)\nsTableCaptionFrame.obj .\$(OBJDIR)\nsTableCell.obj \ + .\$(OBJDIR)\nsTableCellFrame.obj .\$(OBJDIR)\nsTableCol.obj \ + .\$(OBJDIR)\nsTableColGroup.obj .\$(OBJDIR)\nsTableColGroupFrame.obj \ + .\$(OBJDIR)\nsTableContent.obj .\$(OBJDIR)\nsTableFrame.obj \ + .\$(OBJDIR)\nsTableOuterFrame.obj .\$(OBJDIR)\nsTablePart.obj \ + .\$(OBJDIR)\nsTableRow.obj .\$(OBJDIR)\nsTableRowFrame.obj \ + .\$(OBJDIR)\nsTableRowGroup.obj .\$(OBJDIR)\nsTableRowGroupFrame.obj + +LINCS=-I$(XPDIST)\public\xpcom -I$(XPDIST)\public\raptor + +LCFLAGS = \ + $(LCFLAGS) \ + $(DEFINES) \ + $(NULL) + +include <$(DEPTH)\config\rules.mak> + +libs:: $(LIBRARY) + $(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib + +clobber:: + rm -f $(DIST)\lib\$(LIBRARY_NAME).lib diff --git a/mozilla/layout/html/table/src/nsCellLayoutData.cpp b/mozilla/layout/html/table/src/nsCellLayoutData.cpp new file mode 100644 index 00000000000..973c9a42f01 --- /dev/null +++ b/mozilla/layout/html/table/src/nsCellLayoutData.cpp @@ -0,0 +1,597 @@ +/* -*- 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 "nsCRT.h" +#include "nsCellLayoutData.h" +#include "nsSize.h" +#include "nsIFrame.h" +#include "nsTableCell.h" +#include "nsIStyleContext.h" + +#include /* XXX */ // for printf + + +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); + +nsCellLayoutData::nsCellLayoutData(nsTableCellFrame *aCellFrame, + nsReflowMetrics * aDesiredSize, nsSize * aMaxElementSize) + +{ + // IMPORTANT: Always intialize instance variables to null + mCellFrame = nsnull; + mMargin.top = mMargin.bottom = mMargin.left = mMargin.right = 0; + + for (PRInt32 i = 0; i < 4; i++) + mBorderStyle[i] = nsnull; + + // IMPORTANT: call setters: this + // guarentees addrefs/releases are called if needed - gpk + SetCellFrame(aCellFrame); + SetDesiredSize(aDesiredSize); + SetMaxElementSize(aMaxElementSize); +} + +// don't delete mCellFrame, I didn't allocate it +nsCellLayoutData::~nsCellLayoutData() +{ + mCellFrame = nsnull; + mColLayoutData = nsnull; +} + +nsTableCellFrame * nsCellLayoutData::GetCellFrame() +{ return mCellFrame; } + +void nsCellLayoutData::SetCellFrame(nsTableCellFrame * aCellFrame) +{ mCellFrame = aCellFrame; } + +nsReflowMetrics * nsCellLayoutData::GetDesiredSize() +{ return &mDesiredSize; } + +void nsCellLayoutData::SetDesiredSize(nsReflowMetrics * aDesiredSize) +{ + if (nsnull!=aDesiredSize) + mDesiredSize = *aDesiredSize; +} + +nsSize * nsCellLayoutData::GetMaxElementSize() +{ return &mMaxElementSize; } + +void nsCellLayoutData::SetMaxElementSize(nsSize * aMaxElementSize) +{ + if (nsnull!=aMaxElementSize) + mMaxElementSize = *aMaxElementSize; +} + +/** + * Get the style molecue for this object (determined, by + * asking for the frame + * + **/ +nsStyleMolecule* nsCellLayoutData::GetStyleMolecule() +{ + if (mCellFrame != nsnull) + return (nsStyleMolecule*)mCellFrame->GetStyleData(kStyleMoleculeSID); + return nsnull; +} + + + + + +/** + * Given a list of nsCellLayoutData and a index, get the style molecule for + * that element in the list + * + **/ +nsStyleMolecule* nsCellLayoutData::GetStyleMoleculeAt(nsVoidArray* aList, PRInt32 aIndex) +{ + nsStyleMolecule* result = nsnull; + + if (aList != nsnull) + { + nsCellLayoutData* data = (nsCellLayoutData*)aList->ElementAt(aIndex); + if (data != nsnull) + result = data->GetStyleMolecule(); + } + return result; +} + +/** + * Given a style molecule and an edge, find the margin + * + **/ +nscoord nsCellLayoutData::GetMargin(nsStyleMolecule* aStyle,PRUint8 aEdge) +{ + nscoord result = 0; + + if (aStyle) + { + switch (aEdge) + { + + case NS_SIDE_TOP: + result = aStyle->margin.top; + break; + + case NS_SIDE_RIGHT: + result = aStyle->margin.right; + break; + + + case NS_SIDE_BOTTOM: + result = aStyle->margin.bottom; + break; + + case NS_SIDE_LEFT: + result = aStyle->margin.left; + break; + + } + } + return result; +} + + +/** + * Given a style molecule and an edge, find the border width + * + **/ +nscoord nsCellLayoutData::GetBorderWidth(nsStyleMolecule* aStyle,PRUint8 aEdge) +{ + nscoord result = 0; + + if (aStyle) + { + switch (aEdge) + { + case NS_SIDE_TOP: + result = aStyle->border.top; + break; + + case NS_SIDE_RIGHT: + result = aStyle->border.right; + break; + + + case NS_SIDE_BOTTOM: + result = aStyle->border.bottom; + break; + + case NS_SIDE_LEFT: + result = aStyle->border.left; + break; + + } + } + return result; +} + + +/** + * Given a style molecule and an edge, find the padding + * + **/ +nscoord nsCellLayoutData::GetPadding(nsStyleMolecule* aStyle,PRUint8 aEdge) +{ + nscoord result = 0; + + if (aStyle) + { + switch (aEdge) + { + case NS_SIDE_TOP: + result = aStyle->padding.top; + break; + + case NS_SIDE_RIGHT: + result = aStyle->padding.right; + break; + + case NS_SIDE_BOTTOM: + result = aStyle->padding.bottom; + break; + + case NS_SIDE_LEFT: + result = aStyle->padding.left; + break; + + } + } + return result; +} + + + +/** + * Given an Edge, find the opposing edge (top<-->bottom, left<-->right) + * + **/ +PRUint8 nsCellLayoutData::GetOpposingEdge(PRUint8 aEdge) +{ + PRUint8 result; + + switch (aEdge) + { + case NS_SIDE_LEFT: + result = NS_SIDE_RIGHT; + break; + + case NS_SIDE_RIGHT: + result = NS_SIDE_LEFT; + break; + + case NS_SIDE_TOP: + result = NS_SIDE_BOTTOM; + break; + + case NS_SIDE_BOTTOM: + result = NS_SIDE_TOP; + break; + + default: + result = NS_SIDE_TOP; + } + return result; +} + + +/* +* +* Determine border style for two cells. +* + 1.If the adjacent elements are of the same type, the wider of the two borders is used. + "Wider" takes into account the border-style of 'none', so a "1px solid" border + will take precedence over a "20px none" border. + + 2.If there are two or more with the same width, but different style, + then the one with a style near the start of the following list will be drawn: + + 'blank', 'double', 'solid', 'dashed', 'dotted', 'ridge', 'groove', 'none' + + 3.If the borders are of the same width, the border on the element occurring first is used. + + First is defined as aStyle for this method. + + NOTE: This assumes left-to-right, top-to-bottom bias. -- gpk + +* +*/ + + +nsStyleMolecule* nsCellLayoutData::CompareCellBorders(nsStyleMolecule* aStyle1, + PRUint8 aEdge1, + nsStyleMolecule* aStyle2, + PRUint8 aEdge2) +{ + PRInt32 width1 = GetBorderWidth(aStyle1,aEdge1); + PRInt32 width2 = GetBorderWidth(aStyle2,aEdge2); + + nsStyleMolecule* result = nsnull; + + if (width1 > width2) + result = aStyle1; + else if (width1 < width2) + result = aStyle2; + else // width1 == width2 + { + if (aStyle1->borderStyle[aEdge1] >= aStyle2->borderStyle[aEdge2]) + result = aStyle1; + else + result = aStyle2; + } + return result; +} + + +/** + * Given a List of cell layout data, compare the edges to see which has the + * border with the highest precidence. + * + **/ + +nsStyleMolecule* nsCellLayoutData::FindHighestPrecedentBorder(nsVoidArray* aList, + PRUint8 aEdge) +{ + nsStyleMolecule* result = nsnull; + PRInt32 index = 0; + PRInt32 count = 0; + + + NS_ASSERTION(aList,"a List must be valid"); + count = aList->Count(); + if (count) + { + nsStyleMolecule* style = nsnull; + nsStyleMolecule* style2 = nsnull; + + style = GetStyleMoleculeAt(aList,index++); + while (index < count) + { + style2 = GetStyleMoleculeAt(aList,index++); + if (GetMargin(style2,aEdge) == 0) + style = CompareCellBorders(style,aEdge, style2,aEdge); + } + if (style && GetMargin(style,aEdge) != 0) + result = style; + } + return result; +} + + + + +nsStyleMolecule* nsCellLayoutData::FindInnerBorder( nsStyleMolecule* aStyle, + nsVoidArray* aList, + PRUint8 aEdge) +{ + nsStyleMolecule* result = nsnull; + nsStyleMolecule* altStyle = nsnull; + PRUint8 opposite = GetOpposingEdge(aEdge); + + if (GetMargin(aStyle,aEdge) == 0) + { + + nsStyleMolecule* altStyle = FindHighestPrecedentBorder(aList,opposite); + if (altStyle != nsnull) + result = CompareCellBorders(aStyle,aEdge,altStyle,opposite); + else + result = aStyle; + } + + return result; +} + + +/* +* +* FindRelevantBorder recursively searches up the frame hierarchy for the border +* style that is applicable to the cell. If at any point the frame has a margin +* or the parent frame has padding, then the outer frame for this object takes +* presendence over the inner frame. + +1.Borders on 'table' elements take precedence over borders on any other table elements. +2.Borders on 'row-groups' take precedence over borders on 'rows', + and likewise borders on 'column-groups' take precedence over borders on 'columns'. +3.Borders on any other type of table element take precedence over 'table-cell' elements. + +* +* NOTE: This method assumes that the table cell potentially shares a border. +* It should not be called for internal cells +* +* NOTE: COLUMNS AND COLGROUPS NEED TO BE FIGURED INTO THE ALGORITHM -- GPK!!! +* +* +*/ +nsStyleMolecule* nsCellLayoutData::FindOuterBorder( nsTableFrame* aTableFrame, + nsIFrame* aFrame, + nsStyleMolecule* aStyle, + PRUint8 aEdge) +{ + // By default, return the passed in style + nsStyleMolecule* style = aStyle; + nsIFrame* frame = aFrame; + PRBool done = PR_FALSE; + + // The table frame is the outer most frame we test against + while (done == PR_FALSE) + { + done = PR_TRUE; // where done unless the frame's margin is zero + // and the parent's padding is zero + + nscoord margin = GetMargin(style,aEdge); + + // if the margin for this style is zero then check to see if the paddding + // for the parent frame is also zero + if (margin == 0) + { + nsIFrame* parentFrame = aFrame->GetGeometricParent(); + nsStyleMolecule* parentStyle = (nsStyleMolecule*)aFrame->GetStyleData(kStyleMoleculeSID); + + // if the padding for the parent style is zero just + // recursively call this routine + PRInt32 padding = GetPadding(parentStyle,aEdge); + if (parentStyle && padding == 0) + { + style = parentStyle; + frame = parentFrame; + // If this frame represents the table frame then + // the table style is used + done = PRBool(frame != (nsIFrame*)aTableFrame); + continue; + } + + } + } + return style; +} + + + +/* + + Border Resolution + 1.Borders on 'table' elements take precedence over borders on any other table elements. + 2.Borders on 'row-groups' take precedence over borders on 'rows', and likewise borders on 'column-groups' take + precedence over borders on 'columns'. + 3.Borders on any other type of table element take precedence over 'table-cell' elements. + 4.If the adjacent elements are of the same type, the wider of the two borders is used. "Wider" takes into account + the border-style of 'none', so a "1px solid" border will take precedence over a "20px none" border. + 5.If the borders are of the same width, the border on the element occurring first is used. + + + How to compare + 1.Those of the one or two cells that have an edge here. + Less than two can occur at the edge of the table, but also + at the edges of "holes" (unoccupied grid cells). + 2.Those of the columns that have an edge here. + 3.Those of the column groups that have an edge here. + 4.Those of the rows that have an edge here. + 5.Those of the row groups that have an edge here. + 6.Those of the table, if this is the edge of the table. + +* +* @param aIsFirst -- TRUE if this is the first cell in the row +* @param aIsLast -- TRUE if this is the last cell in the row +* @param aIsTop -- TRUE if this is the top cell in the column +* @param aIsBottom -- TRUE if this is the last cell in the column +*/ + +nsStyleMolecule* nsCellLayoutData::FindBorderStyle(nsTableFrame* aTableFrame, + nsStyleMolecule* aCellStyle, + nsVoidArray* aList, + PRUint8 aEdge) +{ + nsStyleMolecule* style = nsnull; + + if (aList && aList->Count() == 0) + style = FindOuterBorder(aTableFrame,mCellFrame,aCellStyle,aEdge); + else + style = FindInnerBorder(aCellStyle,aList, aEdge); + + if (!style) + style = aCellStyle; + + return style; +} + + +void nsCellLayoutData::CalculateBorders(nsTableFrame* aTableFrame, + nsStyleMolecule* aCellStyle, + nsVoidArray* aBoundaryCells[4]) +{ + + for (PRInt32 edge = 0; edge < 4; edge++) + mBorderStyle[edge] = FindBorderStyle(aTableFrame,aCellStyle,aBoundaryCells[edge],edge); +} + + +/** + * Given a List of cell layout data, compare the edges to see which has the + * border with the highest precidence. + * + **/ + +nscoord nsCellLayoutData::FindLargestMargin(nsVoidArray* aList,PRUint8 aEdge) +{ + nscoord result = 0; + PRInt32 index = 0; + PRInt32 count = 0; + + + NS_ASSERTION(aList,"a List must be valid"); + count = aList->Count(); + if (count) + { + nsStyleMolecule* style = nsnull; + + nscoord value = 0; + while (index < count) + { + style = GetStyleMoleculeAt(aList,index++); + value = GetMargin(style,aEdge); + if (value > result) + result = value; + } + } + return result; +} + + + + +void nsCellLayoutData::CalculateMargins(nsTableFrame* aTableFrame, + nsStyleMolecule* aCellStyle, + nsVoidArray* aBoundaryCells[4]) +{ + // By default the margin is just the margin found in the + // table cells style + mMargin = aCellStyle->margin; + + // Left and Top Margins are collapsed with their neightbors + // Right and Bottom Margins are simple left as they are + nscoord value; + + // The left and top sides margins are the difference between + // their inherint value and the value of the margin of the + // object to the left or right of them. + + value = FindLargestMargin(aBoundaryCells[NS_SIDE_LEFT],NS_SIDE_RIGHT); + if (value > mMargin.left) + mMargin.left = 0; + else + mMargin.left -= value; + + value = FindLargestMargin(aBoundaryCells[NS_SIDE_TOP],NS_SIDE_BOTTOM); + if (value > mMargin.top) + mMargin.top = 0; + else + mMargin.top -= value; +} + + +void nsCellLayoutData::RecalcLayoutData(nsTableFrame* aTableFrame, + nsVoidArray* aBoundaryCells[4]) + +{ + nsStyleMolecule* cellStyle = (nsStyleMolecule*)mCellFrame->GetStyleData(kStyleMoleculeSID); + + CalculateBorders(aTableFrame,cellStyle,aBoundaryCells); + CalculateMargins(aTableFrame,cellStyle,aBoundaryCells); +} + + +void nsCellLayoutData::List(FILE* out, PRInt32 aIndent) const +{ + PRInt32 indent; + + nsTableCell* cell = (nsTableCell*)mCellFrame->GetContent(); + if (cell != nsnull) + { + for (indent = aIndent; --indent >= 0; ) fputs(" ", out); + fprintf(out,"RowSpan = %d ColSpan = %d \n",cell->GetRowSpan(),cell->GetColSpan()); + + for (indent = aIndent; --indent >= 0; ) fputs(" ", out); + fprintf(out,"Margin -- Top: %d Left: %d Bottom: %d Right: %d \n", + NS_TWIPS_TO_POINTS_INT(mMargin.top), + NS_TWIPS_TO_POINTS_INT(mMargin.left), + NS_TWIPS_TO_POINTS_INT(mMargin.bottom), + NS_TWIPS_TO_POINTS_INT(mMargin.right)); + + + for (indent = aIndent; --indent >= 0; ) fputs(" ", out); + + nscoord top,left,bottom,right; + + top = (mBorderStyle[NS_SIDE_TOP] ? mBorderStyle[NS_SIDE_TOP]->border.top : 0); + left = (mBorderStyle[NS_SIDE_LEFT] ? mBorderStyle[NS_SIDE_LEFT]->border.left : 0); + bottom = (mBorderStyle[NS_SIDE_BOTTOM] ? mBorderStyle[NS_SIDE_BOTTOM]->border.bottom : 0); + right = (mBorderStyle[NS_SIDE_RIGHT] ? mBorderStyle[NS_SIDE_RIGHT]->border.right : 0); + + + fprintf(out,"Border -- Top: %d Left: %d Bottom: %d Right: %d \n", + NS_TWIPS_TO_POINTS_INT(top), + NS_TWIPS_TO_POINTS_INT(left), + NS_TWIPS_TO_POINTS_INT(bottom), + NS_TWIPS_TO_POINTS_INT(right)); + + + + cell->List(out,aIndent); + NS_RELEASE(cell); + } +} + diff --git a/mozilla/layout/html/table/src/nsCellLayoutData.h b/mozilla/layout/html/table/src/nsCellLayoutData.h new file mode 100644 index 00000000000..dbd37a593c2 --- /dev/null +++ b/mozilla/layout/html/table/src/nsCellLayoutData.h @@ -0,0 +1,131 @@ +/* -*- 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. + */ +#ifndef nsCellLayoutData_h__ +#define nsCellLayoutData_h__ + +#include "nscore.h" +#include "nsSize.h" +#include "nsIFrame.h" +#include "nsTableCellFrame.h" + +class nsColLayoutData; +class nsTableFrame; + + + +/** Simple data class that represents in-process reflow information about a cell. + * TODO: All methods will be inline. + */ +class nsCellLayoutData +{ +public: + + nsCellLayoutData(nsTableCellFrame *aCellFrame, + nsReflowMetrics * aDesiredSize, nsSize * aMaxElementSize); + + virtual ~nsCellLayoutData(); + + nsTableCellFrame * GetCellFrame(); + + void SetCellFrame(nsTableCellFrame * aCellFrame); + + nsReflowMetrics * GetDesiredSize(); + + void SetDesiredSize(nsReflowMetrics * aDesiredSize); + + nsSize * GetMaxElementSize(); + + void SetMaxElementSize(nsSize * aMaxElementSize); + + void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + + nsStyleMolecule* GetStyleMolecule(); + +private: + + // All these methods are support methods for RecalcLayoutData + nsStyleMolecule* GetStyleMoleculeAt(nsVoidArray* aList, PRInt32 aIndex); + + nscoord GetMargin(nsStyleMolecule* aStyle,PRUint8 aEdge); + + nscoord GetBorderWidth(nsStyleMolecule* aStyle,PRUint8 aEdge); + + nscoord GetPadding(nsStyleMolecule* aStyle,PRUint8 aEdge); + + PRUint8 GetOpposingEdge(PRUint8 aEdge); + + nsStyleMolecule* CompareCellBorders(nsStyleMolecule* aStyle1, + PRUint8 aEdge1, + nsStyleMolecule* aStyle2, + PRUint8 aEdge2); + + + nsStyleMolecule* FindHighestPrecedentBorder(nsVoidArray* aList, + PRUint8 aEdge); + + + + nsStyleMolecule* FindInnerBorder( nsStyleMolecule* aStyle, + nsVoidArray* aList, + PRUint8 aEdge); + + nsStyleMolecule* FindOuterBorder( nsTableFrame* aTableFrame, + nsIFrame* aFrame, + nsStyleMolecule* aStyle, + PRUint8 aEdge); + + nsStyleMolecule* FindBorderStyle(nsTableFrame* aTableFrame, + nsStyleMolecule* aCellStyle, + nsVoidArray* aCellList, + PRUint8 aEdge); + + void CalculateBorders(nsTableFrame* aTableFrame, + nsStyleMolecule* aCellStyle, + nsVoidArray* aBoundaryCells[4]); + + nscoord FindLargestMargin(nsVoidArray* aList,PRUint8 aEdge); + + + void CalculateMargins(nsTableFrame* aTableFrame, + nsStyleMolecule* aCellStyle, + nsVoidArray* aBoundaryCells[4]); + +public: + void RecalcLayoutData(nsTableFrame* aTableFrame, + nsVoidArray* aBoundaryCells[4]); + + +private: +#if 0 // these come on line when we do character-based cell content alignment + /** the kinds of width information stored */ + enum {WIDTH_NORMAL=0, WIDTH_LEFT_ALIGNED=1, WIDTH_RIGHT_ALIGNED=2}; + + /** the width information for a cell */ + PRInt32 mWidth[3]; +#endif + + nsColLayoutData *mColLayoutData; + nsTableCellFrame *mCellFrame; + nsReflowMetrics mDesiredSize; + nsSize mMaxElementSize; + + nsMargin mMargin; + nsStyleMolecule* mBorderStyle[4]; +}; + +#endif diff --git a/mozilla/layout/html/table/src/nsCellMap.cpp b/mozilla/layout/html/table/src/nsCellMap.cpp new file mode 100644 index 00000000000..25fd456989d --- /dev/null +++ b/mozilla/layout/html/table/src/nsCellMap.cpp @@ -0,0 +1,136 @@ +/* -*- 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 "nsCRT.h" +#include "nsCellMap.h" +#include "nsTablePart.h" +#include /* XXX */ // for printf + +#ifdef NS_DEBUG +static PRBool gsDebug1 = PR_FALSE; +#else +static const PRBool gsDebug1 = PR_FALSE; +#endif + +static PRInt32 gBytesPerPointer = sizeof(PRInt32); + +nsCellMap::nsCellMap(int aRows, int aColumns) + : mRowCount(aRows), + mColCount(aColumns) +{ + mCells = nsnull; + Reset(aRows, aColumns); +} + +nsCellMap::~nsCellMap() +{ + for (int i=0;iCount(); + for (PRInt32 i = 0; i < count; i++) + { + nsCellLayoutData *data = (nsCellLayoutData *)(mCells->ElementAt(i)); + delete data; + } + delete mCells; + } + mCells = 0; +} + +nsTableCol * nsColLayoutData::GetCol() +{ + NS_IF_ADDREF(mCol); + return mCol; +}; + +void nsColLayoutData::SetCol(nsTableCol * aCol) +{ + if (aCol != mCol) + { + NS_IF_ADDREF(aCol); + NS_IF_RELEASE(mCol); + mCol = aCol; + } +}; + + +nsCellLayoutData* nsColLayoutData::ElementAt(PRInt32 aIndex) const +{ + return (nsCellLayoutData*)mCells->ElementAt(aIndex); +} + + +PRBool nsColLayoutData::AppendElement(nsCellLayoutData* aCellLayoutData) +{ + return mCells->AppendElement((void*)aCellLayoutData); +} + +PRBool nsColLayoutData::ReplaceElementAt(nsCellLayoutData* aCellLayoutData, PRInt32 aIndex) +{ + return mCells->ReplaceElementAt((void*)aCellLayoutData,aIndex); +} + +nsVoidArray * nsColLayoutData::GetCells() +{ return mCells; } + +PRInt32 nsColLayoutData::Count() const +{ return mCells->Count(); } + + +PRInt32 nsColLayoutData::IndexOf(nsCellLayoutData* aCellLayoutData) const +{ + return mCells->IndexOf((void*)aCellLayoutData); +} + +PRInt32 nsColLayoutData::IndexOf(nsTableCell* aTableCell) const +{ + PRInt32 count = this->Count(); + PRInt32 result = -1; + if (aTableCell != nsnull) + { + for (PRInt32 index = 0; index < count; index++) + { + nsCellLayoutData* cellData = ElementAt(index); + if (cellData != nsnull) + { + nsTableCellFrame* frame = cellData->GetCellFrame(); + if (frame != nsnull) + { + nsTableCell* cell = (nsTableCell*)frame->GetContent(); + if (cell == aTableCell) + { + result = index; + NS_RELEASE(cell); + break; + } + NS_IF_RELEASE(cell); + } + } + } + } + return result; +} + + +nsCellLayoutData* nsColLayoutData::GetNext(nsCellLayoutData* aCellLayoutData) const +{ + PRInt32 index = IndexOf(aCellLayoutData); + if (index != -1) + return ElementAt(index+1); + return (nsCellLayoutData*)nsnull; +} + +nsCellLayoutData* nsColLayoutData::GetPrevious(nsCellLayoutData* aCellLayoutData) const +{ + PRInt32 index = IndexOf(aCellLayoutData); + if (index != -1) + return ElementAt(index-1); + return (nsCellLayoutData*)nsnull; +} + + +void nsColLayoutData::List(FILE* out, PRInt32 aIndent) const +{ + if (nsnull!=mCells) + { + PRInt32 count = mCells->Count(); + for (PRInt32 i = 0; i < count; i++) + { + for (PRInt32 indent = aIndent; --indent >= 0; ) fputs(" ", out); + fprintf(out,"Cell Data [%d] \n",i); + + nsCellLayoutData *data = (nsCellLayoutData *)(mCells->ElementAt(i)); + data->List(out,aIndent+1); + } + } +} + + diff --git a/mozilla/layout/html/table/src/nsColLayoutData.h b/mozilla/layout/html/table/src/nsColLayoutData.h new file mode 100644 index 00000000000..edfe9491ba4 --- /dev/null +++ b/mozilla/layout/html/table/src/nsColLayoutData.h @@ -0,0 +1,74 @@ +/* -*- 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. + */ +#ifndef nsColLayoutData_h__ +#define nsColLayoutData_h__ + +#include "nscore.h" +#include "nsSize.h" +#include "nsIFrame.h" +#include "nsTableCol.h" + +class nsVoidArray; +class nsCellLayoutData; +class nsTableFrame; + + +/** Simple data class that represents in-process reflow information about a column. + */ +class nsColLayoutData +{ +public: + nsColLayoutData(nsTableCol *aCol); + + // NOT VIRTUAL BECAUSE THIS CLASS SHOULD **NEVER** BE SUBCLASSED + ~nsColLayoutData(); + + nsTableCol * GetCol(); + + void SetCol(nsTableCol * aCol); + + nsVoidArray * GetCells(); + + PRInt32 Count() const; + + nsCellLayoutData* ElementAt(PRInt32 aIndex) const; + + PRInt32 IndexOf(nsCellLayoutData* aCellLayoutData) const; + PRInt32 IndexOf(nsTableCell* aTableCell) const; + + nsCellLayoutData* GetNext(nsCellLayoutData* aCellLayoutData) const; + + nsCellLayoutData* GetPrevious(nsCellLayoutData* aCellLayoutData) const; + + + + PRBool AppendElement(nsCellLayoutData* aCellLayoutData); + + PRBool ReplaceElementAt(nsCellLayoutData* aCellLayoutData, PRInt32 aIndex); + + void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + + +private: + + nsTableCol *mCol; + nsVoidArray *mCells; + +}; + +#endif diff --git a/mozilla/layout/html/table/src/nsITableContent.h b/mozilla/layout/html/table/src/nsITableContent.h new file mode 100644 index 00000000000..6cc52375418 --- /dev/null +++ b/mozilla/layout/html/table/src/nsITableContent.h @@ -0,0 +1,84 @@ +/* -*- 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. + */ +#ifndef nsITableContent_h__ +#define nsITableContent_h__ + +#include "nsISupports.h" +#include "nscore.h" + +class nsTablePart; + +#define NS_ITABLECONTENT_IID \ + { /* 34a59b40-a71d-11d1-8f2f-006008159b0c */ \ + 0x34a59b40, 0xa71d, 0x11d1, \ + {0x8f, 0x2f, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x0c} } + +/** + * nsITableContent is a concrete subclass for all content nodes contained directly within a table. + * + * @author sclark + * @version $Revision: 1.1 $ + * @see + */ +class nsITableContent : public nsISupports +{ + +public: + + /** constants representing well-known table content types */ + static const int kTableRowGroupType; + static const int kTableRowType; + static const int kTableColGroupType; + static const int kTableColType; + static const int kTableCaptionType; + static const int kTableCellType; + +protected: + nsITableContent (); + +public: + /** + * returns the TablePart that contains this content node. + */ + virtual nsTablePart *GetTable ()=0; + + /** + * + */ + virtual void SetTable (nsTablePart *aTable)=0; + + /** + * + */ + virtual PRBool IsImplicit () const =0; + + /** + * Don't want to put out implicit tags when saving. + */ + virtual PRBool SkipSelfForSaving ()=0; + + /** + * return the type of TableContent this object represents. + * implementing interfaces for all these objects seemed like overkill. + */ + virtual int GetType()=0; + +}; + +#endif + diff --git a/mozilla/layout/html/table/src/nsTableCaption.cpp b/mozilla/layout/html/table/src/nsTableCaption.cpp new file mode 100644 index 00000000000..1660193b378 --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableCaption.cpp @@ -0,0 +1,105 @@ +/* -*- 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 "nsTableCaption.h" +#include "nsTableCaptionFrame.h" +#include "nsBodyFrame.h" +#include "nsTablePart.h" +#include "nsHTMLParts.h" +#include "nsHTMLContainer.h" +#include "nsContainerFrame.h" +#include "nsReflowCommand.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsIPresContext.h" +#include "nsHTMLIIDs.h" + + +#ifdef NS_DEBUG +static PRBool gsDebug = PR_FALSE; +static PRBool gsNoisyRefs = PR_FALSE; +#else +static const PRBool gsDebug = PR_FALSE; +static const PRBool gsNoisyRefs = PR_FALSE; +#endif + + +nsTableCaption::nsTableCaption(nsIAtom* aTag) + : nsTableContent(aTag) +{ + mImplicit = PR_FALSE; +} + +nsTableCaption::nsTableCaption(PRBool aImplicit) + : nsTableContent(NS_NewAtom(nsTablePart::kCaptionTagString)) +{ + mImplicit = aImplicit; +} + +nsTableCaption::~nsTableCaption() +{ +} + +nsrefcnt nsTableCaption::AddRef(void) +{ + if (gsNoisyRefs) printf("Add Ref: %x, nsTableCaption cnt = %d \n",this, mRefCnt+1); + return ++mRefCnt; +} + +nsrefcnt nsTableCaption::Release(void) +{ + if (gsNoisyRefs==PR_TRUE) printf("Release: %x, nsTableCaption cnt = %d \n",this, mRefCnt-1); + if (--mRefCnt == 0) { + if (gsNoisyRefs==PR_TRUE) printf("Delete: %x, nsTableCaption \n",this); + delete this; + return 0; + } + return mRefCnt; +} + +int nsTableCaption::GetType() +{ + return nsITableContent::kTableCaptionType; +} + +nsIFrame* nsTableCaption::CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + NS_PRECONDITION(nsnull!=aPresContext, "bad arg"); + nsIFrame* rv; + nsresult status = nsTableCaptionFrame::NewFrame(&rv, this, aIndexInParent, + aParentFrame); + NS_ASSERTION(nsnull!=rv, "bad arg"); + return rv; +} + + +nsresult +NS_NewTableCaptionPart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "nsnull ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIHTMLContent* body = new nsTableCaption(aTag); + if (nsnull == body) { + return NS_ERROR_OUT_OF_MEMORY; + } + return body->QueryInterface(kIHTMLContentIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/layout/html/table/src/nsTableCaption.h b/mozilla/layout/html/table/src/nsTableCaption.h new file mode 100644 index 00000000000..ff86362b4aa --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableCaption.h @@ -0,0 +1,55 @@ +/* -*- 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. + */ +#ifndef nsTableCaption_h__ +#define nsTableCaption_h__ + +#include "nscore.h" +#include "nsTableContent.h" + +/** + * nsTableCaption + * data structure to maintain information about a single table caption + * + * @author sclark + */ +class nsTableCaption : public nsTableContent +{ +public: + + nsTableCaption (PRBool aImplicit); + + nsTableCaption (nsIAtom* aTag); + + virtual ~nsTableCaption(); + + // For debugging purposes only + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + + virtual int GetType(); + + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + +}; + +#endif + + + diff --git a/mozilla/layout/html/table/src/nsTableCaptionFrame.cpp b/mozilla/layout/html/table/src/nsTableCaptionFrame.cpp new file mode 100644 index 00000000000..5f02504df76 --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableCaptionFrame.cpp @@ -0,0 +1,348 @@ +/* -*- 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 "nsTableCaptionFrame.h" +#include "nsBodyFrame.h" +#include "nsReflowCommand.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsIPresContext.h" +#include "nsIRenderingContext.h" +#include "nsCSSRendering.h" +#include "nsIContent.h" +#include "nsIContentDelegate.h" +#include "nsCSSLayout.h" + +#ifdef NS_DEBUG +static PRBool gsDebug = PR_FALSE; +#else +static const PRBool gsDebug = PR_FALSE; +#endif + +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); +static NS_DEFINE_IID(kStyleColorSID, NS_STYLECOLOR_SID); + +/** + */ +nsTableCaptionFrame::nsTableCaptionFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsContainerFrame(aContent, aIndexInParent, aParentFrame), + mMinWidth(0), + mMaxWidth(0) +{ +} + +nsTableCaptionFrame::~nsTableCaptionFrame() +{ +} + +/** return the min legal width for this caption + * minWidth is the minWidth of it's content plus any insets + */ +PRInt32 nsTableCaptionFrame::GetMinWidth() +{ + return mMinWidth; +} + +/** return the max legal width for this caption + * maxWidth is the maxWidth of it's content when given an infinite space + * plus any insets + */ +PRInt32 nsTableCaptionFrame::GetMaxWidth() +{ + return mMaxWidth; +} + + +void nsTableCaptionFrame::CreatePsuedoFrame(nsIPresContext* aPresContext) +{ + // Do we have a prev-in-flow? + if (nsnull == mPrevInFlow) { + // No, create a column pseudo frame + nsBodyFrame::NewFrame(&mFirstChild, mContent, mIndexInParent, this); + mChildCount = 1; + + // Resolve style and set the style context + nsIStyleContext* styleContext = + aPresContext->ResolveStyleContextFor(mContent, this); // styleContext: ADDREF++ + mFirstChild->SetStyleContext(styleContext); + NS_RELEASE(styleContext); // styleContext: ADDREF-- + } else { + nsTableCaptionFrame* prevFrame = (nsTableCaptionFrame *)mPrevInFlow; + + nsIFrame* prevPseudoFrame = prevFrame->mFirstChild; + NS_ASSERTION(prevFrame->ChildIsPseudoFrame(prevPseudoFrame), "bad previous pseudo-frame"); + + // Create a continuing column + mFirstChild = prevPseudoFrame->CreateContinuingFrame(aPresContext, this); + mChildCount = 1; + } +} + +void nsTableCaptionFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + nsStyleMolecule* myMol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + nsStyleColor* myColor = + (nsStyleColor*)mStyleContext->GetData(kStyleColorSID); + NS_ASSERTION(nsnull!=myColor, "bad style color"); + NS_ASSERTION(nsnull!=myMol, "bad style molecule"); + if (nsnull==myMol) return; + + nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this, + aDirtyRect, mRect, *myColor); + nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, + aDirtyRect, mRect, *myMol, 0); + + + // for debug... + if (nsIFrame::GetShowFrameBorders()) { + aRenderingContext.SetColor(NS_RGB(0,128,128)); + aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height); + } + + PaintChildren(aPresContext, aRenderingContext, aDirtyRect); +} + +/** +* +* Align the frame's child frame within the caption +* +**/ + +void nsTableCaptionFrame::VerticallyAlignChild(nsIPresContext* aPresContext) + { + + nsStyleMolecule* mol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + NS_ASSERTION(nsnull!=mol, "bad style molecule"); + nscoord topInset=0, bottomInset=0; + PRInt32 verticalAlign = NS_STYLE_VERTICAL_ALIGN_MIDDLE; + + if (nsnull!=mol) + { + topInset = mol->borderPadding.top; + bottomInset =mol->borderPadding.bottom; + verticalAlign = mol->verticalAlign; + } + nscoord height = GetHeight(); + + nsRect kidRect; + mFirstChild->GetRect(kidRect); + nscoord childHeight = kidRect.height; + + + // Vertically align the child + nscoord kidYTop = 0; + switch (verticalAlign) + { + case NS_STYLE_VERTICAL_ALIGN_BASELINE: + // Align the child's baseline at the max baseline + //kidYTop = aMaxAscent - kidAscent; + break; + + case NS_STYLE_VERTICAL_ALIGN_TOP: + // Align the top of the child frame with the top of the box, + // minus the top padding + kidYTop = topInset; + break; + + case NS_STYLE_VERTICAL_ALIGN_BOTTOM: + kidYTop = height - childHeight - bottomInset; + break; + + default: + case NS_STYLE_VERTICAL_ALIGN_MIDDLE: + kidYTop = height/2 - childHeight/2; + } + mFirstChild->MoveTo(kidRect.x, kidYTop); +} + +/** + */ +nsIFrame::ReflowStatus +nsTableCaptionFrame::ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ + NS_PRECONDITION(nsnull!=aPresContext, "bad arg"); + +#ifdef NS_DEBUG + PreReflowCheck(); +#endif + + ReflowStatus result = frComplete; + if (gsDebug==PR_TRUE) + printf("nsTableCaptionFrame::ResizeReflow: maxSize=%d,%d\n", + aMaxSize.width, aMaxSize.height); + + mFirstContentOffset = mLastContentOffset = 0; + + nsSize availSize(aMaxSize); + nsSize maxElementSize; + nsSize *pMaxElementSize = aMaxElementSize; + if (NS_UNCONSTRAINEDSIZE==aMaxSize.width) + pMaxElementSize = &maxElementSize; + nsReflowMetrics kidSize; + nscoord x = 0; + // SEC: what about ascent and decent??? + + // Compute the insets (sum of border and padding) + nsStyleMolecule* myMol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + NS_ASSERTION(nsnull!=myMol, "bad style molecule"); + nscoord topInset=0,rightInset=0, bottomInset=0, leftInset=0; + if (nsnull!=myMol) + { + topInset = myMol->borderPadding.top; + rightInset = myMol->borderPadding.right; + bottomInset =myMol->borderPadding.bottom; + leftInset = myMol->borderPadding.left; + } + + // reduce available space by insets + if (NS_UNCONSTRAINEDSIZE!=availSize.width) + availSize.width -= leftInset+rightInset; + if (NS_UNCONSTRAINEDSIZE!=availSize.height) + availSize.height -= topInset+bottomInset; + //was: availSize.SizeBy(-(leftInset+rightInset), -(topInset+bottomInset)); + + mLastContentIsComplete = PR_TRUE; + + // get frame, creating one if needed + if (nsnull==mFirstChild) + { + CreatePsuedoFrame(aPresContext); + } + + // Try to reflow the child into the available space. It might not + // fit or might need continuing. + nsSize maxKidElementSize; + if (gsDebug==PR_TRUE) + printf(" nsTableCaptionFrame::ResizeReflow calling ReflowChild with availSize=%d,%d\n", + availSize.width, availSize.height); + result = ReflowChild(mFirstChild, aPresContext, kidSize, availSize, pMaxElementSize); + + if (gsDebug==PR_TRUE) + { + if (nsnull!=pMaxElementSize) + printf(" nsTableCaptionFrame::ResizeReflow: child returned desiredSize=%d,%d,\ + and maxElementSize=%d,%d\n", + kidSize.width, kidSize.height, + pMaxElementSize->width, pMaxElementSize->height); + else + printf(" nsTableCaptionFrame::ResizeReflow: child returned desiredSize=%d,%d,\ + and maxElementSize=nsnull\n", + kidSize.width, kidSize.height); + } + + SetFirstContentOffset(mFirstChild); + if (gsDebug) printf("CAPTION: set first content offset to %d\n", GetFirstContentOffset()); //@@@ + SetLastContentOffset(mFirstChild); + if (gsDebug) printf("CAPTION: set last content offset to %d\n", GetLastContentOffset()); //@@@ + + // Place the child since some of it's content fit in us. + mFirstChild->SetRect(nsRect(leftInset + x, topInset, + kidSize.width, kidSize.height)); + + + if (frNotComplete == result) { + // If the child didn't finish layout then it means that it used + // up all of our available space (or needs us to split). + mLastContentIsComplete = PR_FALSE; + } + + // Return our size and our result + PRInt32 kidWidth = kidSize.width; + if (NS_UNCONSTRAINEDSIZE!=kidSize.width) + kidWidth += leftInset + rightInset; + PRInt32 kidHeight = kidSize.height; + + // height can be set w/o being restricted by aMaxSize.height + if (NS_UNCONSTRAINEDSIZE!=kidSize.height) + kidHeight += topInset + bottomInset; + aDesiredSize.width = kidWidth; + aDesiredSize.height = kidHeight; + aDesiredSize.ascent = topInset; + aDesiredSize.descent = bottomInset; + + if (nsnull!=aMaxElementSize) + *aMaxElementSize = *pMaxElementSize; + + // in the UNCONSTRAINED case, cache the min and max widths + if (NS_UNCONSTRAINEDSIZE==aMaxSize.width) + { + mMaxWidth = kidWidth; + mMinWidth = pMaxElementSize->width; + if (PR_TRUE==gsDebug) + printf(" caption frame setting min/max to %d,%d\n", mMinWidth, mMaxWidth); + } + + if (gsDebug==PR_TRUE) + printf(" nsTableCaptionFrame::ResizeReflow returning aDesiredSize=%d,%d\n", + aDesiredSize.width, aDesiredSize.height); + +#ifdef NS_DEBUG + PostReflowCheck(result); +#endif + + return result; +} + +nsIFrame::ReflowStatus +nsTableCaptionFrame::IncrementalReflow( nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand) +{ + if (gsDebug == PR_TRUE) printf("nsTableCaptionFrame::IncrementalReflow\n"); + // total hack for now, just some hard-coded values + ResizeReflow(aPresContext, aDesiredSize, aMaxSize, nsnull); + + return frComplete; +} + +nsIFrame* nsTableCaptionFrame::CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent) +{ + nsTableCaptionFrame* cf = new nsTableCaptionFrame(mContent, mIndexInParent, aParent); + PrepareContinuingFrame(aPresContext, aParent, cf); + return cf; +} + +/* ----- static methods ----- */ + +nsresult nsTableCaptionFrame::NewFrame( nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIFrame* it = new nsTableCaptionFrame(aContent, aIndexInParent, aParent); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aInstancePtrResult = it; + return NS_OK; +} diff --git a/mozilla/layout/html/table/src/nsTableCaptionFrame.h b/mozilla/layout/html/table/src/nsTableCaptionFrame.h new file mode 100644 index 00000000000..760d76dc730 --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableCaptionFrame.h @@ -0,0 +1,97 @@ +/* -*- 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. + */ +#ifndef nsTableCaptionFrame_h__ +#define nsTableCaptionFrame_h__ + +#include "nscore.h" +#include "nsContainerFrame.h" +#include "nsTableCaption.h" + +struct nsStyleMolecule; + +/** + * nsTableCaptionFrame + * data structure to maintain information about a single table caption geometry + * + * @author sclark + */ +class nsTableCaptionFrame : public nsContainerFrame +{ +public: + static nsresult NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + virtual void Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + virtual ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + + virtual ReflowStatus IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand); + + /** + * @see nsContainerFrame + */ + virtual nsIFrame* CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent); + + virtual void VerticallyAlignChild(nsIPresContext* aPresContext); + + /** return the min legal width for this caption + * minWidth is the minWidth of it's content plus any insets + */ + virtual PRInt32 GetMinWidth(); + + /** return the max legal width for this caption + * maxWidth is the maxWidth of it's content when given an infinite space + * plus any insets + */ + virtual PRInt32 GetMaxWidth(); + + virtual ~nsTableCaptionFrame(); + +protected: + + /** protected constructor. + * @see NewFrame + */ + nsTableCaptionFrame( nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + /** Create a psuedo-frame for this caption. Handles continuing frames as needed. + */ + virtual void CreatePsuedoFrame(nsIPresContext* aPresContext); + +private: + + PRInt32 mMinWidth; + PRInt32 mMaxWidth; + +}; + + +#endif diff --git a/mozilla/layout/html/table/src/nsTableCell.cpp b/mozilla/layout/html/table/src/nsTableCell.cpp new file mode 100644 index 00000000000..7785e28e7a1 --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableCell.cpp @@ -0,0 +1,222 @@ +/* -*- 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 "nsTableCell.h" +#include "nsTableColGroup.h" +#include "nsTableRow.h" +#include "nsTablePart.h" +#include "nsTableCellFrame.h" +#include "nsHTMLParts.h" +#include "nsHTMLContainer.h" +#include "nsReflowCommand.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsIPresContext.h" +#include "nsIRenderingContext.h" +#include "nsHTMLIIDs.h" +#include "nsHTMLAtoms.h" + +static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + +#ifdef NS_DEBUG +static PRBool gsDebug = PR_FALSE; +static PRBool gsNoisyRefs = PR_FALSE; +#else +static const PRBool gsDebug = PR_FALSE; +static const PRBool gsNoisyRefs = PR_FALSE; +#endif + +nsTableCell::nsTableCell(nsIAtom* aTag) + : nsTableContent(aTag), + mRow(0), + mRowSpan(1), + mColSpan(1), + mColIndex(0) +{ + mImplicit = PR_FALSE; +} + +nsTableCell::nsTableCell(PRBool aImplicit) + : nsTableContent(NS_NewAtom(nsTablePart::kDataCellTagString)), + mRow(0), + mRowSpan(1), + mColSpan(1), + mColIndex(0) +{ + mImplicit = aImplicit; +} + +nsTableCell::nsTableCell (nsIAtom* aTag, int aRowSpan, int aColSpan) + : nsTableContent(aTag), + mRow(0), + mRowSpan(aRowSpan), + mColSpan(aColSpan), + mColIndex(0) +{ + NS_ASSERTION(0ResetCellMap (); +} + +nsresult +NS_NewTableCellPart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "nsnull ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIHTMLContent* body = new nsTableCell(aTag); + if (nsnull == body) { + return NS_ERROR_OUT_OF_MEMORY; + } + return body->QueryInterface(kIHTMLContentIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/layout/html/table/src/nsTableCell.h b/mozilla/layout/html/table/src/nsTableCell.h new file mode 100644 index 00000000000..c8d40ae2701 --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableCell.h @@ -0,0 +1,93 @@ +/* -*- 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. + */ +#ifndef nsTableCell_h__ +#define nsTableCell_h__ + +#include "nscore.h" +#include "nsTableContent.h" +#include "nsTableRow.h" + +/** + * nsTableCell + * datastructure to maintain information about a single table column + * + * @author sclark + */ +class nsTableCell : public nsTableContent +{ + +private: + + nsTableRow * mRow; + int mRowSpan, mColSpan; + int mColIndex; + +public: + + nsTableCell (PRBool aImplicit); + + nsTableCell (nsIAtom* aTag); + + nsTableCell (nsIAtom* aTag, int aRowSpan, int aColSpan); + + virtual ~nsTableCell(); + + // For debugging purposes only + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + + + + virtual int GetType(); + + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void SetAttribute(nsIAtom* aAttribute, const nsString& aValue); + + virtual void MapAttributesInto(nsIStyleContext* aContext, + nsIPresContext* aPresContext); + + virtual int GetRowSpan (); + + virtual void SetRowSpan (int aRowSpan); + + virtual int GetColSpan (); + + virtual void SetColSpan (int aColSpan); + + virtual nsTableRow * GetRow (); + + /** + * Since mRow is the parent of the table cell, + * reference counting should not be done on + * this variable when setting the row. + * see /ns/raptor/doc/MemoryModel.html + **/ + virtual void SetRow (nsTableRow * aRow); + + virtual int GetColIndex (); + + virtual void SetColIndex (int aColIndex); + + virtual void ResetCellMap (); + +}; + +#endif diff --git a/mozilla/layout/html/table/src/nsTableCellFrame.cpp b/mozilla/layout/html/table/src/nsTableCellFrame.cpp new file mode 100644 index 00000000000..fc41977b5ee --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableCellFrame.cpp @@ -0,0 +1,334 @@ +/* -*- 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 "nsTableCellFrame.h" +#include "nsBodyFrame.h" +#include "nsReflowCommand.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsIPresContext.h" +#include "nsIRenderingContext.h" +#include "nsCSSRendering.h" +#include "nsIContent.h" +#include "nsIContentDelegate.h" +#include "nsCSSLayout.h" + +#ifdef NS_DEBUG +static PRBool gsDebug = PR_FALSE; +//#define NOISY +//#define NOISY_FLOW +#else +static const PRBool gsDebug = PR_FALSE; +#endif + +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); +static NS_DEFINE_IID(kStyleColorSID, NS_STYLECOLOR_SID); + +/** + */ +nsTableCellFrame::nsTableCellFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsContainerFrame(aContent, aIndexInParent, aParentFrame) +{ +} + +nsTableCellFrame::~nsTableCellFrame() +{ +} + +void nsTableCellFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + nsStyleColor* myColor = + (nsStyleColor*)mStyleContext->GetData(kStyleColorSID); + nsStyleMolecule* myMol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + NS_ASSERTION(nsnull!=myColor, "bad style color"); + NS_ASSERTION(nsnull!=myMol, "bad style molecule"); + + nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this, + aDirtyRect, mRect, *myColor); + nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, + aDirtyRect, mRect, *myMol, 0); + + + // for debug... + if (nsIFrame::GetShowFrameBorders()) { + aRenderingContext.SetColor(NS_RGB(0,128,128)); + aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height); + } + + PaintChildren(aPresContext, aRenderingContext, aDirtyRect); +} + +/** +* +* Align the cell's child frame within the cell +* +**/ + +void nsTableCellFrame::VerticallyAlignChild(nsIPresContext* aPresContext) + { + + nsStyleMolecule* mol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + NS_ASSERTION(nsnull!=mol, "bad style molecule"); + nscoord topInset=0, bottomInset=0; + PRInt32 verticalAlign = NS_STYLE_VERTICAL_ALIGN_MIDDLE; + + if (nsnull!=mol) + { + topInset = mol->borderPadding.top; + bottomInset =mol->borderPadding.bottom; + verticalAlign = mol->verticalAlign; + } + nscoord height = GetHeight(); + + nsRect kidRect; + mFirstChild->GetRect(kidRect); + nscoord childHeight = kidRect.height; + + + // Vertically align the child + nscoord kidYTop = 0; + switch (verticalAlign) + { + case NS_STYLE_VERTICAL_ALIGN_BASELINE: + // Align the child's baseline at the max baseline + //kidYTop = aMaxAscent - kidAscent; + break; + + case NS_STYLE_VERTICAL_ALIGN_TOP: + // Align the top of the child frame with the top of the box, + // minus the top padding + kidYTop = topInset; + break; + + case NS_STYLE_VERTICAL_ALIGN_BOTTOM: + kidYTop = height - childHeight - bottomInset; + break; + + default: + case NS_STYLE_VERTICAL_ALIGN_MIDDLE: + kidYTop = height/2 - childHeight/2; + } + mFirstChild->MoveTo(kidRect.x, kidYTop); +} + +/** helper method to get the row span of this frame's content (which must be a cell) */ +PRInt32 nsTableCellFrame::GetRowSpan() +{ + PRInt32 result = 0; + nsTableCell *cellContent = (nsTableCell *)GetContent(); // cellContent: REFCNT++ + if (nsnull!=cellContent) + { + result = cellContent->GetRowSpan(); + NS_RELEASE(cellContent); // cellContent: REFCNT-- + } + return result; +} + +void nsTableCellFrame::CreatePsuedoFrame(nsIPresContext* aPresContext) +{ + // Do we have a prev-in-flow? + if (nsnull == mPrevInFlow) { + // No, create a column pseudo frame + nsBodyFrame::NewFrame(&mFirstChild, mContent, mIndexInParent, this); + mChildCount = 1; + + // Resolve style and set the style context + nsIStyleContext* styleContext = + aPresContext->ResolveStyleContextFor(mContent, this); // styleContext: ADDREF++ + mFirstChild->SetStyleContext(styleContext); + NS_RELEASE(styleContext); // styleContext: ADDREF-- + } else { + nsTableCellFrame* prevFrame = (nsTableCellFrame *)mPrevInFlow; + + nsIFrame* prevPseudoFrame = prevFrame->mFirstChild; + NS_ASSERTION(prevFrame->ChildIsPseudoFrame(prevPseudoFrame), "bad previous pseudo-frame"); + + // Create a continuing column + mFirstChild = prevPseudoFrame->CreateContinuingFrame(aPresContext, this); + mChildCount = 1; + } +} + +/** + */ +nsIFrame::ReflowStatus +nsTableCellFrame::ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ + NS_PRECONDITION(nsnull!=aPresContext, "bad arg"); + +#ifdef NS_DEBUG + //PreReflowCheck(); +#endif + + ReflowStatus result = frComplete; + if (gsDebug==PR_TRUE) + printf("nsTableCellFrame::ResizeReflow: maxSize=%d,%d\n", + aMaxSize.width, aMaxSize.height); + + mFirstContentOffset = mLastContentOffset = 0; + + nsSize availSize(aMaxSize); + nsSize maxElementSize; + nsSize *pMaxElementSize = aMaxElementSize; + if (NS_UNCONSTRAINEDSIZE==aMaxSize.width) + pMaxElementSize = &maxElementSize; + nsReflowMetrics kidSize; + nscoord x = 0; + // SEC: what about ascent and decent??? + + // Compute the insets (sum of border and padding) + nsStyleMolecule* myMol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + NS_ASSERTION(nsnull!=myMol, "bad style molecule"); + nscoord topInset=0,rightInset=0, bottomInset=0, leftInset=0; + if (nsnull!=myMol) + { + topInset = myMol->borderPadding.top; + rightInset = myMol->borderPadding.right; + bottomInset =myMol->borderPadding.bottom; + leftInset = myMol->borderPadding.left; + } + + // reduce available space by insets + if (NS_UNCONSTRAINEDSIZE!=availSize.width) + availSize.width -= leftInset+rightInset; + if (NS_UNCONSTRAINEDSIZE!=availSize.height) + availSize.height -= topInset+bottomInset; + //was: availSize.SizeBy(-(leftInset+rightInset), -(topInset+bottomInset)); + + mLastContentIsComplete = PR_TRUE; + + // get frame, creating one if needed + if (nsnull==mFirstChild) + { + CreatePsuedoFrame(aPresContext); + } + + // Try to reflow the child into the available space. It might not + // fit or might need continuing. + nsSize maxKidElementSize; + if (gsDebug==PR_TRUE) + printf(" nsTableCellFrame::ResizeReflow calling ReflowChild with availSize=%d,%d\n", + availSize.width, availSize.height); + result = ReflowChild(mFirstChild, aPresContext, kidSize, availSize, pMaxElementSize); + + if (gsDebug==PR_TRUE) + { + if (nsnull!=pMaxElementSize) + printf(" nsTableCellFrame::ResizeReflow: child returned desiredSize=%d,%d,\ + and maxElementSize=%d,%d\n", + kidSize.width, kidSize.height, + pMaxElementSize->width, pMaxElementSize->height); + else + printf(" nsTableCellFrame::ResizeReflow: child returned desiredSize=%d,%d,\ + and maxElementSize=nsnull\n", + kidSize.width, kidSize.height); + } + + SetFirstContentOffset(mFirstChild); + if (gsDebug) printf("CELL: set first content offset to %d\n", GetFirstContentOffset()); //@@@ + SetLastContentOffset(mFirstChild); + if (gsDebug) printf("CELL: set last content offset to %d\n", GetLastContentOffset()); //@@@ + + // Place the child since some of it's content fit in us. + mFirstChild->SetRect(nsRect(leftInset + x, topInset, + kidSize.width, kidSize.height)); + + + if (frNotComplete == result) { + // If the child didn't finish layout then it means that it used + // up all of our available space (or needs us to split). + mLastContentIsComplete = PR_FALSE; + } + + // Return our size and our result + PRInt32 kidWidth = kidSize.width; + if (NS_UNCONSTRAINEDSIZE!=kidSize.width) //&& NS_UNCONSTRAINEDSIZE!=aMaxSize.width) + kidWidth += leftInset + rightInset; + PRInt32 kidHeight = kidSize.height; + + // height can be set w/o being restricted by aMaxSize.height + if (NS_UNCONSTRAINEDSIZE!=kidSize.height) + kidHeight += topInset + bottomInset; + aDesiredSize.width = kidWidth; + aDesiredSize.height = kidHeight; + aDesiredSize.ascent = topInset; + aDesiredSize.descent = bottomInset; + + if (nsnull!=aMaxElementSize) + *aMaxElementSize = *pMaxElementSize; + + if (gsDebug==PR_TRUE) + printf(" nsTableCellFrame::ResizeReflow returning aDesiredSize=%d,%d\n", + aDesiredSize.width, aDesiredSize.height); + +#ifdef NS_DEBUG + //PostReflowCheck(result); +#endif + + return result; +} + +nsIFrame::ReflowStatus +nsTableCellFrame::IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand) +{ + if (gsDebug == PR_TRUE) printf("nsTableCellFrame::IncrementalReflow\n"); + // total hack for now, just some hard-coded values + ResizeReflow(aPresContext, aDesiredSize, aMaxSize, nsnull); + + return frComplete; +} + +nsIFrame* nsTableCellFrame::CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent) +{ + nsTableCellFrame* cf = new nsTableCellFrame(mContent, mIndexInParent, aParent); + PrepareContinuingFrame(aPresContext, aParent, cf); + return cf; +} + + +/* ----- static methods ----- */ + +nsresult nsTableCellFrame::NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIFrame* it = new nsTableCellFrame(aContent, aIndexInParent, aParent); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aInstancePtrResult = it; + return NS_OK; +} diff --git a/mozilla/layout/html/table/src/nsTableCellFrame.h b/mozilla/layout/html/table/src/nsTableCellFrame.h new file mode 100644 index 00000000000..c71974a1894 --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableCellFrame.h @@ -0,0 +1,84 @@ +/* -*- 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. + */ +#ifndef nsTableCellFrame_h__ +#define nsTableCellFrame_h__ + +#include "nscore.h" +#include "nsContainerFrame.h" +#include "nsTableCell.h" + +struct nsStyleMolecule; + +/** + * nsTableCellFrame + * data structure to maintain information about a single table cell's frame + * + * @author sclark + */ +class nsTableCellFrame : public nsContainerFrame +{ +public: + static nsresult NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + virtual void Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + + ReflowStatus IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand); + + /** + * @see nsContainerFrame + */ + virtual nsIFrame* CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent); + + void VerticallyAlignChild(nsIPresContext* aPresContext); + + virtual PRInt32 GetRowSpan(); + + virtual ~nsTableCellFrame(); + +protected: + + /** protected constructor. + * @see NewFrame + */ + nsTableCellFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + /** Create a psuedo-frame for this caption. Handles continuing frames as needed. + */ + virtual void CreatePsuedoFrame(nsIPresContext* aPresContext); + + +}; + + +#endif diff --git a/mozilla/layout/html/table/src/nsTableCol.cpp b/mozilla/layout/html/table/src/nsTableCol.cpp new file mode 100644 index 00000000000..895a536d130 --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableCol.cpp @@ -0,0 +1,348 @@ +/* -*- 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 "nsTableCol.h" +#include "nsTableColGroup.h" +#include "nsTablePart.h" +#include "nsHTMLParts.h" +#include "nsHTMLContainer.h" +#include "nsContainerFrame.h" +#include "nsReflowCommand.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsIPresContext.h" +#include "nsHTMLIIDs.h" + +#ifdef NS_DEBUG +static PRBool gsDebug = PR_FALSE; +static PRBool gsNoisyRefs = PR_FALSE; +#else +static const PRBool gsDebug = PR_FALSE; +static const PRBool gsNoisyRefs = PR_FALSE; +#endif + +class nsTableColFrame : public nsFrame { +public: + static nsresult NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + void Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + + ReflowStatus IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand); + +protected: + + nsTableColFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + ~nsTableColFrame(); + +}; + + + +nsTableColFrame::nsTableColFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsFrame(aContent, aIndexInParent, aParentFrame) +{ +} + +nsTableColFrame::~nsTableColFrame() +{ +} + +void nsTableColFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + if (gsDebug==PR_TRUE) + printf("nsTableColFrame::Paint\n"); +} + + +nsIFrame::ReflowStatus +nsTableColFrame::ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ + NS_ASSERTION(nsnull!=aPresContext, "bad arg"); + if (gsDebug==PR_TRUE) printf("nsTableoupFrame::ResizeReflow\n"); + aDesiredSize.width=0; + aDesiredSize.height=0; + if (nsnull!=aMaxElementSize) + { + aMaxElementSize->width=0; + aMaxElementSize->height=0; + } + return nsIFrame::frComplete; +} + +nsIFrame::ReflowStatus +nsTableColFrame::IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand) +{ + NS_ASSERTION(nsnull!=aPresContext, "bad arg"); + if (gsDebug==PR_TRUE) printf("nsTableColFrame::IncrementalReflow\n"); + aDesiredSize.width=0; + aDesiredSize.height=0; + return nsIFrame::frComplete; +} + +nsresult nsTableColFrame::NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIFrame* it = new nsTableColFrame(aContent, aIndexInParent, aParent); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aInstancePtrResult = it; + return NS_OK; +} + +//---------------------- nsTableCol implementation ----------------------------------- + +nsTableCol::nsTableCol(nsIAtom* aTag) + : nsTableContent(aTag), + mColGroup(0), + mColIndex(0), + mRepeat(0) +{ +} + +nsTableCol::nsTableCol() +: nsTableContent(NS_NewAtom(nsTablePart::kColTagString)), + mColGroup(0), + mColIndex(0), + mRepeat(0) +{ +} + +nsTableCol::nsTableCol (PRBool aImplicit) + : nsTableContent(NS_NewAtom(nsTablePart::kColTagString)), + mColGroup(0), + mColIndex(0), + mRepeat(0) +{ + mImplicit = aImplicit; +} + +nsTableCol::~nsTableCol() +{ +} + +// Added for debuging purposes -- remove from final build +nsrefcnt nsTableCol::AddRef(void) +{ + if (gsNoisyRefs==PR_TRUE) printf("Add Ref: %x, nsTableCol cnt = %d \n",this, mRefCnt+1); + return ++mRefCnt; +} + +nsrefcnt nsTableCol::Release(void) +{ + if (gsNoisyRefs==PR_TRUE) printf("Release: %x, nsTableCol cnt = %d \n",this,mRefCnt-1); + if (--mRefCnt == 0) { + if (gsNoisyRefs==PR_TRUE) printf("Delete: %x, nsTableCol \n",this); + delete this; + return 0; + } + return mRefCnt; +} + +int nsTableCol::GetType() +{ + return nsITableContent::kTableColType; +} + +int nsTableCol::GetRepeat () +{ + if (0 < mRepeat) + return mRepeat; + return 1; +} + +nsTableColGroup * nsTableCol::GetColGroup () +{ + NS_IF_ADDREF(mColGroup); + return mColGroup; +} + +void nsTableCol::SetColGroup (nsTableColGroup * aColGroup) +{ + mColGroup = aColGroup; +} + +int nsTableCol::GetColumnIndex () +{ + return mColIndex; +} + +void nsTableCol::SetColumnIndex (int aColIndex) +{ + mColIndex = aColIndex; +} + +void nsTableCol::SetRepeat (int aRepeat) +{ + mRepeat = aRepeat; + ResetColumns (); +} + +void nsTableCol::ResetColumns () +{ + if (nsnull != mColGroup) + mColGroup->ResetColumns (); +} + +static const nsString kRepeatAttributeName("REPEAT"); + +PRBool nsTableCol::SetInternalAttribute (nsString * aName, nsString * aValue) +{ + /* + // Assert aName and aValue + if (aName->EqualsIgnoreCase (kRepeatAttributeName)) + { + PRInt32 value = atoi(aValue->ToCString()); + SetRepeat (aValue); + return true; + } + return super.setInternalAttribute (aName, aValue); + */ + return PR_FALSE; +} + +/** I allocated it for you, you delete it when you're done */ +// ack!!! SEC this code and HTMLContainer need to get together and decide +nsString * nsTableCol::GetInternalAttribute (nsString * aName) +{ + /* + // Assert aName + if (aName->EqualsIgnoreCase (kRepeatAttributeName)) + { + char repeatAsCharArray[10]; + sprintf(repeatAsCharArray, "%d", GetRepeat()); + nsString * result = new nsString(repeatAsCharArray); + } + return nsTableContent::GetInternalAttribute (aName); + */ + return nsnull; +} + +PRBool nsTableCol::UnsetInternalAttribute (nsString * aName) +{ + /* + if (aName->EqualsIgnoreCase (kRepeatAttributeName)) + { + fRepeat = 0; + return true; + } + return nsTableContent::UnsetInternalAttribute (aName); + */ + return PR_FALSE; +} + +int nsTableCol::GetInternalAttributeState (nsString * aName) +{ + /* + if (aName->EqualsIgnoreCase (kRepeatAttributeName)) + { + if (0 < fRepeat) + return kAttributeSet; + } + return super.getInternalAttributeState (aName); + */ + return 0; +} + +PRBool nsTableCol::IsInternalAttribute (nsString * aName) +{ + /* + if (aName->EqualsIgnoreCase (kRepeatAttributeName)) + return true; + return super.isInternalAttribute (aName); + */ + return PR_FALSE; +} + + +static nsString * kInternalAttributeNames = nsnull; + +nsString * nsTableCol::GetAllInternalAttributeNames () +{ + /* + if (null == kInternalAttributeNames) + { + nsString * [] superInternal = super.getAllInternalAttributeNames (); + + int superLen = superInternal.length; + kInternalAttributeNames = new nsString * [superLen + 1]; + System.arraycopy (superInternal, 0, kInternalAttributeNames, 0, superLen); + kInternalAttributeNames[superLen] = kRepeatAttributeName; + } + return kInternalAttributeNames; + */ + return nsnull; +} + +nsIFrame* nsTableCol::CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + nsIFrame* rv; + nsresult status = nsTableColFrame::NewFrame(&rv, this, aIndexInParent, + aParentFrame); + return rv; +} + +/* ---------- Global Functions ---------- */ + +nsresult +NS_NewTableColPart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIHTMLContent* body = new nsTableCol(aTag); + if (nsnull == body) { + return NS_ERROR_OUT_OF_MEMORY; + } + return body->QueryInterface(kIHTMLContentIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/layout/html/table/src/nsTableCol.h b/mozilla/layout/html/table/src/nsTableCol.h new file mode 100644 index 00000000000..e63a757979f --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableCol.h @@ -0,0 +1,109 @@ +/* -*- 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. + */ +#ifndef nsTableCol_h__ +#define nsTableCol_h__ + +#include "nscore.h" +#include "nsTableContent.h" +#include "nsTableColGroup.h" + +class nsTablePart; + +/** + * nsTableCol + * data structure to maintain information about a single table column + * + * @author sclark + */ +class nsTableCol : public nsTableContent +{ + + //NS_DECL_ISUPPORTS + +private: + + nsTableColGroup * mColGroup; + PRInt32 mColIndex; + PRInt32 mRepeat; + +public: + + nsTableCol (); + + nsTableCol (PRBool aImplicit); + + nsTableCol (nsIAtom* aTag); + + virtual ~nsTableCol(); + + // For debugging purposes only + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + + virtual int GetType(); + + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual int GetRepeat (); + + void SetRepeat (int aRepeat); + + virtual nsTableColGroup *GetColGroup (); + + /** + * Since mColGroup is the parent of the table column, + * reference counting should NOT be done on + * this variable when setting the row. + * see /ns/raptor/doc/MemoryModel.html + **/ + virtual void SetColGroup (nsTableColGroup * aColGroup); + + virtual int GetColumnIndex (); + + virtual void SetColumnIndex (int aColIndex); + + virtual void ResetColumns (); + + + /* ----------- nsITableContent overrides ----------- */ + +protected: + + PRBool SetInternalAttribute (nsString *aName, nsString *aValue); + + nsString *GetInternalAttribute (nsString *aName); + + PRBool UnsetInternalAttribute (nsString *aName); + + int GetInternalAttributeState (nsString *aName); + + PRBool IsInternalAttribute (nsString *aName); + + static nsString * kInternalAttributeNames; + + nsString * GetAllInternalAttributeNames (); + + +}; + +#endif + + + diff --git a/mozilla/layout/html/table/src/nsTableColGroup.cpp b/mozilla/layout/html/table/src/nsTableColGroup.cpp new file mode 100644 index 00000000000..7e795d95a2b --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableColGroup.cpp @@ -0,0 +1,356 @@ +/* -*- 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 "nsTableColGroup.h" +#include "nsTableColGroupFrame.h" +#include "nsTableCol.h" +#include "nsTablePart.h" +#include "nsContainerFrame.h" +#include "nsReflowCommand.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsIPresContext.h" +#include "nsHTMLIIDs.h" + +#ifdef NS_DEBUG +static PRBool gsDebug = PR_FALSE; +static PRBool gsNoisyRefs = PR_FALSE; +#else +static const PRBool gsDebug = PR_FALSE; +static const PRBool gsNoisyRefs = PR_FALSE; +#endif + + +nsTableColGroup::nsTableColGroup(nsIAtom* aTag, int aSpan) + : nsTableContent(aTag), + mSpan(aSpan), + mStartColIndex(0), + mColCount(0) +{ +} + +nsTableColGroup::nsTableColGroup (PRBool aImplicit) + : nsTableContent(NS_NewAtom(nsTablePart::kColGroupTagString)), + mSpan(0), + mStartColIndex(0), + mColCount(0) +{ + mImplicit = aImplicit; +} + + +nsTableColGroup::~nsTableColGroup() +{ +} + +// Added for debuging purposes -- remove from final build +nsrefcnt nsTableColGroup::AddRef(void) +{ + if (gsNoisyRefs==PR_TRUE) + printf("Add Ref: %x, nsTableColGroup cnt = %d \n",this,mRefCnt+1); + return ++mRefCnt; +} + +nsrefcnt nsTableColGroup::Release(void) +{ + if (gsNoisyRefs==PR_TRUE) + if (gsNoisyRefs==PR_TRUE) printf("Release: %x, nsTableColGroup cnt = %d \n",this,mRefCnt-1); + if (--mRefCnt == 0) { + if (gsNoisyRefs==PR_TRUE) printf("Delete: %x, nsTableColGroup \n",this); + delete this; + return 0; + } + return mRefCnt; +} + +int nsTableColGroup::GetType() +{ + return nsITableContent::kTableColGroupType; +} + +int nsTableColGroup::GetSpan () +{ + if (0 < mSpan) + return mSpan; + return 1; +} + +int nsTableColGroup::GetStartColumnIndex () +{ + return mStartColIndex; +} + +void nsTableColGroup::SetStartColumnIndex (int aIndex) +{ + if (aIndex != mStartColIndex) + mColCount = 0; // our index is beign changed, trigger reset of col indicies, don't propogate back to table + mStartColIndex = aIndex; +} + + +void nsTableColGroup::SetSpan (int aSpan) +{ + mSpan = aSpan; + if (0 < ChildCount ()) // span is only relevant if we don't have children + ResetColumns (); +} + +void nsTableColGroup::ResetColumns () +{ + mColCount = 0; + if (nsnull != mTable) + mTable->ResetColumns (); +} + +int nsTableColGroup::GetColumnCount () +{ + if (0 == mColCount) + { + int count = ChildCount (); + if (0 < count) + { + for (int index = 0; index < count; index++) + { + nsIContent * child = ChildAt (index); // child: REFCNT++ + NS_ASSERTION(nsnull!=child, "bad child"); + // is child a column? + nsTableContent *tableContent = (nsTableContent *)child; + if (tableContent->GetType() == nsITableContent::kTableColType) + { + nsTableCol * col = (nsTableCol *)tableContent; + col->SetColumnIndex (mStartColIndex + mColCount); + mColCount += col->GetRepeat (); + } + NS_RELEASE(child); // child: REFCNT-- + } + } + else + mColCount = GetSpan (); + } + return mColCount; +} + +PRBool nsTableColGroup::SetInternalAttribute (nsString *aName, nsString *aValue) +{ +// Assert aName + PRBool result = PR_FALSE; + return result; +} + +nsString * nsTableColGroup::GetInternalAttribute (nsString *aName) +{ +// Assert aName + nsString * result = nsnull; + return result; +} + +PRBool nsTableColGroup::UnsetInternalAttribute (nsString *aName) +{ +// Assert aName + PRBool result = PR_FALSE; + return result; +} + +int nsTableColGroup::GetInternalAttributeState (nsString *aName) +{ +// Assert aName + int result = 0; + return result; +} + +PRBool nsTableColGroup::IsInternalAttribute (nsString *aName) +{ +// Assert aName + PRBool result = PR_FALSE; + return result; +} + +nsString * nsTableColGroup::GetAllInternalAttributeNames () +{ +// Assert aName + nsString * result = nsnull; + return result; +} + +PRBool nsTableColGroup::AppendChild (nsIContent *aContent) +{ + NS_ASSERTION(nsnull!=aContent, "bad arg"); + + // is aContent a TableRow? + PRBool isCol = IsCol(aContent); + + if (PR_FALSE==isCol) + { + // you should go talk to my parent if you want to insert something other than a column + return PR_FALSE; + } + + PRBool result = PR_FALSE; + PRBool contentHandled = PR_FALSE; + // SEC: TODO verify that aContent is table content + nsTableContent *tableContent = (nsTableContent *)aContent; + if (PR_FALSE==tableContent->IsImplicit()) + { + /* if aContent is not implicit, + * and if we already have an implicit column for this actual column, + * then replace the implicit col with this actual col. + */ + PRInt32 childCount = ChildCount(); + for (PRInt32 colIndex=0; colIndexIsImplicit()) + { + ReplaceChildAt(aContent, colIndex); + contentHandled = PR_TRUE; + break; + } + } + } + if (PR_FALSE==contentHandled) + result = nsTableContent::AppendChild (aContent); + if (result) + { + /* Set the table pointer */ + ((nsTableContent*)aContent)->SetTable(mTable); + + ((nsTableCol *)aContent)->SetColGroup (this); + ResetColumns (); + } + return result; +} + +PRBool nsTableColGroup::InsertChildAt (nsIContent *aContent, int aIndex) +{ + NS_ASSERTION(nsnull!=aContent, "bad arg"); + + // is aContent a TableCol? + PRBool isCol = IsCol(aContent); + + // if not, ignore the request to add aContent + if (PR_FALSE==isCol) + { + // you should go talk to my parent if you want to insert something other than a column + return PR_FALSE; + } + + // if so, add the row to this group + PRBool result = nsTableContent::InsertChildAt (aContent, aIndex); + if (result) + { + ((nsTableCol *)aContent)->SetColGroup (this); + ResetColumns (); + } + return result; +} + + +PRBool nsTableColGroup::ReplaceChildAt (nsIContent * aContent, int aIndex) +{ + NS_ASSERTION(nsnull!=aContent, "bad arg"); + NS_ASSERTION((0<=aIndex && ChildCount()>aIndex), "bad arg"); + if ((nsnull==aContent) || !(0<=aIndex && ChildCount()>aIndex)) + return PR_FALSE; + + // is aContent a TableRow? + PRBool isCol = IsCol(aContent); + + // if not, ignore the request to replace the child at aIndex + if (PR_FALSE==isCol) + { + // you should go talk to my parent if you want to insert something other than a column + return PR_FALSE; + } + + nsIContent * lastChild = ChildAt (aIndex); // lastChild : REFCNT++ + NS_ASSERTION(nsnull!=lastChild, "bad child"); + PRBool result = nsTableContent::ReplaceChildAt (aContent, aIndex); + if (result) + { + ((nsTableCol *)aContent)->SetColGroup (this); + if (nsnull != lastChild) + ((nsTableCol *)lastChild)->SetColGroup (nsnull); + ResetColumns (); + } + NS_RELEASE(lastChild); // lastChild : REFCNT-- + return result; +} + +/** + * Remove a child at the given position. The method is ignored if + * the index is invalid (too small or too large). + */ +PRBool nsTableColGroup::RemoveChildAt (int aIndex) +{ + NS_ASSERTION((0<=aIndex && ChildCount()>aIndex), "bad arg"); + nsIContent * lastChild = ChildAt (aIndex); // lastChild: REFCNT++ + NS_ASSERTION(nsnull!=lastChild, "bad child"); + PRBool result = nsTableContent::RemoveChildAt (aIndex); + if (result) + { + if (nsnull != lastChild) + ((nsTableCol *)lastChild)->SetColGroup (nsnull); + ResetColumns (); + } + NS_IF_RELEASE(lastChild); // lastChild REFCNT-- + return result; +} + +/** support method to determine if the param aContent is a TableRow object */ +PRBool nsTableColGroup::IsCol(nsIContent * aContent) const +{ + NS_ASSERTION(nsnull!=aContent, "bad arg"); + PRBool result = PR_FALSE; + if (nsnull!=aContent) + { + // is aContent a col? + nsTableContent *tableContent = (nsTableContent *)aContent; + const int contentType = tableContent->GetType(); + if (contentType == nsITableContent::kTableColType) + result = PR_TRUE; + } + return result; +} + +nsIFrame* nsTableColGroup::CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + nsIFrame* rv; + nsresult status = nsTableColGroupFrame::NewFrame(&rv, this, aIndexInParent, + aParentFrame); + NS_ASSERTION(nsnull!=rv, "can't allocate a new frame"); + return rv; +} + +/* ---------- Global Functions ---------- */ + +NS_HTML nsresult +NS_NewTableColGroupPart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "nsnull ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIHTMLContent* body = new nsTableColGroup(aTag, 0); + if (nsnull == body) { + return NS_ERROR_OUT_OF_MEMORY; + } + return body->QueryInterface(kIHTMLContentIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/layout/html/table/src/nsTableColGroup.h b/mozilla/layout/html/table/src/nsTableColGroup.h new file mode 100644 index 00000000000..b42c078f180 --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableColGroup.h @@ -0,0 +1,99 @@ +/* -*- 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. + */ +#ifndef nsTableColGroup_h__ +#define nsTableColGroup_h__ + +#include "nscore.h" +#include "nsTableContent.h" + +class nsIPresContext; + +/** + * nsTableColGroup + * datastructure to maintain information about a single table column + * + * @author sclark + */ +class nsTableColGroup : public nsTableContent +{ +protected: + + int mSpan; + int mStartColIndex; + int mColCount; + +public: + + nsTableColGroup (PRBool aImplicit); + + nsTableColGroup (nsIAtom* aTag, int aSpan); + + virtual ~nsTableColGroup(); + + // For debugging purposes only + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual int GetType(); + + virtual int GetSpan (); + + virtual void SetSpan (int aSpan); + + virtual int GetStartColumnIndex (); + + virtual void SetStartColumnIndex (int aIndex); + + virtual void ResetColumns (); + + virtual int GetColumnCount (); + + virtual PRBool IsCol(nsIContent * aContent) const; + + virtual PRBool AppendChild (nsIContent * aContent); + + virtual PRBool InsertChildAt (nsIContent * aContent, int aIndex); + + virtual PRBool ReplaceChildAt (nsIContent * aContent, int aIndex); + + virtual PRBool RemoveChildAt (int aIndex); + +protected: + virtual PRBool SetInternalAttribute (nsString *aName, nsString *aValue); + + virtual nsString *GetInternalAttribute (nsString *aName); + + virtual PRBool UnsetInternalAttribute (nsString *aName); + + virtual int GetInternalAttributeState (nsString *aName); + + virtual PRBool IsInternalAttribute (nsString *aName); + + virtual nsString * GetAllInternalAttributeNames (); + + +}; + +#endif + + + diff --git a/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp b/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp new file mode 100644 index 00000000000..d2741f097ca --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp @@ -0,0 +1,94 @@ +/* -*- 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 "nsTableColGroupFrame.h" +#include "nsReflowCommand.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsIPresContext.h" + +static PRBool gsDebug = PR_FALSE; + + +nsTableColGroupFrame::nsTableColGroupFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsContainerFrame(aContent, aIndexInParent, aParentFrame) +{ +} + +nsTableColGroupFrame::~nsTableColGroupFrame() +{ +} + +void nsTableColGroupFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + if (gsDebug==PR_TRUE) printf("nsTableColGroupFrame::Paint\n"); + PaintChildren(aPresContext, aRenderingContext, aDirtyRect); +} + + +nsIFrame::ReflowStatus +nsTableColGroupFrame::ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ + NS_ASSERTION(nsnull!=aPresContext, "bad arg"); + if (gsDebug==PR_TRUE) printf("nsTableColGroupFrame::ResizeReflow\n"); + aDesiredSize.width=0; + aDesiredSize.height=0; + if (nsnull!=aMaxElementSize) + { + aMaxElementSize->width=0; + aMaxElementSize->height=0; + } + return nsIFrame::frComplete; +} + +nsIFrame::ReflowStatus +nsTableColGroupFrame::IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand) +{ + NS_ASSERTION(nsnull!=aPresContext, "bad arg"); + ReflowStatus status; + + if (gsDebug==PR_TRUE) printf("nsTableColGroupFrame::IncrementalReflow\n"); + + return status; +} + +nsresult nsTableColGroupFrame::NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIFrame* it = new nsTableColGroupFrame(aContent, aIndexInParent, aParent); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aInstancePtrResult = it; + return NS_OK; +} diff --git a/mozilla/layout/html/table/src/nsTableColGroupFrame.h b/mozilla/layout/html/table/src/nsTableColGroupFrame.h new file mode 100644 index 00000000000..260c77c8745 --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableColGroupFrame.h @@ -0,0 +1,63 @@ +/* -*- 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. + */ +#ifndef nsTableColGroupFrame_h__ +#define nsTableColGroupFrame_h__ + +#include "nscore.h" +#include "nsContainerFrame.h" + + +/** + * nsTableColGroupFrame + * data structure to maintain information about a single table cell's frame + * + * @author sclark + */ +class nsTableColGroupFrame : public nsContainerFrame +{ +public: + static nsresult NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + virtual void Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + + ReflowStatus IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand); + +protected: + + nsTableColGroupFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + ~nsTableColGroupFrame(); + +}; + +#endif diff --git a/mozilla/layout/html/table/src/nsTableContent.cpp b/mozilla/layout/html/table/src/nsTableContent.cpp new file mode 100644 index 00000000000..bd7fa3c6934 --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableContent.cpp @@ -0,0 +1,211 @@ +/* -*- 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 "nsTableContent.h" +#include "nsITableContent.h" +#include "nsString.h" + +const int nsITableContent::kTableRowGroupType=1; +const int nsITableContent::kTableRowType=2; +const int nsITableContent::kTableColGroupType=3; +const int nsITableContent::kTableColType=4; +const int nsITableContent::kTableCaptionType=5; +const int nsITableContent::kTableCellType=6; + +#ifdef NS_DEBUG +static PRBool gsDebug = PR_FALSE; +static PRBool gsNoisyRefs = PR_FALSE; +#else +static const PRBool gsDebug = PR_FALSE; +static const PRBool gsNoisyRefs = PR_FALSE; +#endif + +static NS_DEFINE_IID(kITableContentIID, NS_ITABLECONTENT_IID); + +/** + * default contstructor + */ +nsTableContent::nsTableContent (nsIAtom* aTag) + : nsHTMLContainer(aTag) +{ +} + +/** + */ +nsTableContent::nsTableContent (nsIAtom* aTag, PRBool aImplicit) + : nsHTMLContainer(aTag), + mImplicit(aImplicit) +{ +} + +nsrefcnt nsTableContent::AddRef(void) +{ + if (gsNoisyRefs==PR_TRUE) printf("Add Ref: nsTableContent cnt = %d \n",mRefCnt+1); + return ++mRefCnt; +} + +nsrefcnt nsTableContent::Release(void) +{ + if (gsNoisyRefs==PR_TRUE) printf("Release: nsTableContent cnt = %d \n",mRefCnt-1); + if (--mRefCnt == 0) { + if (gsNoisyRefs==PR_TRUE) printf("Delete: nsTableContent \n"); + delete this; + return 0; + } + return mRefCnt; +} + + +nsresult nsTableContent::QueryInterface(const nsIID& aIID, + void** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kITableContentIID)) { + *aInstancePtrResult = (void*) ((nsITableContent*)this); + AddRef(); + return NS_OK; + } + return nsHTMLContent::QueryInterface(aIID, aInstancePtrResult); +} + +/** + * Don't want to put out implicit tags when saving. + */ +PRBool nsTableContent::SkipSelfForSaving() +{ + return mImplicit; +} + +nsTablePart* nsTableContent::GetTable () +{ + NS_IF_ADDREF(mTable); + return mTable; +} + +void nsTableContent::SetTable (nsTablePart *aTable) +{ + mTable = aTable; +} + +PRBool nsTableContent::IsImplicit () const +{ + return mImplicit; +} + + +/* ----- overridable methods from nsHTMLContainer ----- */ + +/** +* +* If the content is a nsTableContent then call SetTable on +* aContent, otherwise, do nothing. +* +*/ +void nsTableContent::SetTableForTableContent(nsIContent* aContent, nsTablePart *aTable) +{ + if (aContent != nsnull) + { + nsITableContent* tableContent; + nsresult result = aContent->QueryInterface(kITableContentIID, (void**) &tableContent); + if (NS_OK == result) + { + tableContent->SetTable(aTable); + NS_IF_RELEASE(tableContent); + } + } +} + + +void nsTableContent::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out); + nsIAtom* tag = GetTag(); + if (tag != nsnull) { + nsAutoString buf; + tag->ToString(buf); + fputs(buf, out); + NS_RELEASE(tag); + } + + char *isImplicitString = ""; + if (PR_TRUE==IsImplicit()) + isImplicitString = " (I)"; + + ListAttributes(out); + + if (gsNoisyRefs == PR_TRUE) + fprintf(out, " RefCount=%d<%s\n", mRefCnt, isImplicitString); + + if (CanContainChildren()) { + PRInt32 kids = ChildCount(); + for (i = 0; i < kids; i++) { + nsIContent* kid = ChildAt(i); + kid->List(out, aIndent + 1); + NS_RELEASE(kid); + } + } + for (i = aIndent; --i >= 0; ) fputs(" ", out); + fputs(">\n", out); +} + +PRBool nsTableContent::InsertChildAt(nsIContent* aKid, PRInt32 aIndex) +{ + PRBool result = nsHTMLContainer::InsertChildAt(aKid, aIndex); + if (result == PR_TRUE) + SetTableForTableContent(aKid,mTable); + return result; +} + +PRBool nsTableContent::ReplaceChildAt(nsIContent* aKid, PRInt32 aIndex) +{ + nsIContent* child = ChildAt(aIndex); + PRBool result = nsHTMLContainer::ReplaceChildAt(aKid, aIndex); + if (result == PR_TRUE) + { + SetTableForTableContent(child,nsnull); + SetTableForTableContent(aKid,mTable); + } + NS_IF_RELEASE(child); + return result; +} + +PRBool nsTableContent::AppendChild(nsIContent* aKid) +{ + PRBool result = nsHTMLContainer::AppendChild(aKid); + if (result == PR_TRUE) + SetTableForTableContent(aKid,mTable); + return result; +} + +PRBool nsTableContent::RemoveChildAt(PRInt32 aIndex) +{ + nsTableContent* child = (nsTableContent*)ChildAt(aIndex); + PRBool result = nsHTMLContainer::RemoveChildAt(aIndex); + if (result == PR_TRUE) + SetTableForTableContent(child,nsnull); + NS_IF_RELEASE(child); + return result; +} + +/* ---------- nsITableContent implementations ----------- */ + +nsITableContent::nsITableContent () +{} + diff --git a/mozilla/layout/html/table/src/nsTableContent.h b/mozilla/layout/html/table/src/nsTableContent.h new file mode 100644 index 00000000000..4ee2fc4fd31 --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableContent.h @@ -0,0 +1,110 @@ +/* -*- 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. + */ +#ifndef nsTableContent_h__ +#define nsTableContent_h__ + +#include "nscore.h" +#include "nsITableContent.h" +#include "nsHTMLContainer.h" +#include "nsTablePart.h" +#include "nsIAtom.h" + +/** + * TableContent is a concrete subclass for all content nodes contained directly within a table. + * + * @author sclark + * @version $Revision: 1.1 $ + * @see + */ +class nsTableContent : public nsHTMLContainer, public nsITableContent +{ + +public: + + //NS_DECL_ISUPPORTS + +protected: + nsTablePart *mTable; + PRBool mImplicit; + +public: + + /** + * default constructor + */ + nsTableContent (nsIAtom* aTag); + + /** + * constructor + * @param aTag + * @param aImplicit + */ + nsTableContent (nsIAtom* aTag, PRBool aImplicit); + + /** supports implementation */ + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtrResult); + + // For debugging purposes only + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + + /** + * returns the nsTablePart that contains this content node. + */ + nsTablePart* GetTable (); + + /** + * Since mColGroup is the parent of the table column, + * reference counting should NOT be done. + * see /ns/raptor/doc/MemoryModel.html + **/ + void SetTable (nsTablePart *aTable); + + /** + * + */ + virtual PRBool IsImplicit () const; + + /** + * Don't want to put out implicit tags when saving. + */ + virtual PRBool SkipSelfForSaving (); + + virtual int GetType()=0; + + void List(FILE* out, PRInt32 aIndent) const; + + PRBool InsertChildAt(nsIContent* aKid, PRInt32 aIndex); + PRBool ReplaceChildAt(nsIContent* aKid, PRInt32 aIndex); + PRBool AppendChild(nsIContent* aKid); + PRBool RemoveChildAt(PRInt32 aIndex); + + +private: + /** + * + * If the content is a nsTableContent then call SetTable on + * aContent, otherwise, do nothing. + * + */ + void SetTableForTableContent(nsIContent* aContent, nsTablePart *aTable); + +}; + +#endif + diff --git a/mozilla/layout/html/table/src/nsTableFrame.cpp b/mozilla/layout/html/table/src/nsTableFrame.cpp new file mode 100644 index 00000000000..d3656cc91a1 --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableFrame.cpp @@ -0,0 +1,2541 @@ +/* -*- 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 "nsTableFrame.h" +#include "nsTablePart.h" +#include "nsIRenderingContext.h" +#include "nsIStyleContext.h" +#include "nsIContent.h" +#include "nsIContentDelegate.h" +#include "nsCellMap.h" +#include "nsTableContent.h" +#include "nsTableCell.h" +#include "nsTableCellFrame.h" +#include "nsTableCol.h" +#include "nsTableRowFrame.h" +#include "nsTableRowGroupFrame.h" +#include "nsColLayoutData.h" +#include "nsIPresContext.h" +#include "nsCSSRendering.h" +#include "nsStyleConsts.h" +#include "nsCellLayoutData.h" +#include "nsVoidArray.h" +#include "prinrval.h" + + +#ifdef NS_DEBUG +static PRBool gsDebug = PR_FALSE; +static PRBool gsDebugCLD = PR_FALSE; +static PRBool gsTiming = PR_FALSE; +static PRBool gsDebugMBP = PR_FALSE; +//#define NOISY +//#define NOISY_FLOW +#else +static const PRBool gsDebug = PR_FALSE; +static const PRBool gsDebugCLD = PR_FALSE; +static const PRBool gsTiming = PR_FALSE; +static const PRBool gsDebugMBP = PR_FALSE; +#endif + +#ifndef max +#define max(x, y) ((x) > (y) ? (x) : (y)) +#endif + +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); +static NS_DEFINE_IID(kStyleColorSID, NS_STYLECOLOR_SID); + +/* ----------- InnerTableReflowState ---------- */ + +struct InnerTableReflowState { + + // The body's style molecule + nsStyleMolecule* mol; + + // The body's available size (computed from the body's parent) + nsSize availSize; + + // Margin tracking information + nscoord prevMaxPosBottomMargin; + nscoord prevMaxNegBottomMargin; + + // Flags for whether the max size is unconstrained + PRBool unconstrainedWidth; + PRBool unconstrainedHeight; + + // Running y-offset + nscoord y; + + // Flag for whether we're dealing with the first interior row group + PRBool firstRowGroup; + + InnerTableReflowState(nsIPresContext* aPresContext, + const nsSize& aMaxSize, + nsStyleMolecule* aMol) + { + mol = aMol; + availSize.width = aMaxSize.width; + availSize.height = aMaxSize.height; + prevMaxPosBottomMargin = 0; + prevMaxNegBottomMargin = 0; + y=0; // border/padding/margin??? + unconstrainedWidth = PRBool(aMaxSize.width == NS_UNCONSTRAINEDSIZE); + unconstrainedHeight = PRBool(aMaxSize.height == NS_UNCONSTRAINEDSIZE); + firstRowGroup = PR_TRUE; + } + + ~InnerTableReflowState() { + } +}; + + + +/* ----------- nsTableFrame ---------- */ + + +nsTableFrame::nsTableFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsContainerFrame(aContent, aIndexInParent, aParentFrame), + mColumnLayoutData(nsnull), + mColumnWidths(nsnull), + mFirstPassValid(PR_FALSE), + mPass(kPASS_UNDEFINED), + mIsInvariantWidth(PR_FALSE) +{ +} + +/** + * Method to delete all owned objects assoicated + * with the ColumnLayoutObject instance variable + */ +void nsTableFrame::DeleteColumnLayoutData() +{ + if (nsnull!=mColumnLayoutData) + { + PRInt32 numCols = mColumnLayoutData->Count(); + for (PRInt32 i = 0; iElementAt(i)); + delete colData; + } + delete mColumnLayoutData; + mColumnLayoutData = nsnull; + } +} + +nsTableFrame::~nsTableFrame() +{ + DeleteColumnLayoutData(); + if (nsnull!=mColumnWidths) + delete [] mColumnWidths; +} + + + +/** +* Lists the column layout data which turns +* around and lists the cell layout data. +* This is for debugging purposes only. +*/ +void nsTableFrame::ListColumnLayoutData(FILE* out, PRInt32 aIndent) const +{ + // if this is a continuing frame, there will be no output + if (nsnull!=mColumnLayoutData) + { + fprintf(out,"Column Layout Data \n"); + + PRInt32 numCols = mColumnLayoutData->Count(); + for (PRInt32 i = 0; iElementAt(i)); + + for (PRInt32 indent = aIndent; --indent >= 0; ) fputs(" ", out); + fprintf(out,"Column Data [%d] \n",i); + colData->List(out,aIndent+2); + } + } +} + + +/** + * Find the CellLayoutData assocated with the TableCell +**/ +nsCellLayoutData* nsTableFrame::FindCellLayoutData(nsTableCell* aCell) +{ + if (aCell != nsnull) + { + if (nsnull!=mColumnLayoutData) + { + PRInt32 numCols = mColumnLayoutData->Count(); + for (PRInt32 i = 0; iElementAt(i)); + PRInt32 index = colLayoutData->IndexOf(aCell); + if (index != -1) + return colLayoutData->ElementAt(index); + } + } + } + return nsnull; +} + + +/** + * For the TableCell in CellData, find the CellLayoutData assocated + * and add it to the list +**/ +void nsTableFrame::AppendLayoutData(nsVoidArray* aList, nsTableCell* aTableCell) +{ + + if (aTableCell != nsnull) + { + nsCellLayoutData* layoutData = FindCellLayoutData(aTableCell); + if (layoutData != nsnull) + aList->AppendElement((void*)layoutData); + } +} + +void nsTableFrame::ResetColumnLayoutData() +{ + + nsTablePart* table = (nsTablePart*)mContent; + nsCellMap* cellMap = table->GetCellMap(); + PRInt32 colCount = cellMap->GetColCount(); + PRInt32 rowCount = cellMap->GetRowCount(); + PRInt32 row = 0; + PRInt32 col = 0; + + nsTableCell* above = nsnull; + nsTableCell* below = nsnull; + nsTableCell* left = nsnull; + nsTableCell* right = nsnull; + + + PRInt32 edge = 0; + nsVoidArray* boundaryCells[4]; + + for (edge = 0; edge < 4; edge++) + boundaryCells[edge] = new nsVoidArray(); + + + if (colCount != 0 && rowCount != 0) + { + for (row = 0; row < rowCount; row++) + { + for (col = 0; col < colCount; col++) + { + CellData* cellData = cellMap->GetCellAt(row,col); + nsTableCell* cell = cellData->mCell; + + if (!cell) + continue; + + PRInt32 colSpan = cell->GetColSpan(); + PRInt32 rowSpan = cell->GetRowSpan(); + + // clear the cells for all for edges + for (edge = 0; edge < 4; edge++) + boundaryCells[edge]->Clear(); + + + // Check to see if the cell data represents the top,left + // corner of a a table cell + + // Check to see if cell the represents a left edge cell + if (row == 0) + above = nsnull; + else + { + cellData = cellMap->GetCellAt(row-1,col); + if (cellData != nsnull) + above = cellData->mCell; + + // Does the cell data point to the same cell? + // If it is, then continue + if (above != nsnull && above == cell) + continue; + } + + // Check to see if cell the represents a top edge cell + if (col == 0) + left == nsnull; + else + { + cellData = cellMap->GetCellAt(row,col-1); + if (cellData != nsnull) + left = cellData->mCell; + + if (left != nsnull && left == cell) + continue; + } + + // If this is the top,left edged cell + // Then add the cells on the for edges to the array + + // Do the top and bottom edge + PRInt32 r,c; + PRInt32 r1,r2; + PRInt32 c1,c2; + PRInt32 last; + + + r1 = row - 1; + r2 = row + rowSpan; + c = col; + last = col + colSpan -1; + + while (c <= last) + { + if (r1 != -1) + { + // Add top edge cells + if (c != col) + { + cellData = cellMap->GetCellAt(r1,c); + if (cellData->mCell != above) + { + above = cellData->mCell; + if (above != nsnull) + AppendLayoutData(boundaryCells[NS_SIDE_TOP],above); + } + } + else if (above != nsnull) + { + AppendLayoutData(boundaryCells[NS_SIDE_TOP],above); + } + } + + if (r2 < rowCount) + { + // Add bottom edge cells + cellData = cellMap->GetCellAt(r2,c); + if (cellData->mCell != below) + { + below = cellData->mCell; + if (below != nsnull) + AppendLayoutData(boundaryCells[NS_SIDE_BOTTOM],below); + } + } + c++; + } + + // Do the left and right edge + c1 = col - 1; + c2 = col + colSpan; + r = row ; + last = row + rowSpan-1; + + while (r <= last) + { + // Add left edge cells + if (c1 != -1) + { + if (r != row) + { + cellData = cellMap->GetCellAt(r,c1); + if (cellData->mCell != left) + { + left = cellData->mCell; + if (left != nsnull) + AppendLayoutData(boundaryCells[NS_SIDE_LEFT],left); + } + } + else if (left != nsnull) + { + AppendLayoutData(boundaryCells[NS_SIDE_LEFT],left); + } + } + + if (c2 < colCount) + { + // Add right edge cells + cellData = cellMap->GetCellAt(r,c2); + if (cellData->mCell != right) + { + right = cellData->mCell; + if (right != nsnull) + AppendLayoutData(boundaryCells[NS_SIDE_RIGHT],right); + } + } + r++; + } + + nsCellLayoutData* cellLayoutData = FindCellLayoutData(cell); + cellLayoutData->RecalcLayoutData(this,boundaryCells); + } + } + } + for (edge = 0; edge < 4; edge++) + delete boundaryCells[edge]; + +} + + + + +/* SEC: TODO: adjust the rect for captions */ +void nsTableFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + // table paint code is concerned primarily with borders and bg color + nsStyleColor* myColor = + (nsStyleColor*)mStyleContext->GetData(kStyleColorSID); + nsStyleMolecule* myMol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + NS_ASSERTION(nsnull != myColor, "null style color"); + NS_ASSERTION(nsnull != myMol, "null style molecule"); + if (nsnull!=myMol) + { + nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this, + aDirtyRect, mRect, *myColor); + nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, + aDirtyRect, mRect, *myMol, 0); + } + + // for debug... + if (nsIFrame::GetShowFrameBorders()) { + aRenderingContext.SetColor(NS_RGB(0,128,0)); + aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height); + } + + PaintChildren(aPresContext, aRenderingContext, aDirtyRect); +} + +PRBool nsTableFrame::NeedsReflow(const nsSize& aMaxSize) +{ + PRBool result = PR_TRUE; + if (PR_TRUE==mIsInvariantWidth) + result = PR_FALSE; + // TODO: other cases... + return result; +} + +// SEC: TODO need to worry about continuing frames prev/next in flow for splitting across pages. +// SEC: TODO need to keep "first pass done" state, update it when ContentChanged notifications come in + +/* overview: + if mFirstPassValid is false, this is our first time through since content was last changed + set pass to 1 + do pass 1 + get min/max info for all cells in an infinite space + do column balancing + set mFirstPassValid to true + do pass 2 + if pass is 1, + set pass to 2 + use column widths to ResizeReflow cells + shrinkWrap Cells in each row to tallest, realigning contents within the cell +*/ + +/** Layout the entire inner table. + */ +nsIFrame::ReflowStatus nsTableFrame::ResizeReflow( nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ + NS_PRECONDITION(nsnull != aPresContext, "null arg"); + if (gsDebug==PR_TRUE) + { + printf("-----------------------------------------------------------------\n"); + printf("nsTableFrame::ResizeReflow: maxSize=%d,%d\n", + aMaxSize.width, aMaxSize.height); + } + +#ifdef NS_DEBUG + PreReflowCheck(); +#endif + + ReflowStatus result = frComplete; + + PRIntervalTime startTime = PR_IntervalNow(); + + if (PR_TRUE==gsDebug) + printf ("*** tableframe reflow\t\t%d\n", this); + + if (PR_TRUE==NeedsReflow(aMaxSize)) + { + nsStyleMolecule* tableStyleMol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + NS_ASSERTION(nsnull != tableStyleMol, "null style molecule"); + if (nsnull==tableStyleMol) + return frComplete; // SEC: this is an error! + + if (PR_FALSE==IsFirstPassValid()) + { // we treat the table as if we've never seen the layout data before + mPass = kPASS_FIRST; + result = ResizeReflowPass1(aPresContext, aDesiredSize, aMaxSize, aMaxElementSize, tableStyleMol); + // check result + } + mPass = kPASS_SECOND; + + // assign column widths, and assign aMaxElementSize->width + BalanceColumnWidths(aPresContext, tableStyleMol, aMaxSize, aMaxElementSize); + + // assign table width + SetTableWidth(aPresContext, tableStyleMol); + + result = ResizeReflowPass2(aPresContext, aDesiredSize, aMaxSize, aMaxElementSize, tableStyleMol, 0, 0); + + PRIntervalTime endTime = PR_IntervalNow(); + if (gsTiming) printf("Table reflow took %ld ticks for frame %d\n", endTime-startTime, this); + + mPass = kPASS_UNDEFINED; + } + else + { + // set aDesiredSize and aMaxElementSize + } + +#ifdef NS_DEBUG + PostReflowCheck(result); +#endif + + return result; +} + +/** the first of 2 reflow passes + * lay out the captions and row groups in an infinite space (NS_UNCONSTRAINEDSIZE) + * cache the results for each caption and cell. + * if successful, set mFirstPassValid=PR_TRUE, so we know we can skip this step + * next time. mFirstPassValid is set to PR_FALSE when content is changed. + * NOTE: should never get called on a continuing frame! All cached pass1 state + * is stored in the inner table first-in-flow. + */ +nsIFrame::ReflowStatus nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize, + nsStyleMolecule* aTableStyle) +{ + NS_ASSERTION(nsnull!=aPresContext, "bad pres context param"); + NS_ASSERTION(nsnull!=aTableStyle, "bad style param"); + NS_ASSERTION(nsnull==mPrevInFlow, "illegal call, cannot call pass 1 on a continuing frame."); + + if (gsDebug==PR_TRUE) printf("nsTableFrame::ResizeReflow Pass1: maxSize=%d,%d\n", + aMaxSize.width, aMaxSize.height); + if (PR_TRUE==gsDebug) printf ("*** tableframe reflow pass1\t\t%d\n", this); + ReflowStatus result = frComplete; + + mChildCount = 0; + mFirstContentOffset = mLastContentOffset = 0; + + nsIContent* c = mContent; + NS_ASSERTION(nsnull != c, "null content"); + ((nsTablePart *)c)->GetMaxColumns(); // as a side effect, does important initialization + + nsSize availSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); // availSize is the space available at any given time in the process + nsSize maxSize(0, 0); // maxSize is the size of the largest child so far in the process + nsSize kidMaxSize(0,0); + nsSize* pKidMaxSize = (nsnull != aMaxElementSize) ? &kidMaxSize : nsnull; + nsReflowMetrics kidSize; + nscoord y = 0; + nscoord maxAscent = 0; + nscoord maxDescent = 0; + PRInt32 kidIndex = 0; + PRInt32 lastIndex = c->ChildCount(); + PRInt32 contentOffset=0; + nsIFrame* prevKidFrame = nsnull;/* XXX incremental reflow! */ + + // Compute the insets (sum of border and padding) + nscoord topInset = aTableStyle->borderPadding.top; + nscoord rightInset = aTableStyle->borderPadding.right; + nscoord bottomInset =aTableStyle->borderPadding.bottom; + nscoord leftInset = aTableStyle->borderPadding.left; + + /* assumes that Table's children are in the following order: + * Captions + * ColGroups, in order + * THead, in order + * TFoot, in order + * TBody, in order + */ + for (;;) { + nsIContent* kid = c->ChildAt(kidIndex); // kid: REFCNT++ + if (nsnull == kid) { + result = frComplete; + break; + } + + mLastContentIsComplete = PR_TRUE; + + const PRInt32 contentType = ((nsTableContent *)kid)->GetType(); + if (contentType==nsITableContent::kTableRowGroupType) + { + // Resolve style + nsIStyleContext* kidStyleContext = + aPresContext->ResolveStyleContextFor(kid, this); + NS_ASSERTION(nsnull != kidStyleContext, "null style context for kid"); + nsStyleMolecule* kidStyle = + (nsStyleMolecule*)kidStyleContext->GetData(kStyleMoleculeSID); + NS_ASSERTION(nsnull != kidStyle, "null style molecule for kid"); + + // SEC: TODO: when content is appended or deleted, be sure to clear out the frame hierarchy!!!! + + nsIFrame* kidFrame = ChildAt(kidIndex); + // if this is the first time, allocate the caption frame + if (nsnull==kidFrame) + { + nsIContentDelegate* kidDel; + kidDel = kid->GetDelegate(aPresContext); + kidFrame = kidDel->CreateFrame(aPresContext, kid, contentOffset, this); + NS_RELEASE(kidDel); + kidFrame->SetStyleContext(kidStyleContext); + } + NS_RELEASE(kidStyleContext); + + nsSize maxKidElementSize; + result = ReflowChild(kidFrame, aPresContext, kidSize, availSize, pKidMaxSize); + + // Place the child since some of it's content fit in us. + if (gsDebug) { + if (nsnull != pKidMaxSize) { + printf ("reflow of row group returned desired=%d,%d, max-element=%d,%d\n", + kidSize.width, kidSize.height, pKidMaxSize->width, pKidMaxSize->height); + } else { + printf ("reflow of row group returned desired=%d,%d\n", kidSize.width, kidSize.height); + } + } + PRInt32 yCoord = y; + if (NS_UNCONSTRAINEDSIZE!=yCoord) + yCoord+= topInset; + kidFrame->SetRect(nsRect(leftInset, yCoord, + kidSize.width, kidSize.height)); + if (NS_UNCONSTRAINEDSIZE==kidSize.height) + y = NS_UNCONSTRAINEDSIZE; + else + y += kidSize.height; + if (nsnull != pKidMaxSize) { + if (pKidMaxSize->width > maxSize.width) { + maxSize.width = pKidMaxSize->width; + } + if (pKidMaxSize->height > maxSize.height) { + maxSize.height = pKidMaxSize->height; + } + } + + // Link child frame into the list of children + if (nsnull != prevKidFrame) { + prevKidFrame->SetNextSibling(kidFrame); + } else { + // Our first child (**blush**) + mFirstChild = kidFrame; + SetFirstContentOffset(kidFrame); + if (gsDebug) printf("INNER: set first content offset to %d\n", GetFirstContentOffset()); //@@@ + } + prevKidFrame = kidFrame; + mChildCount++; + + if (frNotComplete == result) { + // If the child didn't finish layout then it means that it used + // up all of our available space (or needs us to split). + mLastContentIsComplete = PR_FALSE; + NS_RELEASE(kid); // kid: REFCNT-- + break; + } + } + contentOffset++; + kidIndex++; + if (frNotComplete == result) { + // If the child didn't finish layout then it means that it used + // up all of our available space (or needs us to split). + mLastContentIsComplete = PR_FALSE; + NS_RELEASE(kid); // kid: REFCNT-- + break; + } + NS_RELEASE(kid); // kid: REFCNT-- + } + + if (nsnull != prevKidFrame) { + NS_ASSERTION(LastChild() == prevKidFrame, "unexpected last child"); + // can't use SetLastContentOffset here + mLastContentOffset = contentOffset-1; // takes into account colGroup frame we're not using + if (gsDebug) printf("INNER: set last content offset to %d\n", GetLastContentOffset()); //@@@ + } + + mFirstPassValid = PR_TRUE; + + return result; +} + +/** the second of 2 reflow passes + */ +nsIFrame::ReflowStatus nsTableFrame::ResizeReflowPass2(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize, + nsStyleMolecule* aTableStyle, + PRInt32 aMinCaptionWidth, + PRInt32 mMaxCaptionWidth) +{ + if (PR_TRUE==gsDebug) printf ("***tableframe reflow pass2\t\t%d\n", this); + if (gsDebug==PR_TRUE) + printf("nsTableFrame::ResizeReflow Pass2: maxSize=%d,%d\n", + aMaxSize.width, aMaxSize.height); + + ReflowStatus result = frComplete; + + // now that we've computed the column width information, reflow all children + nsIContent* c = mContent; + NS_ASSERTION(nsnull != c, "null kid"); + nsSize kidMaxSize(0,0); + + PRInt32 kidIndex = 0; + PRInt32 lastIndex = c->ChildCount(); + nsIFrame* prevKidFrame = nsnull;/* XXX incremental reflow! */ + +#ifdef NS_DEBUG + PreReflowCheck(); +#endif + + // Initialize out parameter + if (nsnull != aMaxElementSize) { + aMaxElementSize->width = 0; + aMaxElementSize->height = 0; + } + + PRBool reflowMappedOK = PR_TRUE; + ReflowStatus status = frComplete; + + // Check for an overflow list + MoveOverflowToChildList(); + + nsStyleMolecule* myMol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + InnerTableReflowState state(aPresContext, aMaxSize, myMol); + + // Reflow the existing frames + if (nsnull != mFirstChild) { + reflowMappedOK = ReflowMappedChildren(aPresContext, state, aMaxElementSize); + if (PR_FALSE == reflowMappedOK) { + status = frNotComplete; + } + } + + // Did we successfully relow our mapped children? + if (PR_TRUE == reflowMappedOK) { + // Any space left? + if ((nsnull != mFirstChild) && (state.availSize.height <= 0)) { + // No space left. Don't try to pull-up children or reflow unmapped + if (NextChildOffset() < mContent->ChildCount()) { + status = frNotComplete; + } + } else if (NextChildOffset() < mContent->ChildCount()) { + // Try and pull-up some children from a next-in-flow + if ((nsnull == mNextInFlow) || + PullUpChildren(aPresContext, state, aMaxElementSize)) { + // If we still have unmapped children then create some new frames + if (NextChildOffset() < mContent->ChildCount()) { + status = ReflowUnmappedChildren(aPresContext, state, aMaxElementSize); + } + } else { + // We were unable to pull-up all the existing frames from the + // next in flow + status = frNotComplete; + } + } + } + + // Return our size and our status + + if (frComplete == status) { + // Don't forget to add in the bottom margin from our last child. + // Only add it in if there's room for it. + nscoord margin = state.prevMaxPosBottomMargin - + state.prevMaxNegBottomMargin; + if (state.availSize.height >= margin) { + state.y += margin; + } + } + + // Return our desired rect + NS_ASSERTION(0width, aMaxElementSize->height); + else + printf("Reflow complete, returning aDesiredSize = %d,%d and NSNULL aMaxElementSize\n", + aDesiredSize.width, aDesiredSize.height); + } + + // SEC: assign our real width and height based on this reflow step and return + + mPass = kPASS_UNDEFINED; // we're no longer in-process + +#ifdef NS_DEBUG + PostReflowCheck(status); +#endif + + return status; + +} + +// Collapse child's top margin with previous bottom margin +nscoord nsTableFrame::GetTopMarginFor(nsIPresContext* aCX, + InnerTableReflowState& aState, + nsStyleMolecule* aKidMol) +{ + nscoord margin; + nscoord maxNegTopMargin = 0; + nscoord maxPosTopMargin = 0; + if ((margin = aKidMol->margin.top) < 0) { + maxNegTopMargin = -margin; + } else { + maxPosTopMargin = margin; + } + + nscoord maxPos = PR_MAX(aState.prevMaxPosBottomMargin, maxPosTopMargin); + nscoord maxNeg = PR_MAX(aState.prevMaxNegBottomMargin, maxNegTopMargin); + margin = maxPos - maxNeg; + + return margin; +} + +// Position and size aKidFrame and update our reflow state. The origin of +// aKidRect is relative to the upper-left origin of our frame, and includes +// any left/top margin. +void nsTableFrame::PlaceChild(nsIPresContext* aPresContext, + InnerTableReflowState& aState, + nsIFrame* aKidFrame, + const nsRect& aKidRect, + nsStyleMolecule* aKidMol, + nsSize* aMaxElementSize, + nsSize& aKidMaxElementSize) +{ + // Place and size the child + aKidFrame->SetRect(aKidRect); + + // Adjust the running y-offset + aState.y += aKidRect.height; + + // If our height is constrained then update the available height + if (PR_FALSE == aState.unconstrainedHeight) { + aState.availSize.height -= aKidRect.height; + } + + // Update the maximum element size + if (PR_TRUE==aState.firstRowGroup) + { + aState.firstRowGroup = PR_FALSE; + if (nsnull != aMaxElementSize) { + aMaxElementSize->width = aKidMaxElementSize.width; + aMaxElementSize->height = aKidMaxElementSize.height; + } + } +} + +/** + * Reflow the frames we've already created + * + * @param aPresContext presentation context to use + * @param aState current inline state + * @return true if we successfully reflowed all the mapped children and false + * otherwise, e.g. we pushed children to the next in flow + */ +PRBool nsTableFrame::ReflowMappedChildren( nsIPresContext* aPresContext, + InnerTableReflowState& aState, + nsSize* aMaxElementSize) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": reflow mapped (childCount=%d) [%d,%d,%c]\n", + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); +#ifdef NOISY_FLOW + { + nsTableFrame* flow = (nsTableFrame*) mNextInFlow; + while (flow != 0) { + printf(" %p: [%d,%d,%c]\n", + flow, flow->mFirstContentOffset, flow->mLastContentOffset, + (flow->mLastContentIsComplete ? 'T' : 'F')); + flow = (nsTableFrame*) flow->mNextInFlow; + } + } +#endif +#endif + NS_PRECONDITION(nsnull != mFirstChild, "no children"); + + PRInt32 childCount = 0; + nsIFrame* prevKidFrame = nsnull; + + // Remember our original mLastContentIsComplete so that if we end up + // having to push children, we have the correct value to hand to + // PushChildren. + PRBool lastContentIsComplete = mLastContentIsComplete; + + nsSize kidMaxElementSize; + nsSize* pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull; + PRBool result = PR_TRUE; + + for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; ) { + nsSize kidAvailSize(aState.availSize); + nsReflowMetrics desiredSize; + nsIFrame::ReflowStatus status; + + // Get top margin for this kid + nsIContent* kid = kidFrame->GetContent(); + if (((nsTableContent *)kid)->GetType() == nsITableContent::kTableRowGroupType) + { // skip children that are not row groups + nsIStyleContext* kidSC = kidFrame->GetStyleContext(aPresContext); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol); + nscoord bottomMargin = kidMol->margin.bottom; + NS_RELEASE(kid); + NS_RELEASE(kidSC); + + // Figure out the amount of available size for the child (subtract + // off the top margin we are going to apply to it) + if (PR_FALSE == aState.unconstrainedHeight) { + kidAvailSize.height -= topMargin; + } + // Subtract off for left and right margin + if (PR_FALSE == aState.unconstrainedWidth) { + kidAvailSize.width -= kidMol->margin.left + kidMol->margin.right; + } + + // Only skip the reflow if this is not our first child and we are + // out of space. + if ((kidFrame == mFirstChild) || (kidAvailSize.height > 0)) { + // Reflow the child into the available space + status = ReflowChild(kidFrame, aPresContext, desiredSize, + kidAvailSize, pKidMaxElementSize); + } + + // Did the child fit? + if ((kidFrame != mFirstChild) && + ((kidAvailSize.height <= 0) || + (desiredSize.height > kidAvailSize.height))) + { + // The child's height is too big to fit at all in our remaining space, + // and it's not our first child. + // + // Note that if the width is too big that's okay and we allow the + // child to extend horizontally outside of the reflow area + + // Since we are giving the next-in-flow our last child, we + // give it our original mLastContentIsComplete, too (in case we + // are pushing into an empty next-in-flow) + PushChildren(kidFrame, prevKidFrame, lastContentIsComplete); + + // Our mLastContentIsComplete was already set by the last kid we + // reflowed reflow's status + result = PR_FALSE; + break; + } + + // Place the child after taking into account it's margin + aState.y += topMargin; + nsRect kidRect (0, 0, desiredSize.width, desiredSize.height); + kidRect.x += kidMol->margin.left; + kidRect.y += aState.y; + PlaceChild(aPresContext, aState, kidFrame, kidRect, kidMol, aMaxElementSize, + kidMaxElementSize); + if (bottomMargin < 0) { + aState.prevMaxNegBottomMargin = -bottomMargin; + } else { + aState.prevMaxPosBottomMargin = bottomMargin; + } + childCount++; + + // Update mLastContentIsComplete now that this kid fits + mLastContentIsComplete = PRBool(status == frComplete); + + // Special handling for incomplete children + if (frNotComplete == status) { + // XXX It's good to assume that we might still have room + // even if the child didn't complete (floaters will want this) + nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); + if (nsnull == kidNextInFlow) { + // No the child isn't complete, and it doesn't have a next in flow so + // create a continuing frame. This hooks the child into the flow. + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aPresContext, this); + + // Insert the frame. We'll reflow it next pass through the loop + nsIFrame* nextSib = kidFrame->GetNextSibling(); + continuingFrame->SetNextSibling(nextSib); + kidFrame->SetNextSibling(continuingFrame); + if (nsnull == nextSib) { + // Assume that the continuation frame we just created is + // complete, for now. It will get reflowed by our + // next-in-flow (we are going to push it now) + lastContentIsComplete = PR_TRUE; + } + } + } + } + + // Get the next child + prevKidFrame = kidFrame; + kidFrame = kidFrame->GetNextSibling(); + + // XXX talk with troy about checking for available space here + } + + // Update the child count + mChildCount = childCount; + NS_POSTCONDITION(LengthOf(mFirstChild) == mChildCount, "bad child count"); + + // Set the last content offset based on the last child we mapped. + NS_ASSERTION(LastChild() == prevKidFrame, "unexpected last child"); + SetLastContentOffset(prevKidFrame); + +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": reflow mapped %sok (childCount=%d) [%d,%d,%c]\n", + (result ? "" : "NOT "), + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); +#ifdef NOISY_FLOW + { + nsTableFrame* flow = (nsTableFrame*) mNextInFlow; + while (flow != 0) { + printf(" %p: [%d,%d,%c]\n", + flow, flow->mFirstContentOffset, flow->mLastContentOffset, + (flow->mLastContentIsComplete ? 'T' : 'F')); + flow = (nsTableFrame*) flow->mNextInFlow; + } + } +#endif +#endif + return result; +} + +/** + * Try and pull-up frames from our next-in-flow + * + * @param aPresContext presentation context to use + * @param aState current inline state + * @return true if we successfully pulled-up all the children and false + * otherwise, e.g. child didn't fit + */ +PRBool nsTableFrame::PullUpChildren(nsIPresContext* aPresContext, + InnerTableReflowState& aState, + nsSize* aMaxElementSize) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": pullup (childCount=%d) [%d,%d,%c]\n", + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); +#ifdef NOISY_FLOW + { + nsTableFrame* flow = (nsTableFrame*) mNextInFlow; + while (flow != 0) { + printf(" %p: [%d,%d,%c]\n", + flow, flow->mFirstContentOffset, flow->mLastContentOffset, + (flow->mLastContentIsComplete ? 'T' : 'F')); + flow = (nsTableFrame*) flow->mNextInFlow; + } + } +#endif +#endif + NS_PRECONDITION(nsnull != mNextInFlow, "null next-in-flow"); + nsTableFrame* nextInFlow = (nsTableFrame*)mNextInFlow; + nsSize kidMaxElementSize; + nsSize* pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull; + + // The frame previous to the current frame we are reflowing. This + // starts out initially as our last frame. + nsIFrame* prevKidFrame = LastChild(); + + // This will hold the prevKidFrame's mLastContentIsComplete + // status. If we have to push the frame that follows prevKidFrame + // then this will become our mLastContentIsComplete state. Since + // prevKidFrame is initially our last frame, it's completion status + // is our mLastContentIsComplete value. + PRBool prevLastContentIsComplete = mLastContentIsComplete; + PRBool result = PR_TRUE; + + while (nsnull != nextInFlow) { + nsReflowMetrics desiredSize; + nsSize kidAvailSize(aState.availSize); + + // Get first available frame from the next-in-flow + nsIFrame* kidFrame = PullUpOneChild(nextInFlow, prevKidFrame); + if (nsnull == kidFrame) { + // We've pulled up all the children from that next-in-flow, so + // move to the next next-in-flow. + nextInFlow = (nsTableFrame*) nextInFlow->mNextInFlow; + continue; + } + + // Get top margin for this kid + nsIContent* kid = kidFrame->GetContent(); + nsIStyleContext* kidSC = kidFrame->GetStyleContext(aPresContext); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol); + nscoord bottomMargin = kidMol->margin.bottom; + + // Figure out the amount of available size for the child (subtract + // off the top margin we are going to apply to it) + if (PR_FALSE == aState.unconstrainedHeight) { + kidAvailSize.height -= topMargin; + } + // Subtract off for left and right margin + if (PR_FALSE == aState.unconstrainedWidth) { + kidAvailSize.width -= kidMol->margin.left + kidMol->margin.right; + } + + ReflowStatus status; + do { + // Only skip the reflow if this is not our first child and we are + // out of space. + if ((kidFrame == mFirstChild) || (kidAvailSize.height > 0)) { + status = ReflowChild(kidFrame, aPresContext, desiredSize, + kidAvailSize, pKidMaxElementSize); + } + + // Did the child fit? + if ((kidFrame != mFirstChild) && + ((kidAvailSize.height <= 0) || + (desiredSize.height > kidAvailSize.height))) + { + // The child's height is too big to fit at all in our remaining space, + // and it wouldn't have been our first child. + // + // Note that if the width is too big that's okay and we allow the + // child to extend horizontally outside of the reflow area + PRBool lastComplete = PRBool(nsnull == kidFrame->GetNextInFlow()); + PushChildren(kidFrame, prevKidFrame, lastComplete); + mLastContentIsComplete = prevLastContentIsComplete; + mChildCount--; + result = PR_FALSE; + NS_RELEASE(kid); + NS_RELEASE(kidSC); + goto push_done; + } + + // Place the child + aState.y += topMargin; + nsRect kidRect (0, 0, desiredSize.width, desiredSize.height); + kidRect.x += kidMol->margin.left; + kidRect.y += aState.y; + PlaceChild(aPresContext, aState, kidFrame, kidRect, kidMol, aMaxElementSize, + kidMaxElementSize); + if (bottomMargin < 0) { + aState.prevMaxNegBottomMargin = -bottomMargin; + } else { + aState.prevMaxPosBottomMargin = bottomMargin; + } + mLastContentIsComplete = PRBool(status == frComplete); + +#ifdef NOISY + ListTag(stdout); + printf(": pulled up "); + ((nsFrame*)kidFrame)->ListTag(stdout); + printf("\n"); +#endif + + // Is the child we just pulled up complete? + if (frNotComplete == status) { + // No the child isn't complete. + nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); + if (nsnull == kidNextInFlow) { + // The child doesn't have a next-in-flow so create a + // continuing frame. The creation appends it to the flow and + // prepares it for reflow. + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aPresContext, this); + + // Add the continuing frame to our sibling list. + continuingFrame->SetNextSibling(kidFrame->GetNextSibling()); + kidFrame->SetNextSibling(continuingFrame); + prevKidFrame = kidFrame; + prevLastContentIsComplete = mLastContentIsComplete; + kidFrame = continuingFrame; + mChildCount++; + } else { + // The child has a next-in-flow, but it's not one of ours. + // It *must* be in one of our next-in-flows. Collect it + // then. + NS_ASSERTION(kidNextInFlow->GetGeometricParent() != this, + "busted kid next-in-flow"); + break; + } + } + } while (frNotComplete == status); + NS_RELEASE(kid); + NS_RELEASE(kidSC); + + prevKidFrame = kidFrame; + prevLastContentIsComplete = mLastContentIsComplete; + } + + push_done:; + // Update our last content index + if (nsnull != prevKidFrame) { + NS_ASSERTION(LastChild() == prevKidFrame, "bad last child"); + SetLastContentOffset(prevKidFrame); + } + + // We need to make sure the first content offset is correct for any empty + // next-in-flow frames (frames where we pulled up all the child frames) + nextInFlow = (nsTableFrame*)mNextInFlow; + if ((nsnull != nextInFlow) && (nsnull == nextInFlow->mFirstChild)) { + // We have at least one empty frame. Did we succesfully pull up all the + // child frames? + if (PR_FALSE == result) { + // No, so we need to adjust the first content offset of all the empty + // frames + AdjustOffsetOfEmptyNextInFlows(); +#ifdef NS_DEBUG + } else { + // Yes, we successfully pulled up all the child frames which means all + // the next-in-flows must be empty. Do a sanity check + while (nsnull != nextInFlow) { + NS_ASSERTION(nsnull == nextInFlow->mFirstChild, "non-empty next-in-flow"); + nextInFlow = (nsTableFrame*)nextInFlow->GetNextInFlow(); + } +#endif + } + } + +#ifdef NS_DEBUG + PRInt32 len = LengthOf(mFirstChild); + NS_ASSERTION(len == mChildCount, "bad child count"); + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": pullup %sok (childCount=%d) [%d,%d,%c]\n", + (result ? "" : "NOT "), + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); +#ifdef NOISY_FLOW + { + nsTableFrame* flow = (nsTableFrame*) mNextInFlow; + while (flow != 0) { + printf(" %p: [%d,%d,%c]\n", + flow, flow->mFirstContentOffset, flow->mLastContentOffset, + (flow->mLastContentIsComplete ? 'T' : 'F')); + flow = (nsTableFrame*) flow->mNextInFlow; + } + } +#endif +#endif + return result; +} + +/** + * Create new frames for content we haven't yet mapped + * + * @param aPresContext presentation context to use + * @param aState current inline state + * @return frComplete if all content has been mapped and frNotComplete + * if we should be continued + */ +nsIFrame::ReflowStatus +nsTableFrame::ReflowUnmappedChildren(nsIPresContext* aPresContext, + InnerTableReflowState& aState, + nsSize* aMaxElementSize) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif + nsIFrame* kidPrevInFlow = nsnull; + ReflowStatus result = frNotComplete; + + // If we have no children and we have a prev-in-flow then we need to pick + // up where it left off. If we have children, e.g. we're being resized, then + // our content offset should already be set correctly... + if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) { + nsTableFrame* prev = (nsTableFrame*)mPrevInFlow; + NS_ASSERTION(prev->mLastContentOffset >= prev->mFirstContentOffset, "bad prevInFlow"); + + mFirstContentOffset = prev->NextChildOffset(); + if (!prev->mLastContentIsComplete) { + // Our prev-in-flow's last child is not complete + kidPrevInFlow = prev->LastChild(); + } + } + + PRBool originalLastContentIsComplete = mLastContentIsComplete; + + // Place our children, one at a time, until we are out of children + nsSize kidMaxElementSize; + nsSize* pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull; + PRInt32 kidIndex = NextChildOffset(); + nsIFrame* prevKidFrame = LastChild(); // XXX remember this... + + for (;;) { + // Get the next content object + nsIContent* kid = mContent->ChildAt(kidIndex); + if (nsnull == kid) { + result = frComplete; + break; + } + + // Make sure we still have room left + if (aState.availSize.height <= 0) { + // Note: return status was set to frNotComplete above... + NS_RELEASE(kid); + break; + } + + // Resolve style + nsIStyleContext* kidStyleContext = + aPresContext->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = + (nsStyleMolecule*)kidStyleContext->GetData(kStyleMoleculeSID); + nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol); + nscoord bottomMargin = kidMol->margin.bottom; + + nsIFrame* kidFrame; + ReflowStatus status; + + // Create a child frame + if (nsnull == kidPrevInFlow) { + nsIContentDelegate* kidDel = nsnull; + kidDel = kid->GetDelegate(aPresContext); + kidFrame = kidDel->CreateFrame(aPresContext, kid, kidIndex, this); + NS_RELEASE(kidDel); + kidFrame->SetStyleContext(kidStyleContext); + } else { + kidFrame = kidPrevInFlow->CreateContinuingFrame(aPresContext, this); + } + + // Link the child frame into the list of children and update the + // child count + if (nsnull != prevKidFrame) { + NS_ASSERTION(nsnull == prevKidFrame->GetNextSibling(), "bad append"); + prevKidFrame->SetNextSibling(kidFrame); + } else { + NS_ASSERTION(nsnull == mFirstChild, "bad create"); + mFirstChild = kidFrame; + SetFirstContentOffset(kidFrame); + } + mChildCount++; + + do { + nsSize kidAvailSize(aState.availSize); + nsReflowMetrics desiredSize; + + // Figure out the amount of available size for the child (subtract + // off the margin we are going to apply to it) + if (PR_FALSE == aState.unconstrainedHeight) { + kidAvailSize.height -= topMargin; + } + // Subtract off for left and right margin + if (PR_FALSE == aState.unconstrainedWidth) { + kidAvailSize.width -= kidMol->margin.left + kidMol->margin.right; + } + + // Try to reflow the child into the available space. It might not + // fit or might need continuing + if (kidAvailSize.height > 0) { + status = ReflowChild(kidFrame, aPresContext, desiredSize, + kidAvailSize, pKidMaxElementSize); + } + + // Did the child fit? + if ((nsnull != mFirstChild) && + ((kidAvailSize.height <= 0) || + (desiredSize.height > kidAvailSize.height))) { + // The child's height is too big to fit in our remaining + // space, and it's not our first child. + NS_ASSERTION(nsnull == mOverflowList, "bad overflow list"); + NS_ASSERTION(nsnull == mNextInFlow, "whoops"); + + // Chop off the part of our child list that's being overflowed + NS_ASSERTION(prevKidFrame->GetNextSibling() == kidFrame, "bad list"); + prevKidFrame->SetNextSibling(nsnull); + + // Create overflow list + mOverflowList = kidFrame; + + // Fixup child count by subtracting off the number of children + // that just ended up on the reflow list. + PRInt32 overflowKids = 0; + nsIFrame* f = kidFrame; + while (nsnull != f) { + overflowKids++; + f = f->GetNextSibling(); + } + mChildCount -= overflowKids; + NS_RELEASE(kidStyleContext); + NS_RELEASE(kid); + goto done; + } + + // Advance y by the topMargin between children. Zero out the + // topMargin in case this frame is continued because + // continuations do not have a top margin. Update the prev + // bottom margin state in the body reflow state so that we can + // apply the bottom margin when we hit the next child (or + // finish). + aState.y += topMargin; + nsRect kidRect (0, 0, desiredSize.width, desiredSize.height); + kidRect.x += kidMol->margin.left; + kidRect.y += aState.y; + PlaceChild(aPresContext, aState, kidFrame, kidRect, kidMol, aMaxElementSize, + kidMaxElementSize); + if (bottomMargin < 0) { + aState.prevMaxNegBottomMargin = -bottomMargin; + } else { + aState.prevMaxPosBottomMargin = bottomMargin; + } + topMargin = 0; + + mLastContentIsComplete = PRBool(status == frComplete); + if (frNotComplete == status) { + // Child didn't complete so create a continuing frame + kidPrevInFlow = kidFrame; + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aPresContext, this); + + // Add the continuing frame to the sibling list + continuingFrame->SetNextSibling(kidFrame->GetNextSibling()); + kidFrame->SetNextSibling(continuingFrame); + prevKidFrame = kidFrame; + kidFrame = continuingFrame; + mChildCount++; + + // XXX We probably shouldn't assume that there is no room for + // the continuation + } + } while (frNotComplete == status); + NS_RELEASE(kidStyleContext); + NS_RELEASE(kid); + + prevKidFrame = kidFrame; + kidPrevInFlow = nsnull; + + // Update the kidIndex + kidIndex++; + } + +done: + // Update the content mapping + NS_ASSERTION(LastChild() == prevKidFrame, "bad last child"); + if (0 != mChildCount) { + SetLastContentOffset(prevKidFrame); + } +#ifdef NS_DEBUG + PRInt32 len = LengthOf(mFirstChild); + NS_ASSERTION(len == mChildCount, "bad child count"); + VerifyLastIsComplete(); +#endif + return result; +} + +/** + Now I've got all the cells laid out in an infinite space. + For each column, use the min size for each cell in that column + along with the attributes of the table, column group, and column + to assign widths to each column. + */ +// use the cell map to determine which cell is in which column. +void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext, + nsStyleMolecule* aTableStyle, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ + NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!"); + + if (gsDebug) + printf ("BalanceColumnWidths...\n"); + + nsVoidArray *columnLayoutData = GetColumnLayoutData(); + PRInt32 numCols = columnLayoutData->Count(); + if (nsnull==mColumnWidths) + { + mColumnWidths = new PRInt32[numCols]; + // SEC should be a memset + for (PRInt32 i = 0; ifixedWidth) // if there is a fixed width attribute, use it + { + maxWidth = aTableStyle->fixedWidth; + } + else if ((NS_UNCONSTRAINEDSIZE!=maxWidth) && + (-1!=aTableStyle->proportionalWidth && 0!=aTableStyle->proportionalWidth)) + { + maxWidth = (maxWidth*aTableStyle->proportionalWidth)/100; + } + // now, if maxWidth is not NS_UNCONSTRAINED, subtract out my border and padding + if (NS_UNCONSTRAINEDSIZE!=maxWidth) + { + maxWidth -= aTableStyle->borderPadding.left + aTableStyle->borderPadding.right; + if (0>maxWidth) // nonsense style specification + maxWidth = 0; + } + + if (gsDebug) printf (" maxWidth=%d from aMaxSize=%d,%d\n", maxWidth, aMaxSize.width, aMaxSize.height); + + // Step 1 - assign the width of all fixed-width columns + AssignFixedColumnWidths(aPresContext, maxWidth, numCols, aTableStyle, + totalFixedWidth, minTableWidth, maxTableWidth); + + if (nsnull!=aMaxElementSize) + { + aMaxElementSize->width = minTableWidth; + if (gsDebug) printf(" setting aMaxElementSize->width = %d\n", aMaxElementSize->width); + } + else + { + if (gsDebug) printf(" nsnull aMaxElementSize\n"); + } + + // Step 2 - assign the width of all proportional-width columns in the remaining space + PRInt32 availWidth=maxWidth - totalFixedWidth; + if (gsDebug==PR_TRUE) printf ("Step 2...\n availWidth = %d\n", availWidth); + if (TableIsAutoWidth()) + { + if (gsDebug==PR_TRUE) printf (" calling BalanceProportionalColumnsForAutoWidthTable\n"); + BalanceProportionalColumnsForAutoWidthTable(aPresContext, aTableStyle, + availWidth, maxWidth, + minTableWidth, maxTableWidth); + } + else + { + if (gsDebug==PR_TRUE) printf (" calling BalanceProportionalColumnsForSpecifiedWidthTable\n"); + BalanceProportionalColumnsForSpecifiedWidthTable(aPresContext, aTableStyle, + availWidth, maxWidth, + minTableWidth, maxTableWidth); + } + +/* +STEP 1 +for every col + if the col has a fixed width + set the width to max(fixed width, maxElementSize) + if the cell spans columns, divide the cell width between the columns + else skip it for now + +take borders and padding into account + +STEP 2 +determine the min and max size for the table width +if col is proportionately specified + if (col width specified to 0) + col width = minColWidth + else if (minTableWidth >= aMaxSize.width) + set col widths to min, install a hor. scroll bar + else if (maxTableWidth <= aMaxSize.width) + set each col to its max size + else + W = aMaxSize.width - minTableWidth + D = maxTableWidth - minTableWidth + for each col + d = maxColWidth - minColWidth + col width = minColWidth + ((d*W)/D) + +STEP 3 +if there is space left over + for every col + if col is proportionately specified + add space to col width until it is that proportion of the table width + do this non-destructively in case there isn't enough space + if there isn't enough space as determined in the prior step, + add space in proportion to the proportionate width attribute + */ + +} + +// Step 1 - assign the width of all fixed-width columns, + // and calculate min/max table width + // still needs to take insets into account +PRBool nsTableFrame::AssignFixedColumnWidths(nsIPresContext* aPresContext, PRInt32 maxWidth, + PRInt32 aNumCols, nsStyleMolecule* aTableStyleMol, + PRInt32 &aTotalFixedWidth, + PRInt32 &aMinTableWidth, PRInt32 &aMaxTableWidth) +{ + NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!"); + + if (gsDebug==PR_TRUE) printf (" AssignFixedColumnWidths\n"); + for (PRInt32 colIndex = 0; colIndexElementAt(colIndex)); + NS_ASSERTION(nsnull != colData, "bad column data"); + nsTableCol *col = colData->GetCol(); // col: ADDREF++ + NS_ASSERTION(nsnull != col, "bad col"); + nsStyleMolecule* colStyle = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + NS_ASSERTION(nsnull != colStyle, "bad style for col."); + // need to track min/max column width for setting min/max table widths + PRInt32 minColWidth = 0; + PRInt32 maxColWidth = 0; + nsVoidArray *cells = colData->GetCells(); + PRInt32 numCells = cells->Count(); + if (gsDebug==PR_TRUE) printf (" for column %d numCells = %d\n", colIndex, numCells); + for (PRInt32 cellIndex = 0; cellIndexElementAt(cellIndex)); + NS_ASSERTION(nsnull != data, "bad data"); + nsSize * cellMinSize = data->GetMaxElementSize(); + nsReflowMetrics * cellDesiredSize = data->GetDesiredSize(); + NS_ASSERTION(nsnull != cellDesiredSize, "bad cellDesiredSize"); + if (gsDebug==PR_TRUE) + printf (" for cell %d min = %d,%d and des = %d,%d\n", cellIndex, cellMinSize->width, cellMinSize->height, + cellDesiredSize->width, cellDesiredSize->height); + /* the first cell in a column (in row 0) has special standing. + * if the first cell has a width specification, it overrides the COL width + */ + if (0==cellIndex) + { + // SEC: TODO -- when we have a style system, set the mol for the col + nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(0)); + nsTableCellFrame *cellFrame = data->GetCellFrame(); + nsTableCell *cell = (nsTableCell *)cellFrame->GetContent(); // cell: REFCNT++ + nsStyleMolecule* cellStyle = (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + NS_ASSERTION(nsnull != cellStyle, "bad style for cell."); + // SEC: this is the code to replace + if (-1!=cellStyle->fixedWidth) + colStyle->proportionalWidth = cellStyle->proportionalWidth; + if (-1!=cellStyle->proportionalWidth) + colStyle->proportionalWidth = cellStyle->proportionalWidth; + // SEC: end code to replace + NS_RELEASE(cell); // cell: REFCNT-- + } + if (-1!=colStyle->fixedWidth) + { // this col has fixed width, so set the cell's width + // to the larger of (specified width, largest max_element_size of the cells in the column) + PRInt32 widthForThisCell = max(cellMinSize->width, colStyle->fixedWidth); + if (mColumnWidths[colIndex] < widthForThisCell) + { + if (gsDebug) printf (" setting fixed width to %d\n",widthForThisCell); + mColumnWidths[colIndex] = widthForThisCell; + maxColWidth = widthForThisCell; + } + } + // regardless of the width specification, keep track of the min/max column widths + /* TODO: must distribute COLSPAN'd cell widths between columns, either here + * or in the subsequent Balance***ColumnWidth routines + */ + if (minColWidth < cellMinSize->width) + minColWidth = cellMinSize->width; + if (maxColWidth < cellDesiredSize->width) + maxColWidth = cellDesiredSize->width; + if (gsDebug==PR_TRUE) + printf (" after cell %d, minColWidth = %d and maxColWidth = %d\n", cellIndex, minColWidth, maxColWidth); + /* take colspan into account? */ + /* + PRInt32 colSpan = col->GetColSpan(); + cellIndex += colSpan-1; + */ + } + if (-1!=colStyle->fixedWidth) + { + // if the col is fixed-width, expand the col to the specified fixed width if necessary + if (colStyle->fixedWidth > mColumnWidths[colIndex]) + mColumnWidths[colIndex] = colStyle->fixedWidth; + // keep a running total of the amount of space taken up by all fixed-width columns + aTotalFixedWidth += mColumnWidths[colIndex]; + if (gsDebug) + printf (" after col %d, aTotalFixedWidth = %d\n", colIndex, aTotalFixedWidth); + } + // add col[i] metrics to the running totals for the table min/max width + if (NS_UNCONSTRAINEDSIZE!=aMinTableWidth) + aMinTableWidth += minColWidth; // SEC: insets! + if (aMinTableWidth<=0) + aMinTableWidth = NS_UNCONSTRAINEDSIZE; // handle overflow + if (NS_UNCONSTRAINEDSIZE!=aMaxTableWidth) + aMaxTableWidth += maxColWidth; // SEC: insets! + if (aMaxTableWidth<=0) + aMaxTableWidth = NS_UNCONSTRAINEDSIZE; // handle overflow + if (gsDebug==PR_TRUE) + printf (" after this col, minTableWidth = %d and maxTableWidth = %d\n", aMinTableWidth, aMaxTableWidth); + + NS_IF_RELEASE(col); // col: ADDREF-- + } // end Step 1 for fixed-width columns + return PR_TRUE; +} + +PRBool nsTableFrame::BalanceProportionalColumnsForSpecifiedWidthTable(nsIPresContext* aPresContext, + nsStyleMolecule* aTableStyleMol, + PRInt32 aAvailWidth, + PRInt32 aMaxWidth, + PRInt32 aMinTableWidth, + PRInt32 aMaxTableWidth) +{ + NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!"); + + PRBool result = PR_TRUE; + + if (NS_UNCONSTRAINEDSIZE==aMaxWidth) + { // the max width of the table fits comfortably in the available space + if (gsDebug) printf (" * table laying out in NS_UNCONSTRAINEDSIZE, calling BalanceColumnsTableFits\n"); + result = BalanceColumnsTableFits(aPresContext, aTableStyleMol, aAvailWidth); + } + else if (aMinTableWidth > aMaxWidth) + { // the table doesn't fit in the available space + if (gsDebug) printf (" * min table does not fit, calling SetColumnsToMinWidth\n"); + result = SetColumnsToMinWidth(aPresContext); + } + else if (aMaxTableWidth < aMaxWidth) + { // the max width of the table fits comfortably in the available space + if (gsDebug) printf (" * table desired size fits, calling BalanceColumnsTableFits\n"); + result = BalanceColumnsTableFits(aPresContext, aTableStyleMol, aAvailWidth); + } + else + { // the table fits somewhere between its min and desired size + if (gsDebug) printf (" * table desired size does not fit, calling BalanceColumnsHTML4Constrained\n"); + result = BalanceColumnsHTML4Constrained(aPresContext, aTableStyleMol, aAvailWidth, + aMaxWidth, aMinTableWidth, aMaxTableWidth); + } + return result; +} + +PRBool nsTableFrame::BalanceProportionalColumnsForAutoWidthTable( nsIPresContext* aPresContext, + nsStyleMolecule* aTableStyleMol, + PRInt32 aAvailWidth, + PRInt32 aMaxWidth, + PRInt32 aMinTableWidth, + PRInt32 aMaxTableWidth) +{ + PRBool result = PR_TRUE; + + if (NS_UNCONSTRAINEDSIZE==aMaxWidth) + { // the max width of the table fits comfortably in the available space + if (gsDebug) printf (" * table laying out in NS_UNCONSTRAINEDSIZE, calling BalanceColumnsTableFits\n"); + result = BalanceColumnsTableFits(aPresContext, aTableStyleMol, aAvailWidth); + } + else if (aMinTableWidth > aMaxWidth) + { // the table doesn't fit in the available space + if (gsDebug) printf (" * min table does not fit, calling SetColumnsToMinWidth\n"); + result = SetColumnsToMinWidth(aPresContext); + } + else if (aMaxTableWidth < aMaxWidth) + { // the max width of the table fits comfortably in the available space + if (gsDebug) printf (" * table desired size fits, calling BalanceColumnsTableFits\n"); + result = BalanceColumnsTableFits(aPresContext, aTableStyleMol, aAvailWidth); + } + else + { // the table fits somewhere between its min and desired size + if (gsDebug) printf (" * table desired size does not fit, calling BalanceColumnsHTML4Constrained\n"); + result = BalanceColumnsHTML4Constrained(aPresContext, aTableStyleMol, aAvailWidth, + aMaxWidth, aMinTableWidth, aMaxTableWidth); + } + return result; +} + +PRBool nsTableFrame::SetColumnsToMinWidth(nsIPresContext* aPresContext) +{ + PRBool result = PR_TRUE; + nsVoidArray *columnLayoutData = GetColumnLayoutData(); + PRInt32 numCols = columnLayoutData->Count(); + for (PRInt32 colIndex = 0; colIndexElementAt(colIndex)); + nsTableCol *col = colData->GetCol(); // col: ADDREF++ + nsStyleMolecule* colStyle = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + nsVoidArray *cells = colData->GetCells(); + PRInt32 minColWidth = 0; + PRInt32 maxColWidth = 0; + PRInt32 numCells = cells->Count(); + if (gsDebug==PR_TRUE) printf (" for col %d\n", colIndex); + if (PR_TRUE==IsProportionalWidth(colStyle)) + { + for (PRInt32 cellIndex = 0; cellIndexElementAt(cellIndex)); + NS_ASSERTION(nsnull != data, "bad data"); + nsSize * cellMinSize = data->GetMaxElementSize(); + NS_ASSERTION(nsnull != cellMinSize, "bad cellMinSize"); + nsReflowMetrics * cellDesiredSize = data->GetDesiredSize(); + NS_ASSERTION(nsnull != cellDesiredSize, "bad cellDesiredSize"); + if (minColWidth < cellMinSize->width) + minColWidth = cellMinSize->width; + if (maxColWidth < cellDesiredSize->width) + maxColWidth = cellDesiredSize->width; + /* + if (gsDebug==PR_TRUE) + printf (" after cell %d, minColWidth = %d and maxColWidth = %d\n", + cellIndex, minColWidth, maxColWidth); + */ + } + + if (gsDebug==PR_TRUE) + { + printf (" for determining width of col %d %s:\n",colIndex, IsProportionalWidth(colStyle)? "(P)":"(A)"); + printf (" minColWidth = %d and maxColWidth = %d\n", minColWidth, maxColWidth); + } + if (PR_TRUE==IsProportionalWidth(colStyle)) + { // this col has proportional width, so set its width based on the table width + mColumnWidths[colIndex] = minColWidth; + if (gsDebug==PR_TRUE) + printf (" 2: col %d, set to width = %d\n", colIndex, mColumnWidths[colIndex]); + } + } + NS_IF_RELEASE(col); // col: ADDREF-- + } + return result; +} + +PRBool nsTableFrame::BalanceColumnsTableFits(nsIPresContext* aPresContext, + nsStyleMolecule* aTableStyleMol, + PRInt32 aAvailWidth) +{ + NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!"); + + PRBool result = PR_TRUE; + nsVoidArray *columnLayoutData = GetColumnLayoutData(); + PRInt32 numCols = columnLayoutData->Count(); + for (PRInt32 colIndex = 0; colIndexElementAt(colIndex)); + nsTableCol *col = colData->GetCol(); // col: ADDREF++ + nsStyleMolecule* colStyle = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + nsVoidArray *cells = colData->GetCells(); + PRInt32 minColWidth = 0; + PRInt32 maxColWidth = 0; + PRInt32 numCells = cells->Count(); + if (gsDebug==PR_TRUE) printf (" for col %d\n", colIndex); + /* TODO: must distribute COLSPAN'd cell widths between columns, either here + * or in the prior Balance***ColumnWidth routines + */ + if (PR_TRUE==IsProportionalWidth(colStyle)) + { + for (PRInt32 cellIndex = 0; cellIndexElementAt(cellIndex)); + NS_ASSERTION(nsnull != data, "bad data"); + nsSize * cellMinSize = data->GetMaxElementSize(); + NS_ASSERTION(nsnull != cellMinSize, "bad cellMinSize"); + nsReflowMetrics * cellDesiredSize = data->GetDesiredSize(); + NS_ASSERTION(nsnull != cellDesiredSize, "bad cellDesiredSize"); + if (minColWidth < cellMinSize->width) + minColWidth = cellMinSize->width; + if (maxColWidth < cellDesiredSize->width) + maxColWidth = cellDesiredSize->width; + if (gsDebug==PR_TRUE) + printf (" after cell %d, minColWidth = %d and maxColWidth = %d\n", + cellIndex, minColWidth, maxColWidth); + } + + if (gsDebug==PR_TRUE) + { + printf (" for determining width of col %d %s:\n",colIndex, IsProportionalWidth(colStyle)? "(P)":"(A)"); + printf (" minColWidth = %d and maxColWidth = %d\n", minColWidth, maxColWidth); + printf (" aAvailWidth = %d\n", aAvailWidth); + } + if (PR_TRUE==IsProportionalWidth(colStyle)) + { // this col has proportional width, so set its width based on the table width + if (0==colStyle->proportionalWidth) + { // col width is specified to be the minimum + mColumnWidths[colIndex] = minColWidth; + if (gsDebug==PR_TRUE) + printf (" 3 (0): col %d set to min width = %d because style set proportionalWidth=0\n", + colIndex, mColumnWidths[colIndex]); + } + if (PR_TRUE==AutoColumnWidths(aTableStyleMol)) + { // give each remaining column it's desired width + // if there is width left over, we'll factor that in after this loop is complete + mColumnWidths[colIndex] = maxColWidth; + if (gsDebug==PR_TRUE) + printf (" 3a: col %d with availWidth %d, set to width = %d\n", + colIndex, aAvailWidth, mColumnWidths[colIndex]); + } + else + { // give each remaining column an equal percentage of the remaining space + PRInt32 percentage = -1; + if (NS_UNCONSTRAINEDSIZE==aAvailWidth) + { + mColumnWidths[colIndex] = maxColWidth; + } + else + { + percentage = colStyle->proportionalWidth; + if (-1==percentage) + percentage = 100/numCols; + mColumnWidths[colIndex] = (percentage*aAvailWidth)/100; + // if the column was computed to be too small, enlarge the column + if (mColumnWidths[colIndex] <= minColWidth) + mColumnWidths[colIndex] = minColWidth; + } + if (gsDebug==PR_TRUE) + printf (" 3b: col %d given %d percent of availWidth %d, set to width = %d\n", + colIndex, percentage, aAvailWidth, mColumnWidths[colIndex]); + } + } + } + NS_IF_RELEASE(col); // col: ADDREF-- + } + return result; +} + +PRBool nsTableFrame::BalanceColumnsHTML4Constrained(nsIPresContext* aPresContext, + nsStyleMolecule* aTableStyleMol, + PRInt32 aAvailWidth, + PRInt32 aMaxWidth, + PRInt32 aMinTableWidth, + PRInt32 aMaxTableWidth) +{ + NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!"); + + PRBool result = PR_TRUE; + PRInt32 maxOfAllMinColWidths = 0; + nsVoidArray *columnLayoutData = GetColumnLayoutData(); + PRInt32 numCols = columnLayoutData->Count(); + for (PRInt32 colIndex = 0; colIndexElementAt(colIndex)); + nsTableCol *col = colData->GetCol(); // col: ADDREF++ + nsStyleMolecule* colStyle = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + nsVoidArray *cells = colData->GetCells(); + PRInt32 minColWidth = 0; + PRInt32 maxColWidth = 0; + PRInt32 numCells = cells->Count(); + if (gsDebug==PR_TRUE) printf (" for col %d\n", colIndex); + if (PR_TRUE==IsProportionalWidth(colStyle)) + { + for (PRInt32 cellIndex = 0; cellIndexElementAt(cellIndex)); + NS_ASSERTION(nsnull != data, "bad data"); + nsSize * cellMinSize = data->GetMaxElementSize(); + NS_ASSERTION(nsnull != cellMinSize, "bad cellMinSize"); + nsReflowMetrics * cellDesiredSize = data->GetDesiredSize(); + NS_ASSERTION(nsnull != cellDesiredSize, "bad cellDesiredSize"); + if (minColWidth < cellMinSize->width) + minColWidth = cellMinSize->width; + if (maxColWidth < cellDesiredSize->width) + maxColWidth = cellDesiredSize->width; + /* + if (gsDebug==PR_TRUE) + printf (" after cell %d, minColWidth = %d and maxColWidth = %d\n", + cellIndex, minColWidth, maxColWidth); + */ + } + + if (gsDebug==PR_TRUE) + { + printf (" for determining width of col %d %s:\n",colIndex, IsProportionalWidth(colStyle)? "(P)":"(A)"); + printf (" minTableWidth = %d and maxTableWidth = %d\n", aMinTableWidth, aMaxTableWidth); + printf (" minColWidth = %d and maxColWidth = %d\n", minColWidth, maxColWidth); + printf (" aAvailWidth = %d\n", aAvailWidth); + } + if (PR_TRUE==IsProportionalWidth(colStyle)) + { // this col has proportional width, so set its width based on the table width + // the table fits in the space somewhere between its min and max size + // so dole out the available space appropriately + if (0==colStyle->proportionalWidth) + { // col width is specified to be the minimum + mColumnWidths[colIndex] = minColWidth; + if (gsDebug==PR_TRUE) + printf (" 4 (0): col %d set to min width = %d because style set proportionalWidth=0\n", + colIndex, mColumnWidths[colIndex]); + } + else if (AutoColumnWidths(aTableStyleMol)) + { + PRInt32 W = aMaxWidth - aMinTableWidth; + PRInt32 D = aMaxTableWidth - aMinTableWidth; + PRInt32 d = maxColWidth - minColWidth; + mColumnWidths[colIndex] = minColWidth + ((d*W)/D); + if (gsDebug==PR_TRUE) + printf (" 4 auto-width: col %d W=%d D=%d d=%d, set to width = %d\n", + colIndex, W, D, d, mColumnWidths[colIndex]); + } + else + { // give each remaining column an equal percentage of the remaining space + PRInt32 percentage = colStyle->proportionalWidth; + if (-1==percentage) + percentage = 100/numCols; + mColumnWidths[colIndex] = (percentage*aAvailWidth)/100; + // if the column was computed to be too small, enlarge the column + if (mColumnWidths[colIndex] <= minColWidth) + { + mColumnWidths[colIndex] = minColWidth; + if (maxOfAllMinColWidths < minColWidth) + maxOfAllMinColWidths = minColWidth; + } + if (gsDebug==PR_TRUE) + { + printf (" 4 equal width: col %d given %d percent of availWidth %d, set to width = %d\n", + colIndex, percentage, aAvailWidth, mColumnWidths[colIndex]); + if (0!=maxOfAllMinColWidths) + printf(" and setting maxOfAllMins to %d\n", maxOfAllMinColWidths); + } + } + } + } + NS_IF_RELEASE(col); // col: ADDREF-- + } + + // post-process if necessary + + // if columns have equal width, and some column's content couldn't squeeze into the computed size, + // then expand every column to the min size of the column with the largest min size + if (!AutoColumnWidths(aTableStyleMol) && 0!=maxOfAllMinColWidths) + { + if (gsDebug==PR_TRUE) printf(" EqualColWidths specified, so setting all col widths to %d\n", maxOfAllMinColWidths); + for (PRInt32 colIndex = 0; colIndexCount(); + for (PRInt32 i = 0; iborderPadding.right; + nscoord leftInset = aTableStyle->borderPadding.left; + tableWidth += (leftInset + rightInset); + nsRect tableSize = GetRect(); + tableSize.width = tableWidth; + if (gsDebug==PR_TRUE) + { + printf ("setting table rect to %d, %d after adding insets %d, %d\n", + tableSize.width, tableSize.height, rightInset, leftInset); + } + SetRect(tableSize); +} + +/** + */ +void nsTableFrame::ShrinkWrapChildren(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + nsSize* aMaxElementSize) +{ +#ifdef NS_DEBUG + PRBool gsDebugWas = gsDebug; + gsDebug = PR_FALSE; // turn on debug in this method +#endif + // iterate children, tell all row groups to ShrinkWrap + PRInt32 childCount = ChildCount(); + PRBool atLeastOneRowSpanningCell = PR_FALSE; + PRInt32 tableHeight = 0; + for (PRInt32 i = 0; i < childCount; i++) + { + PRInt32 childHeight=0; + // for every child that is a rowFrame, set the row frame height = sum of row heights + nsIFrame * kidFrame = ChildAt(i); // frames are not ref counted + NS_ASSERTION(nsnull != kidFrame, "bad kid frame"); + nsTableContent* kid = (nsTableContent*)(kidFrame->GetContent()); // kid: REFCNT++ + NS_ASSERTION(nsnull != kid, "bad kid"); + if (kid->GetType() == nsITableContent::kTableRowGroupType) + { + /* Step 1: set the row height to the height of the tallest cell, + * and resize all cells in that row to that height (except cells with rowspan>1) + */ + PRInt32 rowGroupHeight = 0; + nsTableRowGroupFrame * rowGroupFrame = (nsTableRowGroupFrame *)kidFrame; + PRInt32 numRows = rowGroupFrame->ChildCount(); + PRInt32 *rowHeights = new PRInt32[numRows]; + if (gsDebug==PR_TRUE) printf("Height Step 1...\n"); + for (PRInt32 rowIndex = 0; rowIndex < numRows; rowIndex++) + { + // get the height of the tallest cell in the row (excluding cells that span rows) + nsTableRowFrame *rowFrame = (nsTableRowFrame *)(rowGroupFrame->ChildAt(rowIndex)); + NS_ASSERTION(nsnull != rowFrame, "bad row frame"); + rowHeights[rowIndex] = rowFrame->GetTallestChild(); + rowFrame->SizeTo(rowFrame->GetWidth(), rowHeights[rowIndex]); + rowGroupHeight += rowHeights[rowIndex]; + // resize all the cells based on the rowHeight + PRInt32 numCells = rowFrame->ChildCount(); + for (PRInt32 cellIndex = 0; cellIndex < numCells; cellIndex++) + { + nsTableCellFrame *cellFrame = (nsTableCellFrame *)(rowFrame->ChildAt(cellIndex)); + PRInt32 rowSpan = cellFrame->GetRowSpan(); + if (1==rowSpan) + { + if (gsDebug==PR_TRUE) printf(" setting cell[%d,%d] height to %d\n", rowIndex, cellIndex, rowHeights[rowIndex]); + cellFrame->SizeTo(cellFrame->GetWidth(), rowHeights[rowIndex]); + // Realign cell content based on new height + cellFrame->VerticallyAlignChild(aPresContext); + } + else + { + if (gsDebug==PR_TRUE) printf(" skipping cell[%d,%d] with a desired height of %d\n", rowIndex, cellIndex, cellFrame->GetHeight()); + atLeastOneRowSpanningCell = PR_TRUE; + } + } + } + + /* Step 2: now account for cells that span rows. + * a spanning cell's height is the sum of the heights of the rows it spans, + * or it's own desired height, whichever is greater. + * If the cell's desired height is the larger value, resize the rows and contained + * cells by an equal percentage of the additional space. + */ + /* TODO + * 1. optimization, if (PR_TRUE==atLeastOneRowSpanningCell) ... otherwise skip this step entirely + * 2. find cases where spanning cells effect other spanning cells that began in rows above themselves. + * I think in this case, we have to make another pass through step 2. + * There should be a "rational" check to terminate that kind of loop after n passes, probably 3 or 4. + */ + if (gsDebug==PR_TRUE) printf("Height Step 2...\n"); + rowGroupHeight=0; + for (rowIndex = 0; rowIndex < numRows; rowIndex++) + { + nsTableRowFrame *rowFrame = (nsTableRowFrame *)(rowGroupFrame->ChildAt(rowIndex)); + PRInt32 numCells = rowFrame->ChildCount(); + for (PRInt32 cellIndex = 0; cellIndex < numCells; cellIndex++) + { + nsTableCellFrame *cellFrame = (nsTableCellFrame *)(rowFrame->ChildAt(cellIndex)); + PRInt32 rowSpan = cellFrame->GetRowSpan(); + if (1cellFrame->GetHeight()) + { + if (gsDebug==PR_TRUE) printf(" cell[%d,%d] fits, setting height to %d\n", rowIndex, cellIndex, heightOfRowsSpanned); + cellFrame->SizeTo(cellFrame->GetWidth(), heightOfRowsSpanned); + // Realign cell content based on new height + cellFrame->VerticallyAlignChild(aPresContext); + } + /* otherwise, we have a real mess on our hands. + * distribute the excess height to the rows effected, and to the cells in those rows + */ + else + { + PRInt32 excessHeight = cellFrame->GetHeight() - heightOfRowsSpanned; + PRInt32 excessHeightPerRow = excessHeight/rowSpan; + if (gsDebug==PR_TRUE) printf(" cell[%d,%d] does not fit, excessHeight = %d, excessHeightPerRow = %d\n", + rowIndex, cellIndex, excessHeight, excessHeightPerRow); + // for the rows effected... + for (i=rowIndex; iChildAt(i)); + if (iSizeTo(rowFrameToBeResized->GetWidth(), rowHeights[i]); + PRInt32 cellCount = rowFrameToBeResized->ChildCount(); + for (PRInt32 j=0; jChildAt(j)); + if (frame->GetRowSpan()==1) + { + if (gsDebug==PR_TRUE) printf(" cell[%d, %d] set height to %d\n", i, j, frame->GetHeight()+excessHeightPerRow); + frame->SizeTo(frame->GetWidth(), frame->GetHeight()+excessHeightPerRow); + // Realign cell content based on new height + frame->VerticallyAlignChild(aPresContext); + } + } + } + // if we're dealing with a row below the row containing the spanning cell, + // push that row down by the amount we've expanded the cell heights by + if (i>rowIndex) + { + nsRect rowRect = rowFrameToBeResized->GetRect(); + rowFrameToBeResized->MoveTo(rowRect.x, rowRect.y + (excessHeightPerRow*(i-rowIndex))); + if (gsDebug==PR_TRUE) printf(" row %d moved to y-offset %d\n", i, + rowRect.y + (excessHeightPerRow*(i-rowIndex))); + } + } + } + } + } + rowGroupHeight += rowHeights[rowIndex]; + } + if (gsDebug==PR_TRUE) printf("row group height set to %d\n", rowGroupHeight); + rowGroupFrame->SizeTo(rowGroupFrame->GetWidth(), rowGroupHeight); + tableHeight += rowGroupHeight; + } + NS_RELEASE(kid); // kid: REFCNT-- + } + if (0!=tableHeight) + { + if (gsDebug==PR_TRUE) printf("table desired height set to %d\n", tableHeight); + aDesiredSize.height = tableHeight; + } +#ifdef NS_DEBUG + gsDebug = gsDebugWas; +#endif +} + +PRBool nsTableFrame::IsProportionalWidth(nsStyleMolecule* aMol) +{ + PRBool result = PR_FALSE; + if ((-1!=aMol->proportionalWidth) || + ((-1==aMol->proportionalWidth) && (-1==aMol->fixedWidth))) + result = PR_TRUE; + return result; +} + +/** + */ +nsIFrame::ReflowStatus +nsTableFrame::IncrementalReflow(nsIPresContext* aCX, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand) +{ + NS_ASSERTION(nsnull != aCX, "bad arg"); + if (gsDebug==PR_TRUE) printf ("nsTableFrame::IncrementalReflow: maxSize=%d,%d\n", + aMaxSize.width, aMaxSize.height); + + // mFirstPassValid needs to be set somewhere in response to change notifications. + + aDesiredSize.width = mRect.width; + aDesiredSize.height = mRect.height; + return frComplete; +} + +void nsTableFrame::VerticallyAlignChildren(nsIPresContext* aPresContext, + nscoord* aAscents, + nscoord aMaxAscent, + nscoord aMaxHeight) +{ +} + +nsVoidArray * nsTableFrame::GetColumnLayoutData() +{ + nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); + NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); + return firstInFlow->mColumnLayoutData; +} + +/** Associate aData with the cell at (aRow,aCol) + * @return PR_TRUE if the data was successfully associated with a Cell + * PR_FALSE if there was an error, such as aRow or aCol being invalid + */ +PRBool nsTableFrame::SetCellLayoutData(nsCellLayoutData * aData, nsTableCell *aCell) +{ + NS_ASSERTION(nsnull != aData, "bad arg"); + NS_ASSERTION(nsnull != aCell, "bad arg"); + + PRBool result = PR_TRUE; + + nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); + NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); + if (this!=firstInFlow) + result = firstInFlow->SetCellLayoutData(aData, aCell); + else + { + if (kPASS_FIRST==GetReflowPass()) + { + if (nsnull==mColumnLayoutData) + { + mColumnLayoutData = new nsVoidArray(); + NS_ASSERTION(nsnull != mColumnLayoutData, "bad alloc"); + nsTablePart * tablePart = (nsTablePart *)mContent; + PRInt32 cols = tablePart->GetMaxColumns(); + PRInt32 tableKidCount = tablePart->ChildCount(); + for (PRInt32 i=0; iChildAt(i); + NS_ASSERTION(nsnull != tableKid, "bad kid"); + const int contentType = tableKid->GetType(); + if (contentType == nsITableContent::kTableColGroupType) + { + PRInt32 colsInGroup = tableKid->ChildCount(); + for (PRInt32 j=0; jChildAt(j); + NS_ASSERTION(nsnull != col, "bad content"); + nsColLayoutData *colData = new nsColLayoutData(col); + mColumnLayoutData->AppendElement((void *)colData); + NS_RELEASE(col); // col: REFCNT-- + } + } + // can't have col groups after row groups, so stop if you find a row group + else if (contentType == nsITableContent::kTableRowGroupType) + { + NS_RELEASE(tableKid); // tableKid: REFCNT-- + break; + } + NS_RELEASE(tableKid); // tableKid: REFCNT-- + } + } + + // create cell layout data objects for the passed in data, one per column spanned + // for now, divide width equally between spanned columns + + PRInt32 firstColIndex = aCell->GetColIndex(); + nsTableRow *row = aCell->GetRow(); // row: ADDREF++ + PRInt32 rowIndex = row->GetRowIndex(); + NS_RELEASE(row); // row: ADDREF-- + PRInt32 colSpan = aCell->GetColSpan(); + nsColLayoutData * colData = (nsColLayoutData *)(mColumnLayoutData->ElementAt(firstColIndex)); + nsVoidArray *col = colData->GetCells(); + if (gsDebugCLD) printf (" ~ SetCellLayoutData with row = %d, firstCol = %d, colSpan = %d, colData = %ld, col=%ld\n", + rowIndex, firstColIndex, colSpan, colData, col); + for (PRInt32 i=0; iGetMaxElementSize(); + nsSize partialCellSize(*cellSize); + partialCellSize.width = (cellSize->width)/colSpan; + // This method will copy the nsReflowMetrics pointed at by aData->GetDesiredSize() + nsCellLayoutData * kidLayoutData = new nsCellLayoutData(aData->GetCellFrame(), + aData->GetDesiredSize(), + &partialCellSize); + PRInt32 numCells = col->Count(); + if (gsDebugCLD) printf (" ~ before setting data, number of cells in this column = %d\n", numCells); + if ((numCells==0) || numCellsAppendElement((void *)kidLayoutData); + } + else + { + if (gsDebugCLD) printf (" ~ replacing %d + rowIndex = %d\n", i, i+rowIndex); + nsCellLayoutData* data = (nsCellLayoutData*)col->ElementAt(i+rowIndex); + col->ReplaceElementAt((void *)kidLayoutData, i+rowIndex); + if (data != nsnull) + delete data; + } + if (gsDebugCLD) printf (" ~ after setting data, number of cells in this column = %d\n", col->Count()); + } + } + else + result = PR_FALSE; + } + + return result; +} + +/** Get the layout data associated with the cell at (aRow,aCol) + * @return nsnull if there was an error, such as aRow or aCol being invalid + * otherwise, the data is returned. + */ +nsCellLayoutData * nsTableFrame::GetCellLayoutData(nsTableCell *aCell) +{ + NS_ASSERTION(nsnull != aCell, "bad arg"); + + nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); + NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); + nsCellLayoutData *result = nsnull; + if (this!=firstInFlow) + result = firstInFlow->GetCellLayoutData(aCell); + else + { + if (nsnull!=mColumnLayoutData) + { + PRInt32 firstColIndex = aCell->GetColIndex(); + nsColLayoutData * colData = (nsColLayoutData *)(mColumnLayoutData->ElementAt(firstColIndex)); + nsVoidArray *cells = colData->GetCells(); + PRInt32 count = cells->Count(); + for (PRInt32 i=0; iElementAt(i)); + nsTableCell *cell = (nsTableCell *)(data->GetCellFrame()->GetContent()); // cell: REFCNT++ + if (cell == aCell) + { + result = data; + NS_RELEASE(cell); // cell: REFCNT-- + break; + } + NS_RELEASE(cell); // cell: REFCNT-- + } + } + } + return result; +} + + + +PRInt32 nsTableFrame::GetReflowPass() const +{ + nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); + NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); + return firstInFlow->mPass; +} + +void nsTableFrame::SetReflowPass(PRInt32 aReflowPass) +{ + nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); + NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); + firstInFlow->mPass = aReflowPass; +} + +PRBool nsTableFrame::IsFirstPassValid() const +{ + nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); + NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); + return firstInFlow->mFirstPassValid; +} + +//ZZZ TOTAL HACK +PRBool isTableAutoWidth = PR_TRUE; +PRBool isAutoColumnWidths = PR_TRUE; + +PRBool nsTableFrame::TableIsAutoWidth() +{ // ZZZ: TOTAL HACK + return isTableAutoWidth; +} + +PRBool nsTableFrame::AutoColumnWidths(nsStyleMolecule* aTableStyleMol) +{ // ZZZ: TOTAL HACK + return isAutoColumnWidths; +} + +nsIFrame* nsTableFrame::CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent) +{ + nsTableFrame* cf = new nsTableFrame(mContent, mIndexInParent, aParent); + PrepareContinuingFrame(aPresContext, aParent, cf); + if (PR_TRUE==gsDebug) printf("nsTableFrame::CCF parent = %p, this=%p, cf=%p\n", aParent, this, cf); + // set my width, because all frames in a table flow are the same width + // code in nsTableOuterFrame depends on this being set + cf->SetRect(nsRect(0, 0, GetWidth(), 0)); + // add headers and footers to cf + nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); + PRInt32 childCount = firstInFlow->ChildCount(); + PRInt32 childIndex = 0; + for (; childIndex < childCount; childIndex++) + { + // TODO: place copies of the header and footer row groups here + // maybe need to do this in ResizeReflow at the beginning, when we determine we are a continuing frame + } + + return cf; +} + +PRInt32 nsTableFrame::GetColumnWidth(PRInt32 aColIndex) +{ + nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); + NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); + PRInt32 result = 0; + if (this!=firstInFlow) + result = firstInFlow->GetColumnWidth(aColIndex); + else + { + NS_ASSERTION(nsnull!=mColumnWidths, "illegal state"); + if (nsnull!=mColumnWidths) + result = mColumnWidths[aColIndex]; + } + return result; +} + +void nsTableFrame::SetColumnWidth(PRInt32 aColIndex, PRInt32 aWidth) +{ + nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); + NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); + if (this!=firstInFlow) + firstInFlow->SetColumnWidth(aColIndex, aWidth); + else + { + NS_ASSERTION(nsnull!=mColumnWidths, "illegal state"); + if (nsnull!=mColumnWidths) + mColumnWidths[aColIndex] = aWidth; + } +} + + +/* ---------- static methods ---------- */ + +nsresult nsTableFrame::NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIFrame* it = new nsTableFrame(aContent, aIndexInParent, aParent); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aInstancePtrResult = it; + return NS_OK; +} + +/* valuable code not yet used anywhere + + // since the table is a specified width, we need to expand the columns to fill the table + nsVoidArray *columnLayoutData = GetColumnLayoutData(); + PRInt32 numCols = columnLayoutData->Count(); + PRInt32 spaceUsed = 0; + for (PRInt32 colIndex = 0; colIndexElementAt(colIndex)); + nsTableCol *col = colData->GetCol(); // col: ADDREF++ + nsStyleMolecule* colStyle = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + if (PR_TRUE==IsProportionalWidth(colStyle)) + { + PRInt32 percentage = (100*mColumnWidths[colIndex]) / aMaxWidth; + PRInt32 additionalSpace = (spaceRemaining*percentage)/100; + mColumnWidths[colIndex] += additionalSpace; + additionalSpaceAdded += additionalSpace; + } + NS_IF_RELEASE(col); // col: ADDREF-- + } + if (spaceUsed+additionalSpaceAdded < aMaxTableWidth) + mColumnWidths[numCols-1] += (aMaxTableWidth - (spaceUsed+additionalSpaceAdded)); + } +*/ + + + + diff --git a/mozilla/layout/html/table/src/nsTableFrame.h b/mozilla/layout/html/table/src/nsTableFrame.h new file mode 100644 index 00000000000..c4dcdf4bd19 --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableFrame.h @@ -0,0 +1,290 @@ +/* -*- 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. + */ +#ifndef nsTableFrame_h__ +#define nsTableFrame_h__ + +#include "nscore.h" +#include "nsContainerFrame.h" + +class nsCellLayoutData; +class nsTableCell; +class nsVoidArray; +class nsTableCellFrame; +class CellData; +struct nsStyleMolecule; +struct InnerTableReflowState; + +/** + */ +class nsTableFrame : public nsContainerFrame +{ +public: + + friend class nsTableOuterFrame; + + static nsresult NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + virtual void Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + virtual ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + + virtual ReflowStatus IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand); + + /** + * @see nsContainerFrame + */ + virtual nsIFrame* CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent); + + /** resize myself and my children according to the arcane rules of cell height magic. + * By default, the height of a cell is the max (height of cells in its row) + * In the case of a cell with rowspan>1 (lets call this C), + * if the sum of the height of the rows spanned (excluding C in the calculation) + * is greater than or equal to the height of C, + * the cells in the rows are sized normally and + * the height of C is set to the sum of the heights (taking into account borders, padding, and margins) + * else + * the height of each row is expanded by a percentage of the difference between + * the row's desired height and the height of C + */ + virtual void ShrinkWrapChildren(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + nsSize* aMaxElementSize); + + /** return the column layout data for this inner table frame. + * if this is a continuing frame, return the first-in-flow's column layout data. + */ + virtual nsVoidArray *GetColumnLayoutData(); + + /** Associate aData with the cell at (aRow,aCol) + * @return PR_TRUE if the data was successfully associated with a Cell + * PR_FALSE if there was an error, such as aRow or aCol being invalid + */ + virtual PRBool SetCellLayoutData(nsCellLayoutData * aData, nsTableCell *aCell); + + /** Get the layout data associated with the cell at (aRow,aCol) + * @return PR_NULL if there was an error, such as aRow or aCol being invalid + * otherwise, the data is returned. + */ + virtual nsCellLayoutData * GetCellLayoutData(nsTableCell *aCell); + + /** + */ + PRBool IsProportionalWidth(nsStyleMolecule* aMol); + + + + /** + * DEBUG METHOD + * + */ + + void ListColumnLayoutData(FILE* out = stdout, PRInt32 aIndent = 0) const; + + + /** + */ + PRInt32 GetColumnWidth(PRInt32 aColIndex); + + /** + */ + void SetColumnWidth(PRInt32 aColIndex, PRInt32 aWidth); + + + + /** + * Calculate Layout Information + * + */ + nsCellLayoutData* FindCellLayoutData(nsTableCell* aCell); + void AppendLayoutData(nsVoidArray* aList, nsTableCell* aTableCell); + void ResetColumnLayoutData(); + void ResetCellLayoutData( nsTableCell* aCell, + nsTableCell* aAbove, + nsTableCell* aBelow, + nsTableCell* aLeft, + nsTableCell* aRight); + + + +protected: + + nsTableFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual ~nsTableFrame(); + + /** + */ + virtual void DeleteColumnLayoutData(); + + /** + */ + virtual nsIFrame::ReflowStatus ResizeReflowPass1(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize, + nsStyleMolecule* aTableStyle); + + /** + * aMinCaptionWidth - the max of all the minimum caption widths. 0 if no captions. + * aMaxCaptionWidth - the max of all the desired caption widths. 0 if no captions. + */ + virtual nsIFrame::ReflowStatus ResizeReflowPass2(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize, + nsStyleMolecule* aTableStyle, + PRInt32 aMinCaptionWidth, + PRInt32 mMaxCaptionWidth); + + nscoord GetTopMarginFor(nsIPresContext* aCX, + InnerTableReflowState& aState, + nsStyleMolecule* aKidMol); + + void PlaceChild(nsIPresContext* aPresContext, + InnerTableReflowState& aState, + nsIFrame* aKidFrame, + const nsRect& aKidRect, + nsStyleMolecule* aKidMol, + nsSize* aMaxElementSize, + nsSize& aKidMaxElementSize); + + PRBool ReflowMappedChildren(nsIPresContext* aPresContext, + InnerTableReflowState& aState, + nsSize* aMaxElementSize); + + PRBool PullUpChildren(nsIPresContext* aPresContext, + InnerTableReflowState& aState, + nsSize* aMaxElementSize); + + ReflowStatus ReflowUnmappedChildren(nsIPresContext* aPresContext, + InnerTableReflowState& aState, + nsSize* aMaxElementSize); + + + /** + */ + virtual void BalanceColumnWidths(nsIPresContext* aPresContext, + nsStyleMolecule* aTableStyle, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + + /** + */ + virtual PRBool AssignFixedColumnWidths(nsIPresContext* aPresContext, + PRInt32 aMaxWidth, + PRInt32 aNumCols, + nsStyleMolecule* aTableStyleMol, + PRInt32 & aTotalFixedWidth, + PRInt32 & aMinTableWidth, + PRInt32 & aMaxTableWidth); + /** + */ + virtual PRBool BalanceProportionalColumnsForSpecifiedWidthTable(nsIPresContext* aPresContext, + nsStyleMolecule* aTableStyleMol, + PRInt32 aAvailWidth, + PRInt32 aMaxWidth, + PRInt32 aMinTableWidth, + PRInt32 aMaxTableWidth); + + /** + */ + virtual PRBool BalanceProportionalColumnsForAutoWidthTable(nsIPresContext* aPresContext, + nsStyleMolecule* aTableStyleMol, + PRInt32 aAvailWidth, + PRInt32 aMaxWidth, + PRInt32 aMinTableWidth, + PRInt32 aMaxTableWidth); + + virtual PRBool SetColumnsToMinWidth(nsIPresContext* aPresContext); + + virtual PRBool BalanceColumnsTableFits(nsIPresContext* aPresContext, + nsStyleMolecule* aTableStyleMol, + PRInt32 aAvailWidth); + + virtual PRBool BalanceColumnsHTML4Constrained(nsIPresContext* aPresContext, + nsStyleMolecule* aTableStyleMol, + PRInt32 aAvailWidth, + PRInt32 aMaxWidth, + PRInt32 aMinTableWidth, + PRInt32 aMaxTableWidth); + + /** + */ + virtual void SetTableWidth(nsIPresContext* aPresContext, + nsStyleMolecule* aTableStyle); + + /** + */ + virtual void VerticallyAlignChildren(nsIPresContext* aPresContext, + nscoord* aAscents, + nscoord aMaxAscent, + nscoord aMaxHeight); + + /** support routine returns PR_TRUE if the table should be sized "automatically" + * according to its content. + * In NAV4, this is the default (no WIDTH, no COLS). + */ + virtual PRBool TableIsAutoWidth(); + + /** support routine returns PR_TRUE if the table columns should be sized "automatically" + * according to its content. + * In NAV4, this is when there is a COLS attribute on the table. + */ + virtual PRBool AutoColumnWidths(nsStyleMolecule* aTableStyleMol); + + /** given the new parent size, do I really need to do a reflow? */ + virtual PRBool NeedsReflow(const nsSize& aMaxSize); + + virtual PRInt32 GetReflowPass() const; + + virtual void SetReflowPass(PRInt32 aReflowPass); + + virtual PRBool IsFirstPassValid() const; + +private: + void nsTableFrame::DebugPrintCount() const; // Debugging routine + + + /** table reflow is a multi-pass operation. Use these constants to keep track of + * which pass is currently being executed. + */ + enum {kPASS_UNDEFINED=0, kPASS_FIRST=1, kPASS_SECOND=2, kPASS_THIRD=3}; + + nsVoidArray *mColumnLayoutData; // array of array of cellLayoutData's + PRInt32 *mColumnWidths; // widths of each column + PRBool mFirstPassValid; // PR_TRUE if first pass data is still legit + PRInt32 mPass; // which Reflow pass are we currently in? + PRBool mIsInvariantWidth; // PR_TRUE if table width cannot change + +}; + +#endif diff --git a/mozilla/layout/html/table/src/nsTableOuterFrame.cpp b/mozilla/layout/html/table/src/nsTableOuterFrame.cpp new file mode 100644 index 00000000000..88fe79a6eef --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableOuterFrame.cpp @@ -0,0 +1,1211 @@ +/* -*- 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 "nsTableOuterFrame.h" +#include "nsTableFrame.h" +#include "nsTableCaptionFrame.h" +#include "nsITableContent.h" +#include "nsTableContent.h" +#include "nsBodyFrame.h" +#include "nsReflowCommand.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsIPresContext.h" +#include "nsIRenderingContext.h" +#include "nsCSSRendering.h" +#include "nsIContent.h" +#include "nsIContentDelegate.h" +#include "nsCSSLayout.h" +#include "nsVoidArray.h" +#include "nsReflowCommand.h" + +#ifdef NS_DEBUG +static PRBool gsDebug = PR_FALSE; +//#define NOISY +//#define NOISY_FLOW +//#define NOISY_MARGINS +#else +static const PRBool gsDebug = PR_FALSE; +#endif + +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); +static NS_DEFINE_IID(kITableContentIID, NS_ITABLECONTENT_IID); + +struct OuterTableReflowState { + + // The body's style molecule + nsStyleMolecule* mol; + + // The total available size (computed from the parent) + nsSize availSize; + // The available size for the inner table frame + nsSize innerTableMaxSize; + + // Margin tracking information + nscoord prevMaxPosBottomMargin; + nscoord prevMaxNegBottomMargin; + + // Flags for whether the max size is unconstrained + PRBool unconstrainedWidth; + PRBool unconstrainedHeight; + + // Running y-offset + nscoord y; + + // Flags for where we are in the content + PRBool firstRowGroup; + PRBool processingCaption; + + OuterTableReflowState(nsIPresContext* aPresContext, + const nsSize& aMaxSize, + nsStyleMolecule* aMol) + { + mol = aMol; + availSize.width = aMaxSize.width; + availSize.height = aMaxSize.height; + prevMaxPosBottomMargin = 0; + prevMaxNegBottomMargin = 0; + y=0; // border/padding/margin??? + unconstrainedWidth = PRBool(aMaxSize.width == NS_UNCONSTRAINEDSIZE); + unconstrainedHeight = PRBool(aMaxSize.height == NS_UNCONSTRAINEDSIZE); + firstRowGroup = PR_TRUE; + processingCaption = PR_FALSE; + } + + ~OuterTableReflowState() { + } +}; + + + +/* ----------- nsTableOuterFrame ---------- */ + + +/** + */ +nsTableOuterFrame::nsTableOuterFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsContainerFrame(aContent, aIndexInParent, aParentFrame), + mInnerTableFrame(nsnull), + mCaptionFrames(nsnull), + mBottomCaptions(nsnull), + mMinCaptionWidth(0), + mMaxCaptionWidth(0), + mFirstPassValid(PR_FALSE) +{ +} + +nsTableOuterFrame::~nsTableOuterFrame() +{ + if (nsnull!=mCaptionFrames) + delete mCaptionFrames; + if (nsnull!=mBottomCaptions) + delete mBottomCaptions; +} + +void nsTableOuterFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + // for debug... + if (nsIFrame::GetShowFrameBorders()) { + aRenderingContext.SetColor(NS_RGB(255,0,0)); + aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height); + } + + PaintChildren(aPresContext, aRenderingContext, aDirtyRect); +} + +PRBool nsTableOuterFrame::NeedsReflow(const nsSize& aMaxSize) +{ + PRBool result=PR_TRUE; + if (nsnull!=mInnerTableFrame) + result = mInnerTableFrame->NeedsReflow(aMaxSize); + return result; +} + +PRBool nsTableOuterFrame::IsFirstPassValid() +{ + return mFirstPassValid; +} + +void nsTableOuterFrame::SetFirstPassValid(PRBool aValidState) +{ + mFirstPassValid = aValidState; +} + +/** + * ResizeReflow is a 2-step process. + * In the first step, we lay out all of the captions and the inner table in NS_UNCONSTRAINEDSIZE space. + * This gives us absolute minimum and maximum widths. + * In the second step, we force all the captions and the table to the width of the widest component, + * given the table's width constraints. + * With the widths known, we reflow the captions and table. + * NOTE: for breaking across pages, this method has to account for table content that is not laid out + * linearly vis a vis the frames. That is, content hierarchy and the frame hierarchy do not match. + */ +nsIFrame::ReflowStatus nsTableOuterFrame::ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ + if (PR_TRUE==gsDebug) printf ("***table outer frame reflow \t\t%d\n", this); + if (gsDebug==PR_TRUE) + printf("nsTableOuterFrame::ResizeReflow : maxSize=%d,%d\n", + aMaxSize.width, aMaxSize.height); + +#ifdef NS_DEBUG + // replace with a check that does not assume linear placement of children + // PreReflowCheck(); +#endif + + // Initialize out parameter + if (nsnull != aMaxElementSize) { + aMaxElementSize->width = 0; + aMaxElementSize->height = 0; + } + + PRBool reflowMappedOK = PR_TRUE; + ReflowStatus status = frComplete; + nsSize innerTableMaxElementSize(0,0); + + // Set up our kids. They're already present, on an overflow list, + // or there are none so we'll create them now + MoveOverflowToChildList(); + if (nsnull==mFirstChild) + CreateChildFrames(aPresContext); + if (nsnull!=mPrevInFlow && nsnull==mInnerTableFrame) + { // if I am a continuing frame, my inner table is my prev-in-flow's mInnerTableFrame's next-in-flow + CreateInnerTableFrame(aPresContext); + } + // at this point, we must have at least one child frame, and we must have an inner table frame + NS_ASSERTION(nsnull!=mFirstChild, "no children"); + NS_ASSERTION(nsnull!=mInnerTableFrame, "no mInnerTableFrame"); + if (nsnull==mFirstChild || nsnull==mInnerTableFrame) //ERROR! + return frComplete; + + nsStyleMolecule* tableStyleMol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + + OuterTableReflowState state(aPresContext, aMaxSize, tableStyleMol); + + // lay out captions pass 1, if necessary + if (PR_FALSE==IsFirstPassValid()) + { + mFirstPassValid = PR_TRUE; + status = ResizeReflowCaptionsPass1(aPresContext, tableStyleMol); + + } + + // lay out inner table, if required + if (PR_FALSE==mInnerTableFrame->IsFirstPassValid()) + { // we treat the table as if we've never seen the layout data before + mInnerTableFrame->SetReflowPass(nsTableFrame::kPASS_FIRST); + status = mInnerTableFrame->ResizeReflowPass1(aPresContext, aDesiredSize, aMaxSize, + &innerTableMaxElementSize, tableStyleMol); + +#ifdef NOISY_MARGINS + nsIContent* content = mInnerTableFrame->GetContent(); + nsTablePart *table = (nsTablePart*)content; + if (table != nsnull) + table->DumpCellMap(); + mInnerTableFrame->ResetColumnLayoutData(); + mInnerTableFrame->ListColumnLayoutData(stdout,1); + NS_IF_RELEASE(content); +#endif + + } + mInnerTableFrame->SetReflowPass(nsTableFrame::kPASS_SECOND); + // assign table width info only if the inner table frame is a first-in-flow + if (nsnull==mInnerTableFrame->GetPrevInFlow()) + { + // assign column widths, and assign aMaxElementSize->width + mInnerTableFrame->BalanceColumnWidths(aPresContext, tableStyleMol, aMaxSize, aMaxElementSize); + // assign table width + mInnerTableFrame->SetTableWidth(aPresContext, tableStyleMol); + } + // inner table max is now the computed width and assigned height + state.innerTableMaxSize.width = mInnerTableFrame->GetWidth(); + state.innerTableMaxSize.height = aMaxSize.height; + + // Reflow the child frames + if (nsnull != mFirstChild) { + reflowMappedOK = ReflowMappedChildren(aPresContext, state, aMaxElementSize); + if (PR_FALSE == reflowMappedOK) { + status = frNotComplete; + } + } + + // Did we successfully relow our mapped children? + if (PR_TRUE == reflowMappedOK) { + // Any space left? + if ((nsnull != mFirstChild) && (state.availSize.height <= 0)) { + // No space left. Don't try to pull-up children or reflow unmapped + if (NextChildOffset() < mContent->ChildCount()) { + status = frNotComplete; + } + } else if (NextChildOffset() < mContent->ChildCount()) { + // Try and pull-up some children from a next-in-flow + if ((nsnull == mNextInFlow) || + PullUpChildren(aPresContext, state, aMaxElementSize)) { + // nothing to do, we will never have unmapped children! + } else { + // We were unable to pull-up all the existing frames from the + // next in flow + status = frNotComplete; + } + } + } + + if (frComplete == status) { + // Don't forget to add in the bottom margin from our last child. + // Only add it in if there's room for it. + nscoord margin = state.prevMaxPosBottomMargin - + state.prevMaxNegBottomMargin; + if (state.availSize.height >= margin) { + state.y += margin; + } + } + + // Return our desired rect + //NS_ASSERTION(0width, aMaxElementSize->height); + else + printf("Outer frame Reflow complete, returning aDesiredSize = %d,%d and NSNULL aMaxElementSize\n", + aDesiredSize.width, aDesiredSize.height); + } + +#ifdef NS_DEBUG + // replace with a check that does not assume linear placement of children + // PostReflowCheck(status); +#endif + + return status; + +} + +// Collapse child's top margin with previous bottom margin +nscoord nsTableOuterFrame::GetTopMarginFor(nsIPresContext* aCX, + OuterTableReflowState& aState, + nsStyleMolecule* aKidMol) +{ + nscoord margin; + nscoord maxNegTopMargin = 0; + nscoord maxPosTopMargin = 0; + if ((margin = aKidMol->margin.top) < 0) { + maxNegTopMargin = -margin; + } else { + maxPosTopMargin = margin; + } + + nscoord maxPos = PR_MAX(aState.prevMaxPosBottomMargin, maxPosTopMargin); + nscoord maxNeg = PR_MAX(aState.prevMaxNegBottomMargin, maxNegTopMargin); + margin = maxPos - maxNeg; + + return margin; +} + +// Position and size aKidFrame and update our reflow state. The origin of +// aKidRect is relative to the upper-left origin of our frame, and includes +// any left/top margin. +void nsTableOuterFrame::PlaceChild( nsIPresContext* aPresContext, + OuterTableReflowState& aState, + nsIFrame* aKidFrame, + const nsRect& aKidRect, + nsStyleMolecule* aKidMol, + nsSize* aMaxElementSize, + nsSize& aKidMaxElementSize) +{ + if (PR_TRUE==gsDebug) printf ("place child: %p with aKidRect %d %d %d %d\n", + aKidFrame, aKidRect.x, aKidRect.y, + aKidRect.width, aKidRect.height); + // Place and size the child + aKidFrame->SetRect(aKidRect); + + // Adjust the running y-offset + aState.y += aKidRect.height; + + // If our height is constrained then update the available height + if (PR_FALSE == aState.unconstrainedHeight) { + aState.availSize.height -= aKidRect.height; + } + + /* Update the maximum element size, which is the sum of: + * the maxElementSize of our first row + * plus the maxElementSize of the top caption if we include it + * plus the maxElementSize of the bottom caption if we include it + */ + if (PR_TRUE==aState.processingCaption || PR_TRUE==aState.firstRowGroup) + { + if (PR_FALSE==aState.processingCaption) + aState.firstRowGroup = PR_FALSE; + if (nsnull != aMaxElementSize) { + aMaxElementSize->width = aKidMaxElementSize.width; + aMaxElementSize->height = aKidMaxElementSize.height; + } + } +} + +/** + * Reflow the frames we've already created + * + * @param aPresContext presentation context to use + * @param aState current inline state + * @return true if we successfully reflowed all the mapped children and false + * otherwise, e.g. we pushed children to the next in flow + */ +PRBool nsTableOuterFrame::ReflowMappedChildren( nsIPresContext* aPresContext, + OuterTableReflowState& aState, + nsSize* aMaxElementSize) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": reflow mapped (childCount=%d) [%d,%d,%c]\n", + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); +#ifdef NOISY_FLOW + { + nsTableOuterFrame* flow = (nsTableOuterFrame*) mNextInFlow; + while (flow != 0) { + printf(" %p: [%d,%d,%c]\n", + flow, flow->mFirstContentOffset, flow->mLastContentOffset, + (flow->mLastContentIsComplete ? 'T' : 'F')); + flow = (nsTableOuterFrame*) flow->mNextInFlow; + } + } +#endif +#endif + NS_PRECONDITION(nsnull != mFirstChild, "no children"); + + PRInt32 childCount = 0; + nsIFrame* prevKidFrame = nsnull; + + // Remember our original mLastContentIsComplete so that if we end up + // having to push children, we have the correct value to hand to + // PushChildren. + PRBool lastContentIsComplete = mLastContentIsComplete; + + nsSize kidMaxElementSize; + nsSize* pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull; + PRBool result = PR_TRUE; + + for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; ) { + nsSize kidAvailSize(aState.innerTableMaxSize.width, aState.availSize.height); + nsReflowMetrics desiredSize; + nsIFrame::ReflowStatus status; + + SetReflowState(aState, kidFrame); + + if (PR_TRUE==gsDebug) printf ("ReflowMappedChildren: %p with state = %s\n", + kidFrame, aState.processingCaption?"caption":"inner"); + + // Get top margin for this kid + nsIStyleContext* kidSC = kidFrame->GetStyleContext(aPresContext); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol); + nscoord bottomMargin = kidMol->margin.bottom; + NS_RELEASE(kidSC); + + // Figure out the amount of available size for the child (subtract + // off the top margin we are going to apply to it) + if (PR_FALSE == aState.unconstrainedHeight) { + kidAvailSize.height -= topMargin; + } + // Subtract off for left and right margin + if (PR_FALSE == aState.unconstrainedWidth) { + kidAvailSize.width -= kidMol->margin.left + kidMol->margin.right; + } + + // Only skip the reflow if this is not our first child and we are + // out of space. + if ((kidFrame == mFirstChild) || (kidAvailSize.height > 0)) { + // Reflow the child into the available space + status = ReflowChild(kidFrame, aPresContext, desiredSize, + kidAvailSize, pKidMaxElementSize, + aState); + } + + // Did the child fit? + if ((kidFrame != mFirstChild) && + ((kidAvailSize.height <= 0) || + (desiredSize.height > kidAvailSize.height))) + { + // The child's height is too big to fit at all in our remaining space, + // and it's not our first child. + // + // Note that if the width is too big that's okay and we allow the + // child to extend horizontally outside of the reflow area + + // Since we are giving the next-in-flow our last child, we + // give it our original mLastContentIsComplete, too (in case we + // are pushing into an empty next-in-flow) + if (PR_TRUE==gsDebug) printf ("ReflowMappedChildren: calling PushChildren\n"); + PushChildren(kidFrame, prevKidFrame, lastContentIsComplete); + + // Our mLastContentIsComplete was already set by the last kid we + // reflowed reflow's status + result = PR_FALSE; + break; + } + + // Place the child after taking into account it's margin + aState.y += topMargin; + nsRect kidRect (0, 0, desiredSize.width, desiredSize.height); + kidRect.x += kidMol->margin.left; + kidRect.y += aState.y; + if (PR_TRUE==gsDebug) printf ("ReflowMappedChildren: calling PlaceChild\n"); + PlaceChild(aPresContext, aState, kidFrame, kidRect, kidMol, aMaxElementSize, + kidMaxElementSize); + if (bottomMargin < 0) { + aState.prevMaxNegBottomMargin = -bottomMargin; + } else { + aState.prevMaxPosBottomMargin = bottomMargin; + } + childCount++; + + // Update mLastContentIsComplete now that this kid fits + mLastContentIsComplete = PRBool(status == frComplete); + + // Special handling for incomplete children + if (frNotComplete == status) { + // XXX It's good to assume that we might still have room + // even if the child didn't complete (floaters will want this) + nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); + if (nsnull == kidNextInFlow) { + // No the child isn't complete, and it doesn't have a next in flow so + // create a continuing frame. This hooks the child into the flow. + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aPresContext, this); + + // Insert the frame. We'll reflow it next pass through the loop + nsIFrame* nextSib = kidFrame->GetNextSibling(); + continuingFrame->SetNextSibling(nextSib); + kidFrame->SetNextSibling(continuingFrame); + if (nsnull == nextSib) { + // Assume that the continuation frame we just created is + // complete, for now. It will get reflowed by our + // next-in-flow (we are going to push it now) + lastContentIsComplete = PR_TRUE; + } + } + } + + // Get the next child + prevKidFrame = kidFrame; + kidFrame = kidFrame->GetNextSibling(); + + // XXX talk with troy about checking for available space here + } + + // Update the child count + mChildCount = childCount; + NS_POSTCONDITION(LengthOf(mFirstChild) == mChildCount, "bad child count"); + + // Set the last content offset based on the last child we mapped. + NS_ASSERTION(LastChild() == prevKidFrame, "unexpected last child"); + SetLastContentOffset(prevKidFrame); + +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": reflow mapped %sok (childCount=%d) [%d,%d,%c]\n", + (result ? "" : "NOT "), + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); +#ifdef NOISY_FLOW + { + nsTableOuterFrame* flow = (nsTableOuterFrame*) mNextInFlow; + while (flow != 0) { + printf(" %p: [%d,%d,%c]\n", + flow, flow->mFirstContentOffset, flow->mLastContentOffset, + (flow->mLastContentIsComplete ? 'T' : 'F')); + flow = (nsTableOuterFrame*) flow->mNextInFlow; + } + } +#endif +#endif + return result; +} + +/** + * Try and pull-up frames from our next-in-flow + * + * @param aPresContext presentation context to use + * @param aState current inline state + * @return true if we successfully pulled-up all the children and false + * otherwise, e.g. child didn't fit + */ +PRBool nsTableOuterFrame::PullUpChildren(nsIPresContext* aPresContext, + OuterTableReflowState& aState, + nsSize* aMaxElementSize) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": pullup (childCount=%d) [%d,%d,%c]\n", + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); +#ifdef NOISY_FLOW + { + nsTableOuterFrame* flow = (nsTableOuterFrame*) mNextInFlow; + while (flow != 0) { + printf(" %p: [%d,%d,%c]\n", + flow, flow->mFirstContentOffset, flow->mLastContentOffset, + (flow->mLastContentIsComplete ? 'T' : 'F')); + flow = (nsTableOuterFrame*) flow->mNextInFlow; + } + } +#endif +#endif + NS_PRECONDITION(nsnull != mNextInFlow, "null next-in-flow"); + nsTableOuterFrame* nextInFlow = (nsTableOuterFrame*)mNextInFlow; + nsSize kidMaxElementSize; + nsSize* pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull; + + // The frame previous to the current frame we are reflowing. This + // starts out initially as our last frame. + nsIFrame* prevKidFrame = LastChild(); + + // This will hold the prevKidFrame's mLastContentIsComplete + // status. If we have to push the frame that follows prevKidFrame + // then this will become our mLastContentIsComplete state. Since + // prevKidFrame is initially our last frame, it's completion status + // is our mLastContentIsComplete value. + PRBool prevLastContentIsComplete = mLastContentIsComplete; + PRBool result = PR_TRUE; + + while (nsnull != nextInFlow) { + nsReflowMetrics desiredSize; + nsSize kidAvailSize(aState.availSize); + + // Get first available frame from the next-in-flow + nsIFrame* kidFrame = PullUpOneChild(nextInFlow, prevKidFrame); + if (nsnull == kidFrame) { + // We've pulled up all the children from that next-in-flow, so + // move to the next next-in-flow. + nextInFlow = (nsTableOuterFrame*) nextInFlow->mNextInFlow; + continue; + } + + // Get top margin for this kid + nsIContent* kid = kidFrame->GetContent(); + nsIStyleContext* kidSC = kidFrame->GetStyleContext(aPresContext); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol); + nscoord bottomMargin = kidMol->margin.bottom; + + // Figure out the amount of available size for the child (subtract + // off the top margin we are going to apply to it) + if (PR_FALSE == aState.unconstrainedHeight) { + kidAvailSize.height -= topMargin; + } + // Subtract off for left and right margin + if (PR_FALSE == aState.unconstrainedWidth) { + kidAvailSize.width -= kidMol->margin.left + kidMol->margin.right; + } + + ReflowStatus status; + do { + // Only skip the reflow if this is not our first child and we are + // out of space. + if ((kidFrame == mFirstChild) || (kidAvailSize.height > 0)) { + SetReflowState(aState, kidFrame); + status = ReflowChild(kidFrame, aPresContext, desiredSize, + kidAvailSize, pKidMaxElementSize, + aState); + } + + // Did the child fit? + if ((kidFrame != mFirstChild) && + ((kidAvailSize.height <= 0) || + (desiredSize.height > kidAvailSize.height))) + { + // The child's height is too big to fit at all in our remaining space, + // and it wouldn't have been our first child. + // + // Note that if the width is too big that's okay and we allow the + // child to extend horizontally outside of the reflow area + PRBool lastComplete = PRBool(nsnull == kidFrame->GetNextInFlow()); + PushChildren(kidFrame, prevKidFrame, lastComplete); + mLastContentIsComplete = prevLastContentIsComplete; + mChildCount--; + result = PR_FALSE; + NS_RELEASE(kid); + NS_RELEASE(kidSC); + goto push_done; + } + + // Place the child + aState.y += topMargin; + nsRect kidRect (0, 0, desiredSize.width, desiredSize.height); + kidRect.x += kidMol->margin.left; + kidRect.y += aState.y; + PlaceChild(aPresContext, aState, kidFrame, kidRect, kidMol, aMaxElementSize, + kidMaxElementSize); + if (bottomMargin < 0) { + aState.prevMaxNegBottomMargin = -bottomMargin; + } else { + aState.prevMaxPosBottomMargin = bottomMargin; + } + mLastContentIsComplete = PRBool(status == frComplete); + +#ifdef NOISY + ListTag(stdout); + printf(": pulled up "); + ((nsFrame*)kidFrame)->ListTag(stdout); + printf("\n"); +#endif + + // Is the child we just pulled up complete? + if (frNotComplete == status) { + // No the child isn't complete. + nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); + if (nsnull == kidNextInFlow) { + // The child doesn't have a next-in-flow so create a + // continuing frame. The creation appends it to the flow and + // prepares it for reflow. + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aPresContext, this); + + // Add the continuing frame to our sibling list. + continuingFrame->SetNextSibling(kidFrame->GetNextSibling()); + kidFrame->SetNextSibling(continuingFrame); + prevKidFrame = kidFrame; + prevLastContentIsComplete = mLastContentIsComplete; + kidFrame = continuingFrame; + mChildCount++; + } else { + // The child has a next-in-flow, but it's not one of ours. + // It *must* be in one of our next-in-flows. Collect it + // then. + NS_ASSERTION(kidNextInFlow->GetGeometricParent() != this, + "busted kid next-in-flow"); + break; + } + } + } while (frNotComplete == status); + NS_RELEASE(kid); + NS_RELEASE(kidSC); + + prevKidFrame = kidFrame; + prevLastContentIsComplete = mLastContentIsComplete; + } + + push_done:; + // Update our last content index + if (nsnull != prevKidFrame) { + NS_ASSERTION(LastChild() == prevKidFrame, "bad last child"); + SetLastContentOffset(prevKidFrame); + } + + // We need to make sure the first content offset is correct for any empty + // next-in-flow frames (frames where we pulled up all the child frames) + nextInFlow = (nsTableOuterFrame*)mNextInFlow; + if ((nsnull != nextInFlow) && (nsnull == nextInFlow->mFirstChild)) { + // We have at least one empty frame. Did we succesfully pull up all the + // child frames? + if (PR_FALSE == result) { + // No, so we need to adjust the first content offset of all the empty + // frames + AdjustOffsetOfEmptyNextInFlows(); +#ifdef NS_DEBUG + } else { + // Yes, we successfully pulled up all the child frames which means all + // the next-in-flows must be empty. Do a sanity check + while (nsnull != nextInFlow) { + NS_ASSERTION(nsnull == nextInFlow->mFirstChild, "non-empty next-in-flow"); + nextInFlow = (nsTableOuterFrame*)nextInFlow->GetNextInFlow(); + } +#endif + } + } + +#ifdef NS_DEBUG + PRInt32 len = LengthOf(mFirstChild); + NS_ASSERTION(len == mChildCount, "bad child count"); + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": pullup %sok (childCount=%d) [%d,%d,%c]\n", + (result ? "" : "NOT "), + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); +#ifdef NOISY_FLOW + { + nsTableOuterFrame* flow = (nsTableOuterFrame*) mNextInFlow; + while (flow != 0) { + printf(" %p: [%d,%d,%c]\n", + flow, flow->mFirstContentOffset, flow->mLastContentOffset, + (flow->mLastContentIsComplete ? 'T' : 'F')); + flow = (nsTableOuterFrame*) flow->mNextInFlow; + } + } +#endif +#endif + return result; +} + +/** set the OuterTableReflowState based on the child frame we are currently processing. + * must be called before ReflowChild, at a minimum. + */ +void nsTableOuterFrame::SetReflowState(OuterTableReflowState& aState, nsIFrame* aKidFrame) +{ + nsIContent *kid = aKidFrame->GetContent(); // kid: REFCNT++ + nsITableContent *tableContentInterface = nsnull; + kid->QueryInterface(kITableContentIID, (void**)&tableContentInterface);// tableContentInterface: REFCNT++ + if (nsnull!=tableContentInterface) + { + aState.processingCaption = PR_TRUE; + NS_RELEASE(tableContentInterface); // tableContentInterface: REFCNT-- + } + else + aState.processingCaption = PR_FALSE; + NS_RELEASE(kid); // kid: REFCNT-- +} + +/** + * Reflow a child frame and return the status of the reflow. If the + * child is complete and it has next-in-flows (it was a splittable child) + * then delete the next-in-flows. + */ +nsIFrame::ReflowStatus +nsTableOuterFrame::ReflowChild( nsIFrame* aKidFrame, + nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize, + OuterTableReflowState& aState) +{ + ReflowStatus status; + + /* call the appropriate reflow method based on the type and position of the child */ +// if (((nsSplittableFrame*)aKidFrame)->GetFirstInFlow()!=mInnerTableFrame) + if (PR_TRUE==aState.processingCaption) + { // it's a caption, find out if it's top or bottom + // Resolve style + nsIStyleContext* captionStyleContext = aKidFrame->GetStyleContext(aPresContext); + NS_ASSERTION(nsnull != captionStyleContext, "null style context for caption"); + nsStyleMolecule* captionStyle = + (nsStyleMolecule*)captionStyleContext->GetData(kStyleMoleculeSID); + NS_ASSERTION(nsnull != captionStyle, "null style molecule for caption"); + if (NS_STYLE_VERTICAL_ALIGN_BOTTOM==captionStyle->verticalAlign) + status = ResizeReflowBottomCaptionsPass2(aPresContext, aDesiredSize, + aMaxSize, aMaxElementSize, + aState.mol, aState.y); + else + status = ResizeReflowTopCaptionsPass2(aPresContext, aDesiredSize, + aMaxSize, aMaxElementSize, + aState.mol); + } + else + status = ((nsTableFrame*)aKidFrame)->ResizeReflowPass2(aPresContext, aDesiredSize, aState.innerTableMaxSize, + aMaxElementSize, aState.mol, + mMinCaptionWidth, mMaxCaptionWidth); + + if (frComplete == status) { + nsIFrame* kidNextInFlow = aKidFrame->GetNextInFlow(); + if (nsnull != kidNextInFlow) { + // Remove all of the childs next-in-flows. Make sure that we ask + // the right parent to do the removal (it's possible that the + // parent is not this because we are executing pullup code) + nsTableOuterFrame* parent = (nsTableOuterFrame*) + aKidFrame->GetGeometricParent(); + parent->DeleteChildsNextInFlow(aKidFrame); + } + } + return status; +} + +void nsTableOuterFrame::CreateChildFrames(nsIPresContext* aPresContext) +{ + nsIFrame *prevKidFrame = nsnull; + nsresult frameCreated = nsTableFrame::NewFrame((nsIFrame **)(&mInnerTableFrame), mContent, 0, this); + if (NS_OK!=frameCreated) + return; // SEC: an error!!!! + // Resolve style + nsIStyleContext* kidStyleContext = + aPresContext->ResolveStyleContextFor(mContent, this); + NS_ASSERTION(nsnull!=kidStyleContext, "bad style context for kid."); + mInnerTableFrame->SetStyleContext(kidStyleContext); + mChildCount++; + // Link child frame into the list of children + mFirstChild = mInnerTableFrame; + prevKidFrame = mInnerTableFrame; + + // now create the caption frames, prepending top captions and + // appending bottom captions + mCaptionFrames = new nsVoidArray(); + // create caption frames as needed + nsIFrame *lastTopCaption = nsnull; + for (PRInt32 kidIndex=0; /* nada */ ;kidIndex++) { + nsIContent* caption = mContent->ChildAt(kidIndex); // caption: REFCNT++ + if (nsnull == caption) { + break; + } + const PRInt32 contentType = ((nsTableContent *)caption)->GetType(); + if (contentType==nsITableContent::kTableCaptionType) + { + nsIFrame *captionFrame=nsnull; + frameCreated = nsTableCaptionFrame::NewFrame(&captionFrame, caption, 0, this); + if (NS_OK!=frameCreated) + return; // SEC: an error!!!! + // Resolve style + nsIStyleContext* captionStyleContext = + aPresContext->ResolveStyleContextFor(caption, this); + NS_ASSERTION(nsnull!=captionStyleContext, "bad style context for caption."); + nsStyleMolecule* captionStyle = + (nsStyleMolecule*)captionStyleContext->GetData(kStyleMoleculeSID); + captionFrame->SetStyleContext(captionStyleContext); + mChildCount++; + // Link child frame into the list of children + if (NS_STYLE_VERTICAL_ALIGN_BOTTOM==captionStyle->verticalAlign) + { // bottom captions get added to the end of the outer frame child list + prevKidFrame->SetNextSibling(captionFrame); + prevKidFrame = captionFrame; + // bottom captions get remembered in an instance variable for easy access later + if (nsnull==mBottomCaptions) + { + mBottomCaptions = new nsVoidArray(); + } + mBottomCaptions->AppendElement(captionFrame); + } + else + { // top captions get prepended to the outer frame child list + if (nsnull == lastTopCaption) + { // our first top caption, therefore our first child + mFirstChild = captionFrame; + mFirstChild->SetNextSibling(mInnerTableFrame); + } + else + { // just another grub in the brood of top captions + lastTopCaption->SetNextSibling(captionFrame); + lastTopCaption = captionFrame; + } + lastTopCaption = captionFrame; + } + mCaptionFrames->AppendElement(captionFrame); + NS_RELEASE(caption); // caption: REFCNT-- + } + else + { + NS_RELEASE(caption); // caption: REFCNT-- + break; + } + } +} + + +nsIFrame::ReflowStatus +nsTableOuterFrame::ResizeReflowCaptionsPass1(nsIPresContext* aPresContext, nsStyleMolecule* aTableStyle) +{ + if (nsnull!=mCaptionFrames) + { + PRInt32 numCaptions = mCaptionFrames->Count(); + for (PRInt32 captionIndex = 0; captionIndex < numCaptions; captionIndex++) + { + nsSize maxElementSize(0,0); + nsSize maxSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); + nsReflowMetrics desiredSize; + nsTableCaptionFrame *captionFrame = (nsTableCaptionFrame *)mCaptionFrames->ElementAt(captionIndex); + captionFrame->ResizeReflow(aPresContext, desiredSize, maxSize, &maxElementSize); + if (mMinCaptionWidthVerticallyAlignChild(aPresContext); + + } + } + return frComplete; +} + +nsIFrame::ReflowStatus +nsTableOuterFrame::ResizeReflowTopCaptionsPass2(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize, + nsStyleMolecule* aTableStyle) +{ + ReflowStatus result = frComplete; + nscoord topCaptionY = 0; + if (nsnull!=mCaptionFrames) + { + PRInt32 numCaptions = mCaptionFrames->Count(); + for (PRInt32 captionIndex = 0; captionIndex < numCaptions; captionIndex++) + { + // get the caption + nsTableCaptionFrame *captionFrame = (nsTableCaptionFrame *)mCaptionFrames->ElementAt(captionIndex); + + // Resolve style + nsIStyleContext* captionStyleContext = captionFrame->GetStyleContext(aPresContext); + NS_ASSERTION(nsnull != captionStyleContext, "null style context for caption"); + nsStyleMolecule* captionStyle = + (nsStyleMolecule*)captionStyleContext->GetData(kStyleMoleculeSID); + NS_ASSERTION(nsnull != captionStyle, "null style molecule for caption"); + + if (NS_STYLE_VERTICAL_ALIGN_BOTTOM==captionStyle->verticalAlign) + { + } + else + { // top-align captions, the default + // reflow the caption, skipping top captions after the first that doesn't fit + if (frComplete==result) + { + nsReflowMetrics desiredSize; + result = nsContainerFrame::ReflowChild(captionFrame, aPresContext, desiredSize, aMaxSize, nsnull); + // place the caption + captionFrame->SetRect(nsRect(0, topCaptionY, desiredSize.width, desiredSize.height)); + if (NS_UNCONSTRAINEDSIZE!=desiredSize.height) + topCaptionY += desiredSize.height; + else + topCaptionY = NS_UNCONSTRAINEDSIZE; + mInnerTableFrame->MoveTo(0, topCaptionY); + if (0==captionFrame->GetIndexInParent()) + { + SetFirstContentOffset(captionFrame); + if (gsDebug) printf("OUTER: set first content offset to %d\n", GetFirstContentOffset()); //@@@ + } + } + // else continue on, so we can build the mBottomCaptions list + } + } + } + aDesiredSize.width = aMaxSize.width; + aDesiredSize.height = topCaptionY; + if (nsnull!=aMaxElementSize) + { // SEC: this isn't right + aMaxElementSize->width = aMaxSize.width; + aMaxElementSize->height = topCaptionY; + } + return result; +} + +nsIFrame::ReflowStatus +nsTableOuterFrame::ResizeReflowBottomCaptionsPass2(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize, + nsStyleMolecule* aTableStyle, + nscoord aYOffset) +{ + ReflowStatus result = frComplete; + nscoord bottomCaptionY = aYOffset; + // for now, assume all captions are stacked vertically + if (nsnull!=mBottomCaptions) + { + PRInt32 numCaptions = mBottomCaptions->Count(); + for (PRInt32 captionIndex = 0; captionIndex < numCaptions; captionIndex++) + { + // get the caption + nsTableCaptionFrame *captionFrame = (nsTableCaptionFrame *)mBottomCaptions->ElementAt(captionIndex); + + // Resolve style +/* + nsIStyleContext* captionStyleContext = captionFrame->GetStyleContext(aPresContext); + NS_ASSERTION(nsnull != captionStyleContext, "null style context for caption"); + nsStyleMolecule* captionStyle = + (nsStyleMolecule*)captionStyleContext->GetData(kStyleMoleculeSID); + NS_ASSERTION(nsnull != captionStyle, "null style molecule for caption"); +*/ + // reflow the caption + nsReflowMetrics desiredSize; + result = nsContainerFrame::ReflowChild(captionFrame, aPresContext, desiredSize, aMaxSize, nsnull); + + // place the caption + nsRect rect = captionFrame->GetRect(); + rect.y = bottomCaptionY; + rect.width=desiredSize.width; + rect.height=desiredSize.height; + captionFrame->SetRect(rect); + if (NS_UNCONSTRAINEDSIZE!=desiredSize.height) + bottomCaptionY += desiredSize.height; + else + bottomCaptionY = NS_UNCONSTRAINEDSIZE; + } + } + aDesiredSize.width = aMaxSize.width; + aDesiredSize.height = bottomCaptionY-aYOffset; + if (nsnull!=aMaxElementSize) + { // SEC: not right + aMaxElementSize->width = aMaxSize.width; + aMaxElementSize->height = bottomCaptionY-aYOffset; + } + return result; +} + +/** + * Sets the last content offset based on the last child frame. If the last + * child is a pseudo frame then it sets mLastContentIsComplete to be the same + * as the last child's mLastContentIsComplete + */ +/* +void nsTableOuterFrame::SetLastContentOffset(const nsIFrame* aLastChild) +{ + NS_PRECONDITION(nsnull != aLastChild, "bad argument"); + NS_PRECONDITION(aLastChild->GetGeometricParent() == this, "bad geometric parent"); + + if (ChildIsPseudoFrame(aLastChild)) { + nsContainerFrame* pseudoFrame = (nsContainerFrame*)aLastChild; + mLastContentOffset = pseudoFrame->GetLastContentOffset(); + mLastContentIsComplete = pseudoFrame->GetLastContentIsComplete(); + } else { + mLastContentOffset = aLastChild->GetIndexInParent(); + } +#ifdef NS_DEBUG + if (mLastContentOffset < mFirstContentOffset) { + nsIFrame* top = this; + while (top->GetGeometricParent() != nsnull) { + top = top->GetGeometricParent(); + } + top->List(); + } +#endif + // it is this next line that forces us to re-implement this method here + //NS_ASSERTION(mLastContentOffset >= mFirstContentOffset, "unexpected content mapping"); +} +*/ + +nsIFrame::ReflowStatus +nsTableOuterFrame::IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand) +{ + if (gsDebug == PR_TRUE) printf("nsTableOuterFrame::IncrementalReflow\n"); + // total hack for now, just some hard-coded values + ResizeReflow(aPresContext, aDesiredSize, aMaxSize, nsnull); + + return frComplete; +} + +nsIFrame* nsTableOuterFrame::CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent) +{ + nsTableOuterFrame* cf = new nsTableOuterFrame(mContent, mIndexInParent, aParent); + PrepareContinuingFrame(aPresContext, aParent, cf); + cf->SetFirstPassValid(PR_TRUE); + printf("nsTableOuterFrame::CCF parent = %p, this=%p, cf=%p\n", aParent, this, cf); + return cf; +} + +void nsTableOuterFrame::PrepareContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent, + nsTableOuterFrame* aContFrame) +{ + // Append the continuing frame to the flow + aContFrame->AppendToFlow(this); + + // Initialize it's content offsets. Note that we assume for now that + // the continuingFrame will map the remainder of the content and + // that therefore mLastContentIsComplete will be true. + PRInt32 nextOffset; + if (mChildCount > 0) { + nextOffset = mLastContentOffset; + if (mLastContentIsComplete) { + nextOffset++; + } + } else { + nextOffset = mFirstContentOffset; + } + + aContFrame->SetFirstContentOffset(nextOffset); + aContFrame->SetLastContentOffset(nextOffset); + aContFrame->SetLastContentIsComplete(PR_TRUE); + + // Resolve style for the continuing frame and set its style context. + // XXX presumptive + nsIStyleContext* styleContext = + aPresContext->ResolveStyleContextFor(mContent, aParent); + aContFrame->SetStyleContext(styleContext); + NS_RELEASE(styleContext); +} + +void nsTableOuterFrame::VerifyTree() const +{ +#ifdef NS_DEBUG + +#endif +} + +void nsTableOuterFrame::CreateInnerTableFrame(nsIPresContext* aPresContext) +{ + // Do we have a prev-in-flow? + if (nsnull == mPrevInFlow) { + // No, create a column pseudo frame + mInnerTableFrame = new nsTableFrame(mContent, mIndexInParent, this); + mChildCount++; + + // Resolve style and set the style context + nsIStyleContext* styleContext = + aPresContext->ResolveStyleContextFor(mContent, this); + mInnerTableFrame->SetStyleContext(styleContext); + NS_RELEASE(styleContext); + } else { + nsTableOuterFrame* prevOuterTable = (nsTableOuterFrame*)mPrevInFlow; + + nsIFrame* prevInnerTable = prevOuterTable->mInnerTableFrame; + + // Create a continuing column + mInnerTableFrame = (nsTableFrame *)prevInnerTable->GetNextInFlow(); + if (nsnull==mInnerTableFrame) + { + mInnerTableFrame = (nsTableFrame *)prevInnerTable->CreateContinuingFrame(aPresContext, this); + mChildCount++; + } + } +} + +/* ----- static methods ----- */ + +nsresult nsTableOuterFrame::NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIFrame* it = new nsTableOuterFrame(aContent, aIndexInParent, aParent); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aInstancePtrResult = it; + return NS_OK; +} diff --git a/mozilla/layout/html/table/src/nsTableOuterFrame.h b/mozilla/layout/html/table/src/nsTableOuterFrame.h new file mode 100644 index 00000000000..cf5c2c9f9ad --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableOuterFrame.h @@ -0,0 +1,197 @@ +/* -*- 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. + */ +#ifndef nsTableOuterFrame_h__ +#define nsTableOuterFrame_h__ + +#include "nscore.h" +#include "nsContainerFrame.h" + +class nsTableFrame; +class nsVoidArray; +struct nsStyleMolecule; +class nsTableCaptionFrame; +struct OuterTableReflowState; + +/** + * nsTableOuterFrame + * main frame for an nsTable content object. + * the nsTableOuterFrame contains 0 or more nsTableCaptionFrames, + * and a single nsTableFrame psuedo-frame. + * + * @author sclark + */ +class nsTableOuterFrame : public nsContainerFrame +{ +public: + static nsresult NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + virtual void Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + + ReflowStatus IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand); + + /** + * @see nsContainerFrame + */ + virtual nsIFrame* CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent); + /** destructor */ + virtual ~nsTableOuterFrame(); + +protected: + + /** constructor */ + nsTableOuterFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + /** return PR_TRUE if the table needs to be reflowed. + * the outer table needs to be reflowed if the table content has changed, + * or if the combination of table style attributes and max height/width have + * changed. + */ + virtual PRBool NeedsReflow(const nsSize& aMaxSize); + + /** returns PR_TRUE if the data obtained from the first reflow pass + * is cached and still valid (ie, no content or style change notifications.) + */ + virtual PRBool IsFirstPassValid(); + + /** setter for mFirstPassValid. + * should be called with PR_FALSE when: + * content changes, style changes, or context changes + */ + virtual void SetFirstPassValid(PRBool aValidState); + + /** create all child frames for this table */ + virtual void CreateChildFrames(nsIPresContext* aPresContext); + + /** reflow the captions in an infinite space, caching the min/max sizes for each + */ + virtual ReflowStatus ResizeReflowCaptionsPass1(nsIPresContext* aPresContext, + nsStyleMolecule* aTableStyle); + + /** reflow the top captions in a space constrained by the computed table width + * and the heigth given to us by our parent. Top captions are laid down + * before the inner table. + */ + virtual ReflowStatus ResizeReflowTopCaptionsPass2(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize, + nsStyleMolecule* aTableStyle); + + /** reflow the bottom captions in a space constrained by the computed table width + * and the heigth given to us by our parent. Bottom captions are laid down + * after the inner table. + */ + virtual ReflowStatus ResizeReflowBottomCaptionsPass2(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize, + nsStyleMolecule* aTableStyle, + nscoord aYOffset); + + nscoord GetTopMarginFor(nsIPresContext* aCX, + OuterTableReflowState& aState, + nsStyleMolecule* aKidMol); + + void PlaceChild( nsIPresContext* aPresContext, + OuterTableReflowState& aState, + nsIFrame* aKidFrame, + const nsRect& aKidRect, + nsStyleMolecule* aKidMol, + nsSize* aMaxElementSize, + nsSize& aKidMaxElementSize); + + PRBool ReflowMappedChildren(nsIPresContext* aPresContext, + OuterTableReflowState& aState, + nsSize* aMaxElementSize); + + PRBool PullUpChildren(nsIPresContext* aPresContext, + OuterTableReflowState& aState, + nsSize* aMaxElementSize); + + virtual void SetReflowState(OuterTableReflowState& aState, + nsIFrame* aKidFrame); + + virtual nsIFrame::ReflowStatus ReflowChild( nsIFrame* aKidFrame, + nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize, + OuterTableReflowState& aState); + + /** + * Sets the last content offset based on the last child frame. If the last + * child is a pseudo frame then it sets mLastContentIsComplete to be the same + * as the last child's mLastContentIsComplete + */ + //virtual void SetLastContentOffset(const nsIFrame* aLastChild); + + /** + * See nsContainerFrame::VerifyTree + */ + virtual void VerifyTree() const; + + /** + * See nsContainerFrame::PrepareContinuingFrame + */ + virtual void PrepareContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent, + nsTableOuterFrame* aContFrame); + + /** + */ + virtual void CreateInnerTableFrame(nsIPresContext* aPresContext); + + +private: + /** used to keep track of this frame's children */ + nsTableFrame *mInnerTableFrame; + nsVoidArray * mCaptionFrames; + nsVoidArray * mBottomCaptions; + + /** used to keep track of min/max caption requirements */ + PRInt32 mMinCaptionWidth; + PRInt32 mMaxCaptionWidth; + + /** used to cache reflow results so we can optimize out reflow in some circumstances */ + nsReflowMetrics mDesiredSize; + nsSize mMaxElementSize; + + /** we can skip the first pass on captions if mFirstPassValid is true */ + PRBool mFirstPassValid; + +}; + + + +#endif diff --git a/mozilla/layout/html/table/src/nsTablePart.cpp b/mozilla/layout/html/table/src/nsTablePart.cpp new file mode 100644 index 00000000000..a978ae98eee --- /dev/null +++ b/mozilla/layout/html/table/src/nsTablePart.cpp @@ -0,0 +1,1010 @@ +/* -*- 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 "nsTablePart.h" +#include "nsTableOuterFrame.h" +#include "nsITableContent.h" +#include "nsTableCol.h" +#include "nsTableColGroup.h" +#include "nsTableRowGroup.h" +#include "nsTableCaption.h" +#include "nsTableRow.h" +#include "nsTableCell.h" +#include "nsCellMap.h" +#include "nsHTMLParts.h" +#include "nsIPresContext.h" +#include "nsContainerFrame.h" +#include "nsIRenderingContext.h" +#include "nsHTMLIIDs.h" +#include "nsIAtom.h" + +static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); +static NS_DEFINE_IID(kITableContentIID, NS_ITABLECONTENT_IID); + +#ifdef NS_DEBUG +static PRBool gsDebug = PR_FALSE; +static PRBool gsNoisyRefs = PR_FALSE; +#else +static const PRBool gsDebug = PR_FALSE; +static const PRBool gsNoisyRefs = PR_FALSE; +#endif + +const char *nsTablePart::kCaptionTagString="CAPTION"; +const char *nsTablePart::kRowGroupBodyTagString="TBODY"; +const char *nsTablePart::kRowGroupHeadTagString="THEAD"; +const char *nsTablePart::kRowGroupFootTagString="TFOOT"; +const char *nsTablePart::kRowTagString="TR"; +const char *nsTablePart::kColGroupTagString="COLGROUP"; +const char *nsTablePart::kColTagString="COL"; +const char *nsTablePart::kDataCellTagString="TD"; +const char *nsTablePart::kHeaderCellTagString="TH"; + +CellData::CellData() +{ + mCell = nsnull; + mRealCell = nsnull; + mOverlap = nsnull; +} + +CellData::~CellData() +{} + + +/*---------- nsTablePart implementation -----------*/ + +/** + * + * BUGS: + *
      + *
    • Enabling css1 margins on tables, rows, cells causes things to not + * fit. why? + *
    • centering (etc.) is leaking into table cell's from the outer environment + *
    + * + * TODO: + *
      + *
    • as table border gets wider, the table gets narrower (somebody is over + * subtracting the table border. + *
    • colspan creating empty cells on rows w/o matching cells + *
    • draw table borders ala navigator + *
    • border sizing + *
    • bordercolor + *
    • draw cell borders ala navigator + *
    • cellspacing + *
    • colspan not the last cell + *
    • rowspan + *
    • floaters in table cells + *
        + *
      • rowspan truncation (rowspan sticking out past the bottom of the table) + *
      • effect on subsequent row structure + *
      + *
    • eliminate TableRow and TableRowLayoutDelegate's + *
    • inherit table border color ala nav4 (use inherited text color) when + * the border is enabled and the bordercolor value nsnull. + *
    + * + * HTML4: + *
      + *
    • borders + *
    • table frame + *
    • colgroup + *
    • col + *
    • thead, tfoot, tbody + *
    + * + * CSS1: + *
      + *
    • table margin + *
    • table border-width + *
    • table padding + *
    • row margin + *
    • row border-width + *
    • row padding + *
    • cell margin + *
    • cell border-width + *
    • cell padding + *
    • what about colgroup, thead, tbody, tfoot margin/border-width/padding? + *
    • map css1 style (borders, padding, margins) in some sensible manner + *
    + * + * CSS2: + *
      + *
    • watch it + *
    + * + * Eventually: + *
      + *
    • splitting tables across pages + *
    + * + * And the hardest of all: + *
      + *
    • column sizing + *
    + */ + +/** constructor + * I do not addref aTag because my superclass does that for me + */ +nsTablePart::nsTablePart(nsIAtom* aTag) + : nsHTMLContainer(aTag), + mColCount(0), + mSpecifiedColCount(0), + mCellMap(0) +{ +} + +/** constructor + * I do not addref aTag because my superclass does that for me + */ +nsTablePart::nsTablePart (nsIAtom* aTag, int aColumnCount) + : nsHTMLContainer(aTag), + mColCount(aColumnCount), + mSpecifiedColCount(0), + mCellMap(0) +{ +} + +/** + */ +nsTablePart::~nsTablePart() +{ + if (nsnull!=mCellMap) + { + delete mCellMap; + } +} + +/** + */ +/* +nsTablePart::void compact() { + compact(); +} +*/ + +nsrefcnt nsTablePart::AddRef(void) +{ + if (gsNoisyRefs==PR_TRUE) printf("Add Ref: nsTablePart cnt = %d \n",mRefCnt+1); + return ++mRefCnt; +} + +nsrefcnt nsTablePart::Release(void) +{ + if (gsNoisyRefs==PR_TRUE) printf("Release: nsTablePart cnt = %d \n",mRefCnt-1); + if (--mRefCnt == 0) { + if (gsNoisyRefs==PR_TRUE) printf("Delete: nsTablePart \n"); + delete this; + return 0; + } + return mRefCnt; +} + +/** + */ +int nsTablePart::GetMaxColumns () +{ + if (nsnull == mCellMap) + { + BuildCellMap (); + } + return mColCount; +} + + // XXX what do rows with no cells turn into? +/** + */ +int nsTablePart::GetRowCount () +{ + if (nsnull != mCellMap) + return mCellMap->GetRowCount(); + + int rowCount = 0; + int index = ChildCount (); + while (0 < index) + { + nsIContent *child = ChildAt (--index); // child: REFCNT++ + nsTableContent *tableContent = (nsTableContent *)child; + const int contentType = tableContent->GetType(); + if (contentType == nsITableContent::kTableRowGroupType) + rowCount += ((nsTableRowGroup *)tableContent)->GetRowCount (); + NS_RELEASE(child); // child: REFCNT-- + } + return rowCount; +} + +/** counts columns in column groups + */ +int nsTablePart::GetSpecifiedColumnCount () +{ + if (mSpecifiedColCount < 0) + { + mSpecifiedColCount = 0; + int count = ChildCount (); + for (int index = 0; index < count; index++) + { + nsIContent *child = ChildAt (index); // child: REFCNT++ + nsTableContent *tableContent = (nsTableContent *)child; + const int contentType = tableContent->GetType(); + if (contentType == nsITableContent::kTableColGroupType) + { + ((nsTableColGroup *)tableContent)->SetStartColumnIndex (mSpecifiedColCount); + mSpecifiedColCount += ((nsTableColGroup *)tableContent)->GetColumnCount (); + } + NS_RELEASE(child); // child: REFCNT-- + } + } + return mSpecifiedColCount; +} + + +nsCellMap* nsTablePart::GetCellMap() const +{ + return mCellMap; +} + + +/** + */ +void nsTablePart::ResetCellMap () +{ + if (mCellMap) + delete mCellMap; + mCellMap = nsnull; // for now, will rebuild when needed +} + +/** + */ +void nsTablePart::ResetColumns () +{ + mSpecifiedColCount = -1; + if (nsnull != mCellMap) + { + int colCount = GetSpecifiedColumnCount (); + GrowCellMap (colCount); // make sure we're at least as big as specified columns + } + else + mColCount = 0; // we'll compute later (as part of building cell map) +} + +/** sum the columns represented by all nsTableColGroup objects + * if the cell map says there are more columns than this, + * add extra implicit columns to the content tree. + */ +void nsTablePart::EnsureColumns() +{ + if (nsnull!=mCellMap) + { + PRInt32 actualColumns = 0; + PRInt32 numColGroups = ChildCount(); + nsTableColGroup *lastColGroup = nsnull; + for (PRInt32 colGroupIndex = 0; colGroupIndex < numColGroups; colGroupIndex++) + { + nsTableContent *colGroup = (nsTableContent*)ChildAt(colGroupIndex); // colGroup: REFCNT++ + const int contentType = colGroup->GetType(); + if (contentType==nsTableContent::kTableColGroupType) + { + PRInt32 numCols = ((nsTableColGroup *)colGroup)->GetColumnCount(); + actualColumns += numCols; + lastColGroup = (nsTableColGroup *)colGroup; + NS_RELEASE(colGroup); + } + else if (contentType==nsTableContent::kTableRowGroupType) + { + NS_RELEASE(colGroup); + break; + } + } + if (actualColumns < mCellMap->GetColCount()) + { + if (nsnull==lastColGroup) + { + lastColGroup = new nsTableColGroup (PR_TRUE); + AppendColGroup(lastColGroup); + } + PRInt32 excessColumns = mCellMap->GetColCount() - actualColumns; + for ( ; excessColumns > 0; excessColumns--) + { + nsTableCol *col = new nsTableCol(PR_TRUE); + lastColGroup->AppendChild (col); + } + } + } +} + +/** + */ +void nsTablePart::ReorderChildren() +{ + NS_ASSERTION(PR_FALSE, "not yet implemented."); +} + +void nsTablePart::NotifyContentComplete() +{ + // set the children in order + ReorderChildren(); +} + +/** add a child to the table content. + * tables are special because they require the content to be normalized, in order. + * so this function doesn't really "append" the content, but adds it in the proper place, + * possibly nested inside of implicit parents. + * order is: + * Captions (optional) + * Column Groups (1 or more, possibly implicit) + * Row Groups + * THEADs (optional) + * TFOOTs (optional) + * TBODY (at least 1, possibly implicit) + * + * should be broken out into separate functions! + */ +PRBool nsTablePart::AppendChild (nsIContent * aContent) +{ + PRBool result = PR_FALSE; + PRBool newCells = PR_FALSE; + PRBool contentHandled = PR_FALSE; + + // wait, stop! need to check to see if this is really tableContent or not! + nsITableContent *tableContentInterface = nsnull; + nsresult rv = aContent->QueryInterface(kITableContentIID, + (void **)&tableContentInterface); // tableContentInterface: REFCNT++ + if (NS_FAILED(rv)) + { // create an implicit cell and return the result of adding it to the table + if (gsDebug==PR_TRUE) + printf ("*** bad HTML in table, not yet implemented.\n"); + return PR_FALSE; + } + else + { + nsTableContent *tableContent = (nsTableContent *)tableContentInterface; + const int contentType = tableContent->GetType(); + if ((contentType == nsITableContent::kTableCellType) || + (contentType==nsITableContent::kTableRowType)) + { + if (gsDebug==PR_TRUE) + { + if (contentType == nsITableContent::kTableRowType) + printf ("nsTablePart::AppendChild -- adding a row.\n"); + else + printf ("nsTablePart::AppendChild -- adding a cell.\n"); + } + // find last row group, if ! implicit, make one, append there + nsTableRowGroup *group = nsnull; + int index = ChildCount (); + while ((0 < index) && (nsnull==group)) + { + nsIContent *child = ChildAt (--index); // child: REFCNT++ + if (nsnull != child) + { + nsTableContent * content = (nsTableContent *)child; + if (content->GetType()==nsITableContent::kTableRowGroupType) + { + group = (nsTableRowGroup *)content; + NS_ADDREF(group); // group: REFCNT++ + } + } + NS_RELEASE(child); // child: REFCNT-- + } + if ((nsnull == group) || (! group->IsImplicit ())) + { + if (gsDebug==PR_TRUE) printf ("nsTablePart::AppendChild -- creating an implicit row group.\n"); + nsIAtom * rowGroupTag = NS_NewAtom(kRowGroupBodyTagString); // rowGroupTag: REFCNT++ + group = new nsTableRowGroup (rowGroupTag, PR_TRUE); + NS_ADDREF(group); // group: REFCNT++ + AppendChild (group); + NS_RELEASE(rowGroupTag); // rowGroupTag: REFCNT-- + } + // group is guaranteed to be allocated at this point + result = group->AppendChild(aContent); + newCells = result; + contentHandled = PR_TRUE; + NS_RELEASE(group); // group: REFCNT-- + } + else if (contentType == nsITableContent::kTableColType) + { + result = AppendColumn((nsTableCol *)aContent); + newCells = result; + contentHandled = PR_TRUE; + } + else if (contentType == nsITableContent::kTableCaptionType) + { + result = AppendCaption((nsTableCaption *)aContent); + contentHandled = PR_TRUE; // whether we succeeded or not, we've "handled" this request + } + else if (contentType == nsITableContent::kTableRowGroupType) + { + result = AppendRowGroup((nsTableRowGroup *)aContent); + if (PR_TRUE==result) + { + newCells = PR_TRUE; + } + contentHandled = PR_TRUE; // whether we succeeded or not, we've "handled" this request + } + else if (contentType == nsITableContent::kTableColGroupType) + { + result = AppendColGroup((nsTableColGroup *)aContent); + if (PR_TRUE==result) + { + newCells = PR_TRUE; + } + contentHandled = PR_TRUE; // whether we succeeded or not, we've "handled" this request + } + /* if aContent is not a known content type, make a capion out of it */ + // SEC the logic here is very suspicious!!!! + if (PR_FALSE==contentHandled) + { + if (gsDebug==PR_TRUE) printf ("nsTablePart::AppendChild -- content not handled!!!\n"); + nsTableCaption *caption = nsnull; + nsIContent *lastChild = ChildAt (ChildCount() - 1); // lastChild: REFCNT++ + if (nsnull != lastChild) + { + nsTableContent * content = (nsTableContent *)lastChild; + if (content->GetType()==nsITableContent::kTableCaptionType) + caption = (nsTableCaption *)content; + NS_RELEASE(lastChild); // lastChild: REFCNT-- + } + if ((nsnull == caption) || (! caption->IsImplicit ())) + { + if (gsDebug==PR_TRUE) printf ("nsTablePart::AppendChild -- adding an implicit caption.\n"); + caption = new nsTableCaption (PR_TRUE); + AppendCaption (caption); + } + result = caption->AppendChild (aContent); + } + /* if we added new cells, we need to fix up the cell map */ + if (newCells) + { + ResetCellMap (); + } + } + NS_RELEASE(tableContentInterface); // tableContentInterface: REFCNT-- + return result; +} + +/** + */ + /* SEC: why can we only insertChildAt (captions or groups) ? */ +PRBool nsTablePart::InsertChildAt(nsIContent * aContent, int aIndex) +{ + PRBool result = PR_FALSE; + nsTableContent *tableContent = (nsTableContent *)aContent; + const int contentType = tableContent->GetType(); + if ((contentType == nsITableContent::kTableCaptionType) || + (contentType == nsITableContent::kTableColGroupType) || + (contentType == nsITableContent::kTableRowGroupType)) + { + result = nsHTMLContainer::InsertChildAt (aContent, aIndex); + if (result) + { + tableContent->SetTable (this); + ResetCellMap (); + } + } + return result; +} + +/** + */ +PRBool nsTablePart::ReplaceChildAt (nsIContent *aContent, int aIndex) +{ + PRBool result = PR_FALSE; + nsTableContent *tableContent = (nsTableColGroup *)aContent; + const int contentType = tableContent->GetType(); + if ( (contentType == nsITableContent::kTableCaptionType) || + (contentType == nsITableContent::kTableColGroupType) || + (contentType == nsITableContent::kTableRowGroupType)) + { + nsIContent *lastChild = ChildAt (aIndex);// lastChild: REFCNT++ + result = nsHTMLContainer::ReplaceChildAt (aContent, aIndex); + if (result) + { + if (nsnull != lastChild) + tableContent->SetTable (nsnull); + tableContent->SetTable (this); + ResetCellMap (); + } + NS_IF_RELEASE(lastChild); // lastChild: REFCNT-- + } + return result; +} + +/** + * Remove a child at the given position. The method is ignored if + * the index is invalid (too small or too large). + */ +PRBool nsTablePart::RemoveChildAt (int aIndex) +{ + nsIContent * lastChild = ChildAt (aIndex); // lastChild: REFCNT++ + PRBool result = nsHTMLContainer::RemoveChildAt (aIndex); + if (result) + { + nsTableContent *tableContent = (nsTableColGroup *)lastChild; + const int contentType = tableContent->GetType(); + if (contentType == nsITableContent::kTableRowType) + { + if (nsnull != lastChild) + ((nsTableRow *)tableContent)->SetRowGroup (nsnull); + tableContent->SetTable(nsnull); + ResetCellMap (); + } + } + NS_IF_RELEASE(lastChild); + return result; +} + +/** protected method for appending a column group to this table */ +PRBool nsTablePart::AppendRowGroup (nsTableRowGroup *aContent) +{ + NS_PRECONDITION(nsnull!=aContent, "null arg."); + PRBool result = PR_TRUE; + if (gsDebug==PR_TRUE) + printf ("nsTablePart::AppendRowGroup -- adding a row group.\n"); + // find the last row group of this kind and insert this row group after it + // if there is no row group of this type already in the table, + // find the appropriate slot depending on this row group tag + nsIAtom * rowGroupTag = aContent->GetTag(); + int childCount = ChildCount (); + nsIAtom * tHeadTag = NS_NewAtom(kRowGroupHeadTagString); // tHeadTag: REFCNT++ + nsIAtom * tFootTag = NS_NewAtom(kRowGroupFootTagString); // tFootTag: REFCNT++ + nsIAtom * tBodyTag = NS_NewAtom(kRowGroupBodyTagString); // tBodyTag: REFCNT++ + for (PRInt32 childIndex = 0; childIndex < childCount; childIndex++) + { + nsTableContent *tableChild = (nsTableContent *)ChildAt(childIndex); // tableChild: REFCNT++ + const int tableChildType = tableChild->GetType(); + if ((tableChildType == nsITableContent::kTableCaptionType) || + (tableChildType == nsITableContent::kTableColGroupType)) + { + NS_RELEASE(tableChild); // tableChild: REFCNT-- (a) + continue; + } + else if (tableChildType == nsITableContent::kTableRowGroupType) + { + nsIAtom * tableChildTag = tableChild->GetTag(); + NS_RELEASE(tableChild); // tableChild: REFCNT-- (b) + if (tHeadTag==rowGroupTag && tHeadTag==tableChildTag) + continue; + else if (tFootTag==rowGroupTag && + tHeadTag==tableChildTag || + tFootTag==tableChildTag) + continue; + else if (tBodyTag==tableChildTag) + continue; + else + break; + } + else + break; + } + NS_RELEASE(tFootTag); + NS_RELEASE(tHeadTag); + NS_RELEASE(tBodyTag); + result = nsHTMLContainer::InsertChildAt(aContent, childIndex); + if (result) + { + ((nsTableContent *)aContent)->SetTable (this); + } + return result; +} + +/** protected method for appending a column group to this table */ +PRBool nsTablePart::AppendColGroup(nsTableColGroup *aContent) +{ + NS_PRECONDITION(nsnull!=aContent, "null arg."); + if (gsDebug==PR_TRUE) + printf ("nsTablePart::AppendColGroup -- adding a column group.\n"); + // find the last column group and insert this column group after it. + // if there is no column group already in the table, make this the first child + // after any caption + int childCount = ChildCount (); + for (PRInt32 childIndex = 0; childIndex < childCount; childIndex++) + { + nsTableContent *tableChild = (nsTableContent *)ChildAt(childIndex); // tableChild: REFCNT++ + const int tableChildType = tableChild->GetType(); + NS_RELEASE(tableChild); // tableChild: REFCNT-- + if (!((tableChildType == nsITableContent::kTableCaptionType) || + (tableChildType == nsITableContent::kTableColGroupType))) + break; + } + PRBool result = nsHTMLContainer::InsertChildAt(aContent, childIndex); + if (result) + { + ((nsTableContent *)aContent)->SetTable (this); + } + // if col group has a SPAN attribute, create implicit columns for the value of SPAN + // what sucks is if we then get a COL for this COLGROUP, we have to delete all the + // COLs we created for SPAN, and just contain the explicit COLs. + PRInt32 span = 0; // SEC: TODO find a way to really get this + for (PRInt32 i=0; iAppendChild (col); + } + + return result; +} + +/** protected method for appending a column group to this table */ +PRBool nsTablePart::AppendColumn(nsTableCol *aContent) +{ + NS_PRECONDITION(nsnull!=aContent, "null arg."); + if (gsDebug==PR_TRUE) + printf ("nsTablePart::AppendColumn -- adding a column.\n"); + // find last col group, if ! implicit, make one, append there + nsTableColGroup *group = nsnull; + PRBool foundColGroup = PR_FALSE; + int index = ChildCount (); + while ((0 < index) && (PR_FALSE==foundColGroup)) + { + nsIContent *child = ChildAt (--index); // child: REFCNT++ + if (nsnull != child) + { + group = (nsTableColGroup *)child; + foundColGroup = (PRBool) + (group->GetType()==nsITableContent::kTableColGroupType); + NS_RELEASE(child); // child: REFCNT-- + } + } + if ((PR_FALSE == foundColGroup) || (! group->IsImplicit ())) + { + if (gsDebug==PR_TRUE) + printf ("nsTablePart::AppendChild -- creating an implicit column group.\n"); + group = new nsTableColGroup (PR_TRUE); + AppendChild (group); + } + PRBool result = group->AppendChild (aContent); + return result; +} + +/** protected method for appending a column group to this table */ +PRBool nsTablePart::AppendCaption(nsTableCaption *aContent) +{ + NS_PRECONDITION(nsnull!=aContent, "null arg."); + if (gsDebug==PR_TRUE) + printf ("nsTablePart::AppendCaption -- adding a caption.\n"); + // find the last caption and insert this caption after it. + // if there is no caption already in the table, make this the first child + int childCount = ChildCount (); + for (PRInt32 childIndex = 0; childIndex < childCount; childIndex++) + { + nsTableContent *tableChild = (nsTableContent *)ChildAt(childIndex); + const int tableChildType = tableChild->GetType(); + NS_RELEASE(tableChild); + if (tableChildType != nsITableContent::kTableCaptionType) + break; + } + PRBool result = nsHTMLContainer::InsertChildAt(aContent, childIndex); + if (PR_TRUE==result) + { + ((nsTableContent *)aContent)->SetTable (this); + } + return result; +} + +/** + */ +int nsTablePart::NextRowGroup (int aStartIndex) +{ + int index = aStartIndex; + int count = ChildCount (); + + while (++index < count) + { + nsIContent * child = ChildAt (index); // child: REFCNT++ + nsTableContent *tableContent = (nsTableColGroup *)child; + const int contentType = tableContent->GetType(); + NS_RELEASE(child); // child: REFCNT-- + if (contentType == nsITableContent::kTableRowGroupType) + return index; + } + return count; +} + +// XXX This should be computed incrementally and updated +// automatically when rows are added/deleted. To do this, however, +// we need to change the way the ContentSink works and somehow +// notify this table when a row is modified. We can give the rows +// parent pointers, but that would bite. + +// XXX nuke this; instead pretend the content sink is working +// incrementally like we want it to and build up the data a row at a +// time. + +void nsTablePart::BuildCellMap () +{ + if (gsDebug==PR_TRUE) printf("Build Cell Map...\n"); + int rowCount = GetRowCount (); + if (0 == rowCount) + { + if (gsDebug==PR_TRUE) printf("0 row count. Returning.\n"); + mColCount = GetSpecifiedColumnCount (); // at least set known column count + EnsureColumns(); + return; + } + + // Make an educated guess as to how many columns we have. It's + // only a guess because we can't know exactly until we have + // processed the last row. + + int childCount = ChildCount (); + int groupIndex = NextRowGroup (-1); + if (0 == mColCount) + mColCount = GetSpecifiedColumnCount (); + if (0 == mColCount) // no column parts + { + nsTableRowGroup *rowGroup = (nsTableRowGroup*)(ChildAt (groupIndex)); // rowGroup: REFCNT++ + nsTableRow *row = (nsTableRow *)(rowGroup->ChildAt (0)); // row: REFCNT++ + mColCount = row->GetMaxColumns (); + if (gsDebug==PR_TRUE) printf("mColCount=0 at start. Guessing col count to be %d from a row.\n", mColCount); + NS_RELEASE(rowGroup); // rowGroup: REFCNT-- + NS_RELEASE(row); // row: REFCNT-- + } + if (nsnull==mCellMap) + mCellMap = new nsCellMap(rowCount, mColCount); + else + mCellMap->Reset(rowCount, mColCount); + if (gsDebug==PR_TRUE) printf("mCellMap set to (%d, %d)\n", rowCount, mColCount); + int rowStart = 0; + if (gsDebug==PR_TRUE) printf("childCount is %d\n", childCount); + while (groupIndex < childCount) + { + if (gsDebug==PR_TRUE) printf(" groupIndex is %d\n", groupIndex); + if (gsDebug==PR_TRUE) printf(" rowStart is %d\n", rowStart); + nsTableRowGroup *rowGroup = (nsTableRowGroup *)ChildAt (groupIndex); // rowGroup: REFCNT++ + int groupRowCount = rowGroup->ChildCount (); + if (gsDebug==PR_TRUE) printf(" groupRowCount is %d\n", groupRowCount); + for (int rowIndex = 0; rowIndex < groupRowCount; rowIndex++) + { + nsTableRow *row = (nsTableRow *)(rowGroup->ChildAt (rowIndex)); // row: REFCNT++ + int cellCount = row->ChildCount (); + int cellIndex = 0; + int colIndex = 0; + if (gsDebug==PR_TRUE) + DumpCellMap(); + if (gsDebug==PR_TRUE) printf(" rowIndex is %d, row->SetRowIndex(%d)\n", rowIndex, rowIndex + rowStart); + row->SetRowIndex (rowIndex + rowStart); + while (colIndex < mColCount) + { + if (gsDebug==PR_TRUE) printf(" colIndex = %d, with mColCount = %d\n", colIndex, mColCount); + CellData *data =mCellMap->GetCellAt(rowIndex + rowStart, colIndex); + if (nsnull == data) + { + if (gsDebug==PR_TRUE) printf(" null data from GetCellAt(%d,%d)\n", rowIndex+rowStart, colIndex); + if (gsDebug==PR_TRUE) printf(" cellIndex=%d, cellCount=%d)\n", cellIndex, cellCount); + if (cellIndex < cellCount) + { + nsTableCell* cell = (nsTableCell *) row->ChildAt (cellIndex); // cell: REFCNT++ + if (gsDebug==PR_TRUE) printf(" calling BuildCellIntoMap(cell, %d, %d), and incrementing cellIndex\n", rowIndex + rowStart, colIndex); + BuildCellIntoMap (cell, rowIndex + rowStart, colIndex); + NS_RELEASE(cell); // cell: REFCNT-- + cellIndex++; + } + } + colIndex++; + } + + // SEC: this whole next if block is very suspicious. + + if (cellIndex < cellCount) + { + // We didn't use all the cells in this row up. Grow the cell + // data because we now know that we have more columns than we + // originally thought we had. + if (gsDebug==PR_TRUE) printf(" calling GrowCellMap because cellIndex < %d\n", cellIndex, cellCount); + GrowCellMap (cellCount); + while (cellIndex < cellCount) + { + if (gsDebug==PR_TRUE) printf(" calling GrowCellMap again because cellIndex < %d\n", cellIndex, cellCount); + GrowCellMap (colIndex + 1); // ensure enough cols in map, may be low due to colspans + CellData *data =mCellMap->GetCellAt(rowIndex + rowStart, colIndex); + if (data == nsnull) + { + nsTableCell* cell = (nsTableCell *) row->ChildAt (cellIndex); // cell: REFCNT++ + BuildCellIntoMap (cell, rowIndex + rowStart, colIndex); + cellIndex++; + NS_RELEASE(cell); // cell: REFCNT-- + } + colIndex++; + } + } + NS_RELEASE(row); // row: REFCNT-- + } + NS_RELEASE(rowGroup); // rowGroup: REFCNT-- + rowStart += groupRowCount; + groupIndex = NextRowGroup (groupIndex); + } + if (gsDebug==PR_TRUE) + DumpCellMap (); + EnsureColumns(); +} + +/** + */ +void nsTablePart::DumpCellMap () const +{ + printf("dumping CellMap:\n"); + if (nsnull != mCellMap) + { + int rowCount = mCellMap->GetRowCount(); + int cols = mCellMap->GetColCount(); + for (int r = 0; r < rowCount; r++) + { + if (gsDebug==PR_TRUE) + { printf("row %d", r); + printf(": "); + } + for (int c = 0; c < cols; c++) + { + CellData *cd =mCellMap->GetCellAt(r, c); + if (cd != nsnull) + { + if (cd->mCell != nsnull) + { + printf("C%d,%d ", r, c); + printf(" "); + } + else + { + nsTableCell *cell = cd->mRealCell->mCell; + nsTableRow *row = cell->GetRow(); + int rr = row->GetRowIndex (); + int cc = cell->GetColIndex (); + printf("S%d,%d ", rr, cc); + if (cd->mOverlap != nsnull) + { + cell = cd->mOverlap->mCell; + nsTableRow* row2 = cell->GetRow(); + rr = row2->GetRowIndex (); + cc = cell->GetColIndex (); + printf("O%d,%c ", rr, cc); + NS_RELEASE(row2); + } + else + printf(" "); + NS_RELEASE(row); + } + } + else + printf("---- "); + } + printf("\n"); + } + } + else + printf ("[nsnull]"); +} + +void nsTablePart::BuildCellIntoMap (nsTableCell *aCell, int aRowIndex, int aColIndex) +{ + //SEC Assert.Assertion (aColIndex < mColCount); + //SEC Assert.Assertion (nsnull!=aCell); + + // Setup CellMap for this cell + int rowSpan = GetEffectiveRowSpan (aRowIndex, aCell); + int colSpan = aCell->GetColSpan (); + if (gsDebug==PR_TRUE) printf(" BuildCellIntoMap. rowSpan = %d, colSpan = %d\n", rowSpan, colSpan); + + // Grow the mCellMap array if we will end up addressing + // some new columns. + if (mColCount < (aColIndex + colSpan)) + { + if (gsDebug==PR_TRUE) printf(" mColCount=%dmCell = aCell; + data->mRealCell = data; + if (gsDebug==PR_TRUE) printf(" calling mCellMap->SetCellAt(data, %d, %d)\n", aRowIndex, aColIndex); + mCellMap->SetCellAt(data, aRowIndex, aColIndex); + aCell->SetColIndex (aColIndex); + + // Create CellData objects for the rows that this cell spans. Set + // their mCell to nsnull and their mRealCell to point to data. If + // there were no column overlaps then we could use the same + // CellData object for each row that we span... + if ((1 < rowSpan) || (1 < colSpan)) + { + if (gsDebug==PR_TRUE) printf(" spans\n"); + for (int rowIndex = 0; rowIndex < rowSpan; rowIndex++) + { + if (gsDebug==PR_TRUE) printf(" rowIndex = %d\n", rowIndex); + int workRow = aRowIndex + rowIndex; + if (gsDebug==PR_TRUE) printf(" workRow = %d\n", workRow); + for (int colIndex = 0; colIndex < colSpan; colIndex++) + { + if (gsDebug==PR_TRUE) printf(" colIndex = %d\n", colIndex); + int workCol = aColIndex + colIndex; + if (gsDebug==PR_TRUE) printf(" workCol = %d\n", workCol); + CellData *testData = mCellMap->GetCellAt(workRow, workCol); + if (nsnull == testData) + { + CellData *spanData = new CellData (); + spanData->mRealCell = data; + if (gsDebug==PR_TRUE) printf(" null GetCellAt(%d, %d) so setting to spanData\n", workRow, workCol); + mCellMap->SetCellAt(spanData, workRow, workCol); + } + else if ((0 < rowIndex) || (0 < colIndex)) + { // we overlap, replace existing data, it might be shared + if (gsDebug==PR_TRUE) printf(" overlapping Cell from GetCellAt(%d, %d) so setting to spanData\n", workRow, workCol); + CellData *overlap = new CellData (); + overlap->mCell = testData->mCell; + overlap->mRealCell = testData->mRealCell; + overlap->mOverlap = data; + mCellMap->SetCellAt(overlap, workRow, workCol); + } + } + } + } +} + +void nsTablePart::GrowCellMap (int aColCount) +{ + if (nsnull!=mCellMap) + { + if (mColCount < aColCount) + { + mCellMap->GrowTo(aColCount); + } + mColCount = aColCount; + } +} + +int nsTablePart::GetEffectiveRowSpan (int aRowIndex, nsTableCell *aCell) +{ + //SEC Assert.Assertion (nsnull!=aCell) + int rowSpan = aCell->GetRowSpan (); + int rowCount = GetRowCount (); + if (rowCount < (aRowIndex + rowSpan)) + return (rowCount - aRowIndex); + return rowSpan; +} + + +/** + * Create a frame object that will layout this table. + */ +nsIFrame* nsTablePart::CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + nsIFrame* rv; + nsresult status = nsTableOuterFrame::NewFrame(&rv, this, aIndexInParent, + aParentFrame); + return rv; +} + +/* ---------- Global Functions ---------- */ + +/** + */ +nsresult +NS_NewTablePart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "nsnull ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIHTMLContent* table = new nsTablePart(aTag); + if (nsnull == table) { + return NS_ERROR_OUT_OF_MEMORY; + } + return table->QueryInterface(kIHTMLContentIID, (void **) aInstancePtrResult); +} + diff --git a/mozilla/layout/html/table/src/nsTablePart.h b/mozilla/layout/html/table/src/nsTablePart.h new file mode 100644 index 00000000000..c2775bcf6a5 --- /dev/null +++ b/mozilla/layout/html/table/src/nsTablePart.h @@ -0,0 +1,120 @@ +/* -*- 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. + */ +#ifndef nsTablePart_h___ +#define nsTablePart_h___ + + +// nsTablePart.h +#include "nsHTMLContainer.h" + +// forward declarations +class nsTableCell; +class nsCellMap; +class nsTableRowGroup; +class nsTableColGroup; +class nsTableCol; +class nsTableCaption; + +/** + * if mCell is null then mRealCell will be the rowspan/colspan source + * in addition, if fOverlap is non-null then it will point to the + * other cell that overlaps this position + */ +class CellData +{ +public: + nsTableCell *mCell; + CellData *mRealCell; + CellData *mOverlap; + + CellData(); + + ~CellData(); +}; + +/** + * Table Content Model. + * A Table can contain RowGroups, ColumnGroups, and Captions. + */ +class nsTablePart : public nsHTMLContainer { + +public: + + static const char *nsTablePart::kCaptionTagString; + static const char *nsTablePart::kRowGroupBodyTagString; + static const char *nsTablePart::kRowGroupHeadTagString; + static const char *nsTablePart::kRowGroupFootTagString; + static const char *nsTablePart::kRowTagString; + static const char *nsTablePart::kColGroupTagString; + static const char *nsTablePart::kColTagString; + static const char *nsTablePart::kDataCellTagString; + static const char *nsTablePart::kHeaderCellTagString; + + nsTablePart(nsIAtom* aTag); + nsTablePart(nsIAtom* aTag, int aColumnCount); + + // For debugging purposes only + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + + /* public Table methods */ + virtual void ResetCellMap (); + virtual void ResetColumns (); + virtual void EnsureColumns (); + virtual int GetSpecifiedColumnCount (); + virtual int GetRowCount(); + virtual int GetMaxColumns(); + + /* overrides from nsHTMLContainer */ + virtual PRBool InsertChildAt(nsIContent* aKid, PRInt32 aIndex); + virtual PRBool ReplaceChildAt(nsIContent* aKid, PRInt32 aIndex); + virtual PRBool AppendChild(nsIContent* aKid); + virtual PRBool RemoveChildAt(PRInt32 aIndex); + + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual void NotifyContentComplete(); + +protected: + virtual ~nsTablePart(); + virtual int GetEffectiveRowSpan(int aRowIndex, nsTableCell *aCell); + virtual void BuildCellMap (); + virtual void GrowCellMap(int aColCount); + virtual void BuildCellIntoMap (nsTableCell *aCell, int aRowIndex, int aColIndex); + virtual int NextRowGroup (int aStartIndex); + virtual void ReorderChildren(); + virtual PRBool AppendRowGroup(nsTableRowGroup *aContent); + virtual PRBool AppendColGroup(nsTableColGroup *aContent); + virtual PRBool AppendColumn(nsTableCol *aContent); + virtual PRBool AppendCaption(nsTableCaption *aContent); + +public: + virtual void DumpCellMap() const; + virtual nsCellMap* GetCellMap() const; + +private: + + int mColCount; + int mSpecifiedColCount; + nsCellMap* mCellMap; + static nsIAtom *kDefaultTag; +}; + +#endif // nsTablePart_h___ diff --git a/mozilla/layout/html/table/src/nsTableRow.cpp b/mozilla/layout/html/table/src/nsTableRow.cpp new file mode 100644 index 00000000000..5ee6119ed9b --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableRow.cpp @@ -0,0 +1,262 @@ +/* -*- 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 "nsTableRow.h" +#include "nsTableRowFrame.h" +#include "nsTableRowGroup.h" +#include "nsTableCell.h" +#include "nsTableFrame.h" +#include "nsCellLayoutData.h" +#include "nsHTMLParts.h" +#include "nsHTMLContainer.h" +#include "nsTableRowFrame.h" +#include "nsReflowCommand.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsIContentDelegate.h" +#include "nsHTMLIIDs.h" + +#ifdef NS_DEBUG +static PRBool gsDebug = PR_FALSE; +static PRBool gsNoisyRefs = PR_FALSE; +#else +static const PRBool gsDebug = PR_FALSE; +static const PRBool gsNoisyRefs = PR_FALSE; +#endif + + +nsTableRow::nsTableRow(nsIAtom* aTag) + : nsTableContent(aTag), + mRowGroup(0), + mRowIndex(0) +{ +} + +nsTableRow::nsTableRow(nsIAtom* aTag, PRBool aImplicit) + : nsTableContent(aTag), + mRowGroup(0), + mRowIndex(0) +{ + mImplicit = aImplicit; +} + +nsTableRow::~nsTableRow() +{ +} + +int nsTableRow::GetType() +{ + return nsITableContent::kTableRowType; +} + +nsTableRowGroup * nsTableRow::GetRowGroup () +{ + NS_IF_ADDREF(mRowGroup); + return mRowGroup; +} + +void nsTableRow::SetRowGroup (nsTableRowGroup * aRowGroup) +{ + if (aRowGroup != mRowGroup) + { + mRowGroup = aRowGroup; + } +} + +PRInt32 nsTableRow::GetRowIndex () +{ + return mRowIndex; +} + +void nsTableRow::SetRowIndex (int aRowIndex) +{ + mRowIndex = aRowIndex; +} + +// Added for debuging purposes -- remove from final build +nsrefcnt nsTableRow::AddRef(void) +{ + if (gsNoisyRefs==PR_TRUE) printf("Add Ref: %x, nsTableRow cnt = %d \n",this, mRefCnt+1); + return ++mRefCnt; +} + +nsrefcnt nsTableRow::Release(void) +{ + if (gsNoisyRefs==PR_TRUE) printf("Release: %x, nsTableRow cnt = %d \n",this,mRefCnt-1); + if (--mRefCnt == 0) { + if (gsNoisyRefs==PR_TRUE) printf("Delete: %x, nsTableRow \n",this); + delete this; + return 0; + } + return mRefCnt; +} + +PRInt32 nsTableRow::GetMaxColumns() +{ + int sum = 0; + for (int i = 0, n = ChildCount(); i < n; i++) { + nsTableCell *cell = (nsTableCell *) ChildAt(i); // cell: REFCNT++ + sum += cell->GetColSpan(); + NS_RELEASE(cell); // cell: REFCNT-- + } + return sum; +} + +void nsTableRow::ResetCellMap () +{ + // SEC Assert.Assertion(nsnull!=mTable) + if (nsnull != mRowGroup) + { + mRowGroup->ResetCellMap (); + } +} + +PRBool nsTableRow::AppendChild (nsIContent *aContent) +{ + NS_PRECONDITION(nsnull != aContent, "null ptr"); + PRBool result = PR_FALSE; + if (nsnull!=aContent) + { + // SEC: should verify that it is indeed table content before we do the cast + nsTableContent *tableContent = (nsTableContent *)aContent; + const int contentType = tableContent->GetType(); + if (contentType != nsITableContent::kTableCellType) + { + if (gsDebug==PR_TRUE) printf ("nsTableRow::AppendChild -- didn't get a cell, giving up to parent.\n"); + if (nsnull != mRowGroup) + return mRowGroup->AppendChild (aContent); // let parent have it + return PR_FALSE; + } + else + { + PRBool result = nsTableContent::AppendChild (aContent); + if (result) + { + ((nsTableCell *)aContent)->SetRow (this); + ResetCellMap (); + } + } + } + return result; +} + +PRBool nsTableRow::InsertChildAt (nsIContent *aContent, int aIndex) +{ + NS_PRECONDITION(nsnull != aContent, "null ptr"); + PRBool result = PR_FALSE; + if (nsnull!=aContent) + { + nsTableContent *tableContent = (nsTableContent *)aContent; + const int contentType = tableContent->GetType(); + if (contentType != nsITableContent::kTableCellType) + { + return PR_FALSE; + } + else + { + PRBool result = nsTableContent::InsertChildAt (aContent, aIndex); + if (result) + { + ((nsTableCell *)aContent)->SetRow (this); + ResetCellMap (); + } + } + } + return result; +} + + +PRBool nsTableRow::ReplaceChildAt (nsIContent *aContent, int aIndex) +{ + PRBool result = PR_FALSE; + // SEC Assert.PreCondition (nsnull!=aContent); + // SEC Assert.PreCondition (aIndex in range); + if ((nsnull==aContent) || /*(aIndex not in range)*/PR_FALSE) + return PR_FALSE; + else + { + nsTableContent *tableContent = (nsTableContent *)aContent; + const int contentType = tableContent->GetType(); + if (contentType != nsITableContent::kTableCellType) + { + return PR_FALSE; + } + else + return PR_FALSE; + nsIContent * oldChild = ChildAt (aIndex); // oldChild: REFCNT++ + result = nsTableContent::ReplaceChildAt (aContent, aIndex); + if (result) + { + ((nsTableCell *)aContent)->SetRow (this); + if (nsnull!=oldChild) + ((nsTableCell *)oldChild)->SetRow (nsnull); + ResetCellMap (); + } + NS_IF_RELEASE(oldChild); // oldChild: REFCNT-- + } + return result; +} + +/** + * Remove a child at the given position. The method is ignored if + * the index is invalid (too small or too large). + */ +PRBool nsTableRow::RemoveChildAt (int aIndex) +{ + PRBool result = PR_FALSE; + //Assert aIndex in range + nsIContent * oldChild = ChildAt (aIndex); // oldChild: REFCNT++ + if (nsnull!=oldChild) + { + result = nsTableContent::RemoveChildAt (aIndex); + if (result) + { + if (nsnull != oldChild) + ((nsTableCell *)oldChild)->SetRow (nsnull); + ResetCellMap (); + } + } + NS_IF_RELEASE(oldChild); // oldChild: REFCNT-- + return result; +} + +nsIFrame* nsTableRow::CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + nsIFrame* rv; + nsresult status = nsTableRowFrame::NewFrame(&rv, this, aIndexInParent, + aParentFrame); + return rv; +} + +/* ---------- Global Functions ---------- */ + +nsresult +NS_NewTableRowPart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "nsnull ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIHTMLContent* body = new nsTableRow(aTag); + if (nsnull == body) { + return NS_ERROR_OUT_OF_MEMORY; + } + return body->QueryInterface(kIHTMLContentIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/layout/html/table/src/nsTableRow.h b/mozilla/layout/html/table/src/nsTableRow.h new file mode 100644 index 00000000000..1da93dac2d9 --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableRow.h @@ -0,0 +1,94 @@ +/* -*- 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. + */ +#ifndef nsTableRow_h__ +#define nsTableRow_h__ + +#include "nscore.h" +#include "nsTableContent.h" +#include "nsTableRowGroup.h" + + +/** + * nsTableRow + * datastructure to maintain information about a single table row + * + * @author sclark + */ +class nsTableRow : public nsTableContent +{ + +private: + + nsTableRowGroup * mRowGroup; + PRInt32 mRowIndex; + +public: + + nsTableRow (nsIAtom* aTag); + + nsTableRow (nsIAtom* aTag, PRBool aImplicit); + + virtual ~nsTableRow(); + + // For debugging purposes only + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + + virtual int GetType(); + + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual nsTableRowGroup *GetRowGroup (); + + + /** + * Since mRowGroup is the parent of the table row, + * reference counting should not be done on + * this variable when setting the row. + * see /ns/raptor/doc/MemoryModel.html + **/ + virtual void SetRowGroup (nsTableRowGroup * aRowGroup); + + + virtual PRInt32 GetRowIndex (); + + virtual void SetRowIndex (int aRowIndex); + + virtual PRInt32 GetMaxColumns(); + + virtual void ResetCellMap (); + + /* ----------- nsTableContent overrides ----------- */ + + virtual PRBool AppendChild (nsIContent * aContent); + + virtual PRBool InsertChildAt (nsIContent * aContent, int aIndex); + + virtual PRBool ReplaceChildAt (nsIContent * aContent, int aIndex); + + virtual PRBool RemoveChildAt (int aIndex); + + +}; + +#endif + + + diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.cpp b/mozilla/layout/html/table/src/nsTableRowFrame.cpp new file mode 100644 index 00000000000..668e983a8b4 --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableRowFrame.cpp @@ -0,0 +1,317 @@ +/* -*- 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 "nsTableRowFrame.h" +#include "nsIRenderingContext.h" +#include "nsIPresContext.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsIContent.h" +#include "nsIContentDelegate.h" +#include "nsTableFrame.h" +#include "nsTableCellFrame.h" +#include "nsTableCell.h" +#include "nsCellLayoutData.h" + +#ifdef NS_DEBUG +static PRBool gsDebug1 = PR_FALSE; +static PRBool gsDebug2 = PR_FALSE; +//#define NOISY +//#define NOISY_FLOW +#else +static const PRBool gsDebug1 = PR_FALSE; +static const PRBool gsDebug2 = PR_FALSE; +#endif + +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); + +nsTableRowFrame::nsTableRowFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsContainerFrame(aContent, aIndexInParent, aParentFrame), + mTallestCell(0) +{ +} + +nsTableRowFrame::~nsTableRowFrame() +{ +} + +void nsTableRowFrame::ResetMaxChildHeight() +{ + mTallestCell=0; +} + +void nsTableRowFrame::SetMaxChildHeight(PRInt32 aChildHeight) +{ + if (mTallestCellGetRect(kidRect); + nsRect damageArea(aDirtyRect); + // Translate damage area into kid's coordinate system + nsRect kidDamageArea(damageArea.x - kidRect.x, damageArea.y - kidRect.y, + damageArea.width, damageArea.height); + aRenderingContext.PushState(); + aRenderingContext.Translate(kidRect.x, kidRect.y); + kid->Paint(aPresContext, aRenderingContext, kidDamageArea); + if (nsIFrame::GetShowFrameBorders()) { + aRenderingContext.SetColor(NS_RGB(255,0,0)); + aRenderingContext.DrawRect(0, 0, kidRect.width, kidRect.height); + } + aRenderingContext.PopState(); + kid = kid->GetNextSibling(); + } +} + + +/** returns the tallest child in this row (ignoring any cell with rowspans) */ +PRInt32 nsTableRowFrame::GetTallestChild() const +{ + return mTallestCell; +} + +/* + +want to use min space the child can fit in to +determine its real size, unless fixed columns sizes +are present. + + */ + +/** Layout the entire row. + * This method stacks rows horizontally according to HTML 4.0 rules. + * Rows are responsible for layout of their children. + */ +nsIFrame::ReflowStatus +nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ + if (gsDebug1==PR_TRUE) + printf("nsTableRowFrame::ResizeReflow - %p with aMaxSize = %d, %d\n", + this, aMaxSize.width, aMaxSize.height); +#ifdef NS_DEBUG + PreReflowCheck(); +#endif + + PRInt32 maxCellHeight = 0; + ResetMaxChildHeight(); + + ReflowStatus result = frComplete; + + mFirstContentOffset = mLastContentOffset = 0; + + nsIContent* c = mContent; + + nsSize availSize(aMaxSize); + nsSize maxSize(0, 0); + nsSize kidMaxSize(0,0); + nsReflowMetrics kidSize; + nscoord cellXOffset = 0; + nscoord maxAscent = 0; + nscoord maxDescent = 0; + PRInt32 kidIndex = 0; + PRInt32 lastIndex = c->ChildCount(); + nsIFrame* prevKidFrame = nsnull;/* XXX incremental reflow! */ + +// Row doesn't factor in insets, the cells do that + + nsTableFrame *tableFrame = (nsTableFrame *)(GetContentParent()->GetContentParent()); + + for (;;) { + nsIContent* kid = c->ChildAt(kidIndex); // kid: REFCNT++ + if (nsnull == kid) { + result = frComplete; + break; + } + + // get frame, creating one if needed + nsIFrame* kidFrame = ChildAt(kidIndex); + if (nsnull==kidFrame) + { + nsIContentDelegate* kidDel; + kidDel = kid->GetDelegate(aPresContext); + kidFrame = kidDel->CreateFrame(aPresContext, kid, kidIndex, this); + mChildCount++; + NS_RELEASE(kidDel); + // Resolve style + nsIStyleContext* kidStyleContext = + aPresContext->ResolveStyleContextFor(kid, this); + NS_ASSERTION(nsnull!=kidStyleContext, "bad style context for kid."); + kidFrame->SetStyleContext(kidStyleContext); + NS_RELEASE(kidStyleContext); + } + + nsTableCell* cell = (nsTableCell *)(kidFrame->GetContent()); // cell: ADDREF++ + // Try to reflow the child into the available space. + if (NS_UNCONSTRAINEDSIZE == availSize.width) + { // Each cell is given the entire row width to try to lay out into + result = ReflowChild(kidFrame, aPresContext, kidSize, availSize, &kidMaxSize); + if (gsDebug1) printf("reflow of cell returned result = %s with desired=%d,%d, min = %d,%d\n", + result==frComplete?"complete":"NOT complete", + kidSize.width, kidSize.height, kidMaxSize.width, kidMaxSize.height); + nsCellLayoutData kidLayoutData((nsTableCellFrame *)kidFrame, &kidSize, &kidMaxSize); + tableFrame->SetCellLayoutData(&kidLayoutData, cell); + } + else + { // we're in a constrained situation, so get the avail width from the known column widths + nsTableFrame *innerTableFrame = (nsTableFrame *)(GetContentParent()->GetContentParent()); + nsCellLayoutData *cellData = innerTableFrame->GetCellLayoutData(cell); + PRInt32 cellStartingCol = cell->GetColIndex(); + PRInt32 cellColSpan = cell->GetColSpan(); + PRInt32 availWidth = 0; + for (PRInt32 numColSpan=0; numColSpanGetColumnWidth(cellStartingCol+numColSpan); + NS_ASSERTION(0GetColIndex(); colIndex++) + cellXOffset += innerTableFrame->GetColumnWidth(colIndex); + } + PRInt32 rowSpan = cell->GetRowSpan(); + if ((1==rowSpan) && (maxCellHeightSetRect(nsRect(cellXOffset, 0, kidSize.width, kidSize.height)); + if (kidSize.width > maxSize.width) { + maxSize.width = kidSize.width; + } + if ((1==rowSpan) && (kidSize.height > maxSize.height)) { + maxSize.height = kidSize.height; + } + if (NS_UNCONSTRAINEDSIZE!=cellXOffset) + cellXOffset+=kidSize.width; + if (cellXOffset<=0) + cellXOffset = NS_UNCONSTRAINEDSIZE; // handle overflow + + // Link child frame into the list of children + if (nsnull != prevKidFrame) { + prevKidFrame->SetNextSibling(kidFrame); + } else { + // Our first child (**blush**) + mFirstChild = kidFrame; + SetFirstContentOffset(kidFrame); + if (gsDebug1) printf("ROW: set first content offset to %d\n", GetFirstContentOffset()); //@@@ + } + prevKidFrame = kidFrame; + + kidIndex++; + if (frNotComplete == result) { + // If the child didn't finish layout then it means that it used + // up all of our available space (or needs us to split). + mLastContentIsComplete = PR_FALSE; + break; + } + NS_RELEASE(kid); // kid: REFCNT-- + } + + if (nsnull != prevKidFrame) { + NS_ASSERTION(LastChild() == prevKidFrame, "unexpected last child"); + SetLastContentOffset(prevKidFrame); + } + + // Return our size and our result + aDesiredSize.width = cellXOffset; + aDesiredSize.height = maxSize.height; + aDesiredSize.ascent = maxAscent; + aDesiredSize.descent = maxDescent; + if (nsnull != aMaxElementSize) { + *aMaxElementSize = kidMaxSize; + } + SetMaxChildHeight(maxCellHeight); // remember height of tallest child who doesn't have a row span + +#ifdef NS_DEBUG + PostReflowCheck(result); +#endif + + return result; + +} + +nsIFrame::ReflowStatus +nsTableRowFrame::IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand) +{ + if (gsDebug1==PR_TRUE) printf("nsTableRowFrame::IncrementalReflow\n"); + return frComplete; +} + +nsIFrame* nsTableRowFrame::CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent) +{ + nsTableRowFrame* cf = new nsTableRowFrame(mContent, mIndexInParent, aParent); + PrepareContinuingFrame(aPresContext, aParent, cf); + return cf; +} + +nsresult nsTableRowFrame::NewFrame( nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIFrame* it = new nsTableRowFrame(aContent, aIndexInParent, aParent); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aInstancePtrResult = it; + return NS_OK; +} + diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.h b/mozilla/layout/html/table/src/nsTableRowFrame.h new file mode 100644 index 00000000000..d410b77472c --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableRowFrame.h @@ -0,0 +1,86 @@ +/* -*- 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. + */ +#ifndef nsTableRowFrame_h__ +#define nsTableRowFrame_h__ + +#include "nscore.h" +#include "nsContainerFrame.h" + + +/** + * nsTableRowFrame + * data structure to maintain information about a single table row's geometry + * + * @author sclark + */ +/** + */ +class nsTableRowFrame : public nsContainerFrame +{ +public: + static nsresult NewFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + virtual void Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + virtual void PaintChildren(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + + ReflowStatus IncrementalReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsReflowCommand& aReflowCommand); + + /** + * @see nsContainerFrame + */ + virtual nsIFrame* CreateContinuingFrame(nsIPresContext* aPresContext, + nsIFrame* aParent); + + void ResetMaxChildHeight(); + + void SetMaxChildHeight(PRInt32 aChildHeight); + + /** returns the tallest child in this row (ignoring any cell with rowspans) */ + PRInt32 GetTallestChild() const; + + +protected: + + nsTableRowFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual ~nsTableRowFrame(); + +private: + PRInt32 mTallestCell; // not my height, but the height of my tallest child + +}; + +#endif diff --git a/mozilla/layout/html/table/src/nsTableRowGroup.cpp b/mozilla/layout/html/table/src/nsTableRowGroup.cpp new file mode 100644 index 00000000000..8ce83dedebb --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableRowGroup.cpp @@ -0,0 +1,278 @@ +/* -*- 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 "nsTableRowGroup.h" +#include "nsTableRowGroupFrame.h" +#include "nsTableRowFrame.h" +#include "nsTablePart.h" +#include "nsTableRow.h" +#include "nsHTMLParts.h" +#include "nsHTMLContainer.h" +#include "nsIContentDelegate.h" +#include "nsReflowCommand.h" +#include "nsIStyleContext.h" +#include "nsIRenderingContext.h" +#include "nsStyleConsts.h" +#include "nsIPresContext.h" +#include "nsIDocument.h" +#include "nsHTMLIIDs.h" + +#ifdef NS_DEBUG +static PRBool gsDebug = PR_FALSE; +static PRBool gsNoisyRefs = PR_FALSE; +#else +static const PRBool gsDebug = PR_FALSE; +static const PRBool gsNoisyRefs = PR_FALSE; +#endif + +static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); +static NS_DEFINE_IID(kITableContentIID, NS_ITABLECONTENT_IID); + + +nsTableRowGroup::nsTableRowGroup(nsIAtom* aTag) + : nsTableContent(aTag) +{ +} + +nsTableRowGroup::nsTableRowGroup(nsIAtom* aTag, PRBool aImplicit) + : nsTableContent(aTag) +{ + mImplicit = aImplicit; +} + +nsTableRowGroup::~nsTableRowGroup() +{ +} + +/** return the number of columns in the widest row in this group */ +PRInt32 nsTableRowGroup::GetMaxColumns() +{ // computed every time for now, could be cached + PRInt32 result = 0; + PRInt32 numRows = ChildCount(); + for (PRInt32 rowIndex = 0; rowIndex < numRows; rowIndex++) + { + nsTableRow *row = (nsTableRow*)ChildAt(rowIndex); + PRInt32 numCols = row->GetMaxColumns(); + if (result < numCols) + result = numCols; + } + return result; +} + +// Added for debuging purposes -- remove from final build +nsrefcnt nsTableRowGroup::AddRef(void) +{ + if (gsNoisyRefs==PR_TRUE) + printf("Add Ref: %x, nsTableRowGroup cnt = %d \n",this,mRefCnt+1); + return ++mRefCnt; +} + +nsrefcnt nsTableRowGroup::Release(void) +{ + if (gsNoisyRefs==PR_TRUE) + printf("Release: %x, nsTableRowGroup cnt = %d \n",this,mRefCnt-1); + if (--mRefCnt == 0) { + if (gsNoisyRefs==PR_TRUE) printf("Delete: %x, nsTableRowGroup \n",this); + delete this; + return 0; + } + return mRefCnt; +} + +nsIFrame* nsTableRowGroup::CreateFrame( nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + nsIFrame* rv; + nsresult status = nsTableRowGroupFrame::NewFrame(&rv, this, aIndexInParent, + aParentFrame); + return rv; +} + +void nsTableRowGroup::ResetCellMap () +{ + // SEC Assert.Assertion(nsnull!=mTable) + if (nsnull != mTable) + mTable->ResetCellMap (); +} + +PRBool nsTableRowGroup::AppendChild (nsIContent *aContent) +{ + //SEC Assert.PreCondition(nsnull!=aContent); + PRBool result = PR_TRUE; + + // is aContent a TableRow? + PRBool isRow = IsRow(aContent); + + // if so, simply add it + if (PR_TRUE==isRow) + { + if (gsDebug==PR_TRUE) printf ("nsTableRowGroup::AppendChild -- inserting a row into this row group.\n"); + // if it is, we'll add it here + PRBool result = nsTableContent::AppendChild (aContent); + if (result) + { + ((nsTableRow *)aContent)->SetRowGroup (this); + ResetCellMap (); + } + } + // otherwise, if it's a cell, create an implicit row for it + else + { + nsTableContent *tableContent = (nsTableContent *)aContent; + const int contentType = tableContent->GetType(); + if (contentType == nsITableContent::kTableCellType) + { + // find last row, if ! implicit, make one, append there + nsTableRow *row = nsnull; + int index = ChildCount (); + while ((0 < index) && (nsnull==row)) + { + nsIContent *child = ChildAt (--index); // child: REFCNT++ + if (nsnull != child) + { + nsTableContent * content = (nsTableContent *)child; + if (content->GetType()==nsITableContent::kTableRowType) + row = (nsTableRow *)content; + NS_RELEASE(child); // child: REFCNT-- + } + } + if ((nsnull == row) || (! row->IsImplicit ())) + { + printf ("nsTableRow::AppendChild -- creating an implicit row.\n"); + nsIAtom * trDefaultTag = NS_NewAtom(nsTablePart::kRowTagString); // trDefaultTag: REFCNT++ + row = new nsTableRow (trDefaultTag, PR_TRUE); + NS_RELEASE(trDefaultTag); // trDefaultTag: REFCNT-- + result = AppendChild (row); + // SEC: check result + } + // group is guaranteed to be allocated at this point + result = row->AppendChild(aContent); + } + // otherwise, punt and let the table try to insert it. Or maybe just return a failure? + else + { + // you should go talk to my parent if you want to insert something other than a row + result = PR_FALSE; + } + } + return result; +} + +PRBool nsTableRowGroup::InsertChildAt (nsIContent *aContent, int aIndex) +{ + //SEC Assert.PreCondition(nsnull!=aContent); + + // is aContent a TableRow? + PRBool isRow = IsRow(aContent); + + // if not, ignore the request to add aContent + if (PR_FALSE==isRow) + { + // you should go talk to my parent if you want to insert something other than a column + return PR_FALSE; + } + + // if so, add the row to this group + PRBool result = nsTableContent::InsertChildAt (aContent, aIndex); + if (result) + { + ((nsTableRow *)aContent)->SetRowGroup (this); + ResetCellMap (); + } + return result; +} + + +PRBool nsTableRowGroup::ReplaceChildAt (nsIContent *aContent, int aIndex) +{ + // SEC Assert.PreCondition (nsnull!=aContent); + // SEC Assert.PreCondition (aIndex in range); + if ((nsnull==aContent) || /*(aIndex not in range)*/PR_FALSE) + return PR_FALSE; + + // is aContent a TableRow? + PRBool isRow = IsRow(aContent); + + // if not, ignore the request to replace the child at aIndex + { + // you should go talk to my parent if you want to insert something other than a column + return PR_FALSE; + } + + nsIContent * lastChild = ChildAt (aIndex); // lastChild: REFCNT++ + PRBool result = nsTableContent::ReplaceChildAt (aContent, aIndex); + if (result) + { + ((nsTableRow *)aContent)->SetRowGroup (this); + if (nsnull != lastChild) + ((nsTableRow *)lastChild)->SetRowGroup (nsnull); + ResetCellMap (); + } + NS_IF_RELEASE(lastChild); // lastChild: REFCNT-- + return result; +} + +/** + * Remove a child at the given position. The method is ignored if + * the index is invalid (too small or too large). + */ +PRBool nsTableRowGroup::RemoveChildAt (int aIndex) +{ + nsIContent * lastChild = ChildAt (aIndex); // lastChild: REFCNT++ + PRBool result = nsTableContent::RemoveChildAt (aIndex); + if (result) + { + if (nsnull != lastChild) + ((nsTableRow *)lastChild)->SetRowGroup (nsnull); + ResetCellMap (); + } + NS_IF_RELEASE(lastChild); // lastChild: REFCNT-- + return result; +} + +/** support method to determine if the param aContent is a TableRow object */ +PRBool nsTableRowGroup::IsRow(nsIContent * aContent) const +{ + PRBool result = PR_FALSE; + if (nsnull!=aContent) + { + // is aContent a row? + nsTableContent *tableContent = (nsTableContent *)aContent; + const int contentType = tableContent->GetType(); + if (contentType == nsITableContent::kTableRowType) + result = PR_TRUE; + } + return result; +} + +/* ----------- Global Functions ---------- */ + +nsresult +NS_NewTableRowGroupPart(nsIHTMLContent** aInstancePtrResult, + nsIAtom* aTag) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "nsnull ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + nsIHTMLContent* body = new nsTableRowGroup(aTag); + if (nsnull == body) { + return NS_ERROR_OUT_OF_MEMORY; + } + return body->QueryInterface(kIHTMLContentIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/layout/html/table/src/nsTableRowGroup.h b/mozilla/layout/html/table/src/nsTableRowGroup.h new file mode 100644 index 00000000000..7daf80a9c5a --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableRowGroup.h @@ -0,0 +1,87 @@ +/* -*- 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. + */ +#ifndef nsTableRowGroup_h__ +#define nsTableRowGroup_h__ + +#include "nscore.h" +#include "nsTableContent.h" + +class nsIPresContext; + +/** + * TableRowGroup + * + * @author sec 11-20-97 6:12pm + * @version $Revision: 1.1 $ + * @see + */ +class nsTableRowGroup : public nsTableContent +{ + +public: + + nsTableRowGroup (nsIAtom* aTag); + + nsTableRowGroup (nsIAtom* aTag, PRBool aImplicit); + + virtual ~nsTableRowGroup(); + + virtual PRInt32 GetMaxColumns(); + + // For debugging purposes only + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + + virtual nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + virtual int GetRowCount () + { + return ChildCount (); + }; + + virtual int GetType() + { + return nsITableContent::kTableRowGroupType; + }; + + virtual void ResetCellMap (); + + /* ----------- overrides from nsTableContent ---------- */ + + virtual PRBool AppendChild (nsIContent * aContent); + + virtual PRBool InsertChildAt (nsIContent * aContent, int aIndex); + + virtual PRBool ReplaceChildAt (nsIContent * aContent, int aIndex); + + /** + * Remove a child at the given position. The method is ignored if + * the index is invalid (too small or too large). + */ + virtual PRBool RemoveChildAt (int aIndex); + +protected: + + virtual PRBool IsRow(nsIContent * aContent) const; + +}; + +#endif + diff --git a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp new file mode 100644 index 00000000000..5a460592a85 --- /dev/null +++ b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp @@ -0,0 +1,957 @@ +/* -*- 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 "nsTableRowGroupFrame.h" +#include "nsTableRowFrame.h" +#include "nsTableCellFrame.h" +#include "nsIRenderingContext.h" +#include "nsIPresContext.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsIContent.h" +#include "nsIContentDelegate.h" + + +#ifdef NS_DEBUG +static PRBool gsDebug1 = PR_FALSE; +static PRBool gsDebug2 = PR_FALSE; +//#define NOISY +//#define NOISY_FLOW +#else +static const PRBool gsDebug1 = PR_FALSE; +static const PRBool gsDebug2 = PR_FALSE; +#endif + +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); + +/* ----------- RowGroupReflowState ---------- */ + +struct RowGroupReflowState { + + // The body's style molecule + nsStyleMolecule* mol; + + // The body's available size (computed from the body's parent) + nsSize availSize; + + // Margin tracking information + nscoord prevMaxPosBottomMargin; + nscoord prevMaxNegBottomMargin; + + // Flags for whether the max size is unconstrained + PRBool unconstrainedWidth; + PRBool unconstrainedHeight; + + // Running y-offset + nscoord y; + + // Flag used to set aMaxElementSize to my first row + PRBool firstRow; + + // Remember the height of the first row, because it's our maxElementHeight (plus header/footers) + nscoord firstRowHeight; + + RowGroupReflowState(nsIPresContext* aPresContext, + const nsSize& aMaxSize, + nsStyleMolecule* aMol) + { + mol = aMol; + availSize.width = aMaxSize.width; + availSize.height = aMaxSize.height; + prevMaxPosBottomMargin = 0; + prevMaxNegBottomMargin = 0; + y=0; // border/padding/margin??? + unconstrainedWidth = PRBool(aMaxSize.width == NS_UNCONSTRAINEDSIZE); + unconstrainedHeight = PRBool(aMaxSize.height == NS_UNCONSTRAINEDSIZE); + firstRow = PR_TRUE; + firstRowHeight=0; + } + + ~RowGroupReflowState() { + } +}; + + + + +/* ----------- nsTableRowGroupFrame ---------- */ + +nsTableRowGroupFrame::nsTableRowGroupFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsContainerFrame(aContent, aIndexInParent, aParentFrame) +{ +} + +nsTableRowGroupFrame::~nsTableRowGroupFrame() +{ +} + + +void nsTableRowGroupFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + + // for debug... + if (nsIFrame::GetShowFrameBorders()) { + aRenderingContext.SetColor(NS_RGB(128,0,0)); + aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height); + } + + PaintChildren(aPresContext, aRenderingContext, aDirtyRect); +} + +// aDirtyRect is in our coordinate system +// child rect's are also in our coordinate system +/** overloaded method from nsContainerFrame. The difference is that + * we don't want to clip our children, so a cell can do a rowspan + */ +void nsTableRowGroupFrame::PaintChildren(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + nsIFrame* kid = mFirstChild; + while (nsnull != kid) { + nsRect kidRect; + kid->GetRect(kidRect); + nsRect damageArea(aDirtyRect); + // Translate damage area into kid's coordinate system + nsRect kidDamageArea(damageArea.x - kidRect.x, damageArea.y - kidRect.y, + damageArea.width, damageArea.height); + aRenderingContext.PushState(); + aRenderingContext.Translate(kidRect.x, kidRect.y); + kid->Paint(aPresContext, aRenderingContext, kidDamageArea); + if (nsIFrame::GetShowFrameBorders()) { + aRenderingContext.SetColor(NS_RGB(255,0,0)); + aRenderingContext.DrawRect(0, 0, kidRect.width, kidRect.height); + } + aRenderingContext.PopState(); + kid = kid->GetNextSibling(); + } +} + +// Collapse child's top margin with previous bottom margin +nscoord nsTableRowGroupFrame::GetTopMarginFor(nsIPresContext* aCX, + RowGroupReflowState& aState, + nsStyleMolecule* aKidMol) +{ + nscoord margin; + nscoord maxNegTopMargin = 0; + nscoord maxPosTopMargin = 0; + if ((margin = aKidMol->margin.top) < 0) { + maxNegTopMargin = -margin; + } else { + maxPosTopMargin = margin; + } + + nscoord maxPos = PR_MAX(aState.prevMaxPosBottomMargin, maxPosTopMargin); + nscoord maxNeg = PR_MAX(aState.prevMaxNegBottomMargin, maxNegTopMargin); + margin = maxPos - maxNeg; + + return margin; +} + +// Position and size aKidFrame and update our reflow state. The origin of +// aKidRect is relative to the upper-left origin of our frame, and includes +// any left/top margin. +void nsTableRowGroupFrame::PlaceChild(nsIPresContext* aPresContext, + RowGroupReflowState& aState, + nsIFrame* aKidFrame, + const nsRect& aKidRect, + nsStyleMolecule* aKidMol, + nsSize* aMaxElementSize, + nsSize& aKidMaxElementSize) +{ + // Place and size the child + aKidFrame->SetRect(aKidRect); + + // Adjust the running y-offset + aState.y += aKidRect.height; + + // If our height is constrained then update the available height + if (PR_FALSE == aState.unconstrainedHeight) { + aState.availSize.height -= aKidRect.height; + } + + // Update the maximum element size + if (PR_TRUE==aState.firstRow) + { + aState.firstRow = PR_FALSE; + aState.firstRowHeight = aKidRect.height; + if (nsnull != aMaxElementSize) { + aMaxElementSize->width = aKidMaxElementSize.width; + aMaxElementSize->height = aKidMaxElementSize.height; + } + } +} + +/** + * Reflow the frames we've already created + * + * @param aPresContext presentation context to use + * @param aState current inline state + * @return true if we successfully reflowed all the mapped children and false + * otherwise, e.g. we pushed children to the next in flow + */ +PRBool nsTableRowGroupFrame::ReflowMappedChildren( nsIPresContext* aPresContext, + RowGroupReflowState& aState, + nsSize* aMaxElementSize) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": reflow mapped (childCount=%d) [%d,%d,%c]\n", + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); +#ifdef NOISY_FLOW + { + nsTableRowGroupFrame* flow = (nsTableRowGroupFrame*) mNextInFlow; + while (flow != 0) { + printf(" %p: [%d,%d,%c]\n", + flow, flow->mFirstContentOffset, flow->mLastContentOffset, + (flow->mLastContentIsComplete ? 'T' : 'F')); + flow = (nsTableRowGroupFrame*) flow->mNextInFlow; + } + } +#endif +#endif + NS_PRECONDITION(nsnull != mFirstChild, "no children"); + + PRInt32 childCount = 0; + nsIFrame* prevKidFrame = nsnull; + + // Remember our original mLastContentIsComplete so that if we end up + // having to push children, we have the correct value to hand to + // PushChildren. + PRBool lastContentIsComplete = mLastContentIsComplete; + + nsSize kidMaxElementSize; + nsSize* pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull; + PRBool result = PR_TRUE; + + for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; ) { + nsSize kidAvailSize(aState.availSize); + nsReflowMetrics desiredSize; + nsIFrame::ReflowStatus status; + + // Get top margin for this kid + nsIContent* kid = kidFrame->GetContent(); + nsIStyleContext* kidSC = kidFrame->GetStyleContext(aPresContext); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol); + nscoord bottomMargin = kidMol->margin.bottom; + NS_RELEASE(kid); + NS_RELEASE(kidSC); + + // Figure out the amount of available size for the child (subtract + // off the top margin we are going to apply to it) + if (PR_FALSE == aState.unconstrainedHeight) { + kidAvailSize.height -= topMargin; + } + // Subtract off for left and right margin + if (PR_FALSE == aState.unconstrainedWidth) { + kidAvailSize.width -= kidMol->margin.left + kidMol->margin.right; + } + + // Only skip the reflow if this is not our first child and we are + // out of space. + if ((kidFrame == mFirstChild) || (kidAvailSize.height > 0)) { + // Reflow the child into the available space + status = ReflowChild(kidFrame, aPresContext, desiredSize, + kidAvailSize, pKidMaxElementSize); + } + + // Did the child fit? + if ((kidFrame != mFirstChild) && + ((kidAvailSize.height <= 0) || + (desiredSize.height > kidAvailSize.height))) + { + // The child's height is too big to fit at all in our remaining space, + // and it's not our first child. + // + // Note that if the width is too big that's okay and we allow the + // child to extend horizontally outside of the reflow area + + // Since we are giving the next-in-flow our last child, we + // give it our original mLastContentIsComplete, too (in case we + // are pushing into an empty next-in-flow) + PushChildren(kidFrame, prevKidFrame, lastContentIsComplete); + + // Our mLastContentIsComplete was already set by the last kid we + // reflowed reflow's status + result = PR_FALSE; + break; + } + + // Place the child after taking into account it's margin + aState.y += topMargin; + nsRect kidRect (0, 0, desiredSize.width, desiredSize.height); + kidRect.x += kidMol->margin.left; + kidRect.y += aState.y; + PlaceChild(aPresContext, aState, kidFrame, kidRect, kidMol, aMaxElementSize, + kidMaxElementSize); + if (bottomMargin < 0) { + aState.prevMaxNegBottomMargin = -bottomMargin; + } else { + aState.prevMaxPosBottomMargin = bottomMargin; + } + childCount++; + + // Update mLastContentIsComplete now that this kid fits + mLastContentIsComplete = PRBool(status == frComplete); + + // Special handling for incomplete children + if (frNotComplete == status) { + // XXX It's good to assume that we might still have room + // even if the child didn't complete (floaters will want this) + nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); + if (nsnull == kidNextInFlow) { + // No the child isn't complete, and it doesn't have a next in flow so + // create a continuing frame. This hooks the child into the flow. + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aPresContext, this); + + // Insert the frame. We'll reflow it next pass through the loop + nsIFrame* nextSib = kidFrame->GetNextSibling(); + continuingFrame->SetNextSibling(nextSib); + kidFrame->SetNextSibling(continuingFrame); + if (nsnull == nextSib) { + // Assume that the continuation frame we just created is + // complete, for now. It will get reflowed by our + // next-in-flow (we are going to push it now) + lastContentIsComplete = PR_TRUE; + } + } + } + + // Get the next child + prevKidFrame = kidFrame; + kidFrame = kidFrame->GetNextSibling(); + + // XXX talk with troy about checking for available space here + } + + // Update the child count + mChildCount = childCount; + NS_POSTCONDITION(LengthOf(mFirstChild) == mChildCount, "bad child count"); + + // Set the last content offset based on the last child we mapped. + NS_ASSERTION(LastChild() == prevKidFrame, "unexpected last child"); + SetLastContentOffset(prevKidFrame); + +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": reflow mapped %sok (childCount=%d) [%d,%d,%c]\n", + (result ? "" : "NOT "), + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); +#ifdef NOISY_FLOW + { + nsTableRowGroupFrame* flow = (nsTableRowGroupFrame*) mNextInFlow; + while (flow != 0) { + printf(" %p: [%d,%d,%c]\n", + flow, flow->mFirstContentOffset, flow->mLastContentOffset, + (flow->mLastContentIsComplete ? 'T' : 'F')); + flow = (nsTableRowGroupFrame*) flow->mNextInFlow; + } + } +#endif +#endif + return result; +} + +/** + * Try and pull-up frames from our next-in-flow + * + * @param aPresContext presentation context to use + * @param aState current inline state + * @return true if we successfully pulled-up all the children and false + * otherwise, e.g. child didn't fit + */ +PRBool nsTableRowGroupFrame::PullUpChildren(nsIPresContext* aPresContext, + RowGroupReflowState& aState, + nsSize* aMaxElementSize) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": pullup (childCount=%d) [%d,%d,%c]\n", + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); +#ifdef NOISY_FLOW + { + nsTableRowGroupFrame* flow = (nsTableRowGroupFrame*) mNextInFlow; + while (flow != 0) { + printf(" %p: [%d,%d,%c]\n", + flow, flow->mFirstContentOffset, flow->mLastContentOffset, + (flow->mLastContentIsComplete ? 'T' : 'F')); + flow = (nsTableRowGroupFrame*) flow->mNextInFlow; + } + } +#endif +#endif + NS_PRECONDITION(nsnull != mNextInFlow, "null next-in-flow"); + nsTableRowGroupFrame* nextInFlow = (nsTableRowGroupFrame*)mNextInFlow; + nsSize kidMaxElementSize; + nsSize* pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull; + + // The frame previous to the current frame we are reflowing. This + // starts out initially as our last frame. + nsIFrame* prevKidFrame = LastChild(); + + // This will hold the prevKidFrame's mLastContentIsComplete + // status. If we have to push the frame that follows prevKidFrame + // then this will become our mLastContentIsComplete state. Since + // prevKidFrame is initially our last frame, it's completion status + // is our mLastContentIsComplete value. + PRBool prevLastContentIsComplete = mLastContentIsComplete; + PRBool result = PR_TRUE; + + while (nsnull != nextInFlow) { + nsReflowMetrics desiredSize; + nsSize kidAvailSize(aState.availSize); + + // Get first available frame from the next-in-flow + nsIFrame* kidFrame = PullUpOneChild(nextInFlow, prevKidFrame); + if (nsnull == kidFrame) { + // We've pulled up all the children from that next-in-flow, so + // move to the next next-in-flow. + nextInFlow = (nsTableRowGroupFrame*) nextInFlow->mNextInFlow; + continue; + } + + // Get top margin for this kid + nsIContent* kid = kidFrame->GetContent(); + nsIStyleContext* kidSC = kidFrame->GetStyleContext(aPresContext); + nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID); + nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol); + nscoord bottomMargin = kidMol->margin.bottom; + + // Figure out the amount of available size for the child (subtract + // off the top margin we are going to apply to it) + if (PR_FALSE == aState.unconstrainedHeight) { + kidAvailSize.height -= topMargin; + } + // Subtract off for left and right margin + if (PR_FALSE == aState.unconstrainedWidth) { + kidAvailSize.width -= kidMol->margin.left + kidMol->margin.right; + } + + ReflowStatus status; + do { + // Only skip the reflow if this is not our first child and we are + // out of space. + if ((kidFrame == mFirstChild) || (kidAvailSize.height > 0)) { + status = ReflowChild(kidFrame, aPresContext, desiredSize, + kidAvailSize, pKidMaxElementSize); + } + + // Did the child fit? + if ((kidFrame != mFirstChild) && + ((kidAvailSize.height <= 0) || + (desiredSize.height > kidAvailSize.height))) + { + // The child's height is too big to fit at all in our remaining space, + // and it wouldn't have been our first child. + // + // Note that if the width is too big that's okay and we allow the + // child to extend horizontally outside of the reflow area + PRBool lastComplete = PRBool(nsnull == kidFrame->GetNextInFlow()); + PushChildren(kidFrame, prevKidFrame, lastComplete); + mLastContentIsComplete = prevLastContentIsComplete; + mChildCount--; + result = PR_FALSE; + NS_RELEASE(kid); + NS_RELEASE(kidSC); + goto push_done; + } + + // Place the child + aState.y += topMargin; + nsRect kidRect (0, 0, desiredSize.width, desiredSize.height); + kidRect.x += kidMol->margin.left; + kidRect.y += aState.y; + PlaceChild(aPresContext, aState, kidFrame, kidRect, kidMol, aMaxElementSize, + kidMaxElementSize); + if (bottomMargin < 0) { + aState.prevMaxNegBottomMargin = -bottomMargin; + } else { + aState.prevMaxPosBottomMargin = bottomMargin; + } + mLastContentIsComplete = PRBool(status == frComplete); + +#ifdef NOISY + ListTag(stdout); + printf(": pulled up "); + ((nsFrame*)kidFrame)->ListTag(stdout); + printf("\n"); +#endif + + // Is the child we just pulled up complete? + if (frNotComplete == status) { + // No the child isn't complete. + nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); + if (nsnull == kidNextInFlow) { + // The child doesn't have a next-in-flow so create a + // continuing frame. The creation appends it to the flow and + // prepares it for reflow. + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aPresContext, this); + + // Add the continuing frame to our sibling list. + continuingFrame->SetNextSibling(kidFrame->GetNextSibling()); + kidFrame->SetNextSibling(continuingFrame); + prevKidFrame = kidFrame; + prevLastContentIsComplete = mLastContentIsComplete; + kidFrame = continuingFrame; + mChildCount++; + } else { + // The child has a next-in-flow, but it's not one of ours. + // It *must* be in one of our next-in-flows. Collect it + // then. + NS_ASSERTION(kidNextInFlow->GetGeometricParent() != this, + "busted kid next-in-flow"); + break; + } + } + } while (frNotComplete == status); + NS_RELEASE(kid); + NS_RELEASE(kidSC); + + prevKidFrame = kidFrame; + prevLastContentIsComplete = mLastContentIsComplete; + } + + push_done:; + // Update our last content index + if (nsnull != prevKidFrame) { + NS_ASSERTION(LastChild() == prevKidFrame, "bad last child"); + SetLastContentOffset(prevKidFrame); + } + + // We need to make sure the first content offset is correct for any empty + // next-in-flow frames (frames where we pulled up all the child frames) + nextInFlow = (nsTableRowGroupFrame*)mNextInFlow; + if ((nsnull != nextInFlow) && (nsnull == nextInFlow->mFirstChild)) { + // We have at least one empty frame. Did we succesfully pull up all the + // child frames? + if (PR_FALSE == result) { + // No, so we need to adjust the first content offset of all the empty + // frames + AdjustOffsetOfEmptyNextInFlows(); +#ifdef NS_DEBUG + } else { + // Yes, we successfully pulled up all the child frames which means all + // the next-in-flows must be empty. Do a sanity check + while (nsnull != nextInFlow) { + NS_ASSERTION(nsnull == nextInFlow->mFirstChild, "non-empty next-in-flow"); + nextInFlow = (nsTableRowGroupFrame*)nextInFlow->GetNextInFlow(); + } +#endif + } + } + +#ifdef NS_DEBUG + PRInt32 len = LengthOf(mFirstChild); + NS_ASSERTION(len == mChildCount, "bad child count"); + VerifyLastIsComplete(); +#endif +#ifdef NOISY + ListTag(stdout); + printf(": pullup %sok (childCount=%d) [%d,%d,%c]\n", + (result ? "" : "NOT "), + mChildCount, + mFirstContentOffset, mLastContentOffset, + (mLastContentIsComplete ? 'T' : 'F')); +#ifdef NOISY_FLOW + { + nsTableRowGroupFrame* flow = (nsTableRowGroupFrame*) mNextInFlow; + while (flow != 0) { + printf(" %p: [%d,%d,%c]\n", + flow, flow->mFirstContentOffset, flow->mLastContentOffset, + (flow->mLastContentIsComplete ? 'T' : 'F')); + flow = (nsTableRowGroupFrame*) flow->mNextInFlow; + } + } +#endif +#endif + return result; +} + +/** + * Create new frames for content we haven't yet mapped + * + * @param aPresContext presentation context to use + * @param aState current inline state + * @return frComplete if all content has been mapped and frNotComplete + * if we should be continued + */ +nsIFrame::ReflowStatus +nsTableRowGroupFrame::ReflowUnmappedChildren(nsIPresContext* aPresContext, + RowGroupReflowState& aState, + nsSize* aMaxElementSize) +{ +#ifdef NS_DEBUG + VerifyLastIsComplete(); +#endif + nsIFrame* kidPrevInFlow = nsnull; + ReflowStatus result = frNotComplete; + + // If we have no children and we have a prev-in-flow then we need to pick + // up where it left off. If we have children, e.g. we're being resized, then + // our content offset should already be set correctly... + if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) { + nsTableRowGroupFrame* prev = (nsTableRowGroupFrame*)mPrevInFlow; + NS_ASSERTION(prev->mLastContentOffset >= prev->mFirstContentOffset, "bad prevInFlow"); + + mFirstContentOffset = prev->NextChildOffset(); + if (!prev->mLastContentIsComplete) { + // Our prev-in-flow's last child is not complete + kidPrevInFlow = prev->LastChild(); + } + } + + PRBool originalLastContentIsComplete = mLastContentIsComplete; + + // Place our children, one at a time, until we are out of children + nsSize kidMaxElementSize; + nsSize* pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull; + PRInt32 kidIndex = NextChildOffset(); + nsIFrame* prevKidFrame = LastChild(); // XXX remember this... + + for (;;) { + // Get the next content object + nsIContent* kid = mContent->ChildAt(kidIndex); + if (nsnull == kid) { + result = frComplete; + break; + } + + // Make sure we still have room left + if (aState.availSize.height <= 0) { + // Note: return status was set to frNotComplete above... + NS_RELEASE(kid); + break; + } + + // Resolve style + nsIStyleContext* kidStyleContext = + aPresContext->ResolveStyleContextFor(kid, this); + nsStyleMolecule* kidMol = + (nsStyleMolecule*)kidStyleContext->GetData(kStyleMoleculeSID); + nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol); + nscoord bottomMargin = kidMol->margin.bottom; + + //nsBlockFrame* pseudoFrame = nsnull; + nsIFrame* kidFrame; + ReflowStatus status; + + // Create a child frame + if (nsnull == kidPrevInFlow) { + nsIContentDelegate* kidDel = nsnull; + kidDel = kid->GetDelegate(aPresContext); + kidFrame = kidDel->CreateFrame(aPresContext, kid, kidIndex, this); + NS_RELEASE(kidDel); + kidFrame->SetStyleContext(kidStyleContext); + } else { + kidFrame = kidPrevInFlow->CreateContinuingFrame(aPresContext, this); + } + + // Link the child frame into the list of children and update the + // child count + if (nsnull != prevKidFrame) { + NS_ASSERTION(nsnull == prevKidFrame->GetNextSibling(), "bad append"); + prevKidFrame->SetNextSibling(kidFrame); + } else { + NS_ASSERTION(nsnull == mFirstChild, "bad create"); + mFirstChild = kidFrame; + SetFirstContentOffset(kidFrame); + } + mChildCount++; + + do { + nsSize kidAvailSize(aState.availSize); + nsReflowMetrics desiredSize; + + // Figure out the amount of available size for the child (subtract + // off the margin we are going to apply to it) + if (PR_FALSE == aState.unconstrainedHeight) { + kidAvailSize.height -= topMargin; + } + // Subtract off for left and right margin + if (PR_FALSE == aState.unconstrainedWidth) { + kidAvailSize.width -= kidMol->margin.left + kidMol->margin.right; + } + + // Try to reflow the child into the available space. It might not + // fit or might need continuing + if (kidAvailSize.height > 0) { + status = ReflowChild(kidFrame, aPresContext, desiredSize, + kidAvailSize, pKidMaxElementSize); + } + + // Did the child fit? + if ((nsnull != mFirstChild) && + ((kidAvailSize.height <= 0) || + (desiredSize.height > kidAvailSize.height))) { + // The child's height is too big to fit in our remaining + // space, and it's not our first child. + NS_ASSERTION(nsnull == mOverflowList, "bad overflow list"); + NS_ASSERTION(nsnull == mNextInFlow, "whoops"); + + // Chop off the part of our child list that's being overflowed + NS_ASSERTION(prevKidFrame->GetNextSibling() == kidFrame, "bad list"); + prevKidFrame->SetNextSibling(nsnull); + + // Create overflow list + mOverflowList = kidFrame; + + // Fixup child count by subtracting off the number of children + // that just ended up on the reflow list. + PRInt32 overflowKids = 0; + nsIFrame* f = kidFrame; + while (nsnull != f) { + overflowKids++; + f = f->GetNextSibling(); + } + mChildCount -= overflowKids; + NS_RELEASE(kidStyleContext); + NS_RELEASE(kid); + goto done; + } + + // Advance y by the topMargin between children. Zero out the + // topMargin in case this frame is continued because + // continuations do not have a top margin. Update the prev + // bottom margin state in the body reflow state so that we can + // apply the bottom margin when we hit the next child (or + // finish). + aState.y += topMargin; + nsRect kidRect (0, 0, desiredSize.width, desiredSize.height); + kidRect.x += kidMol->margin.left; + kidRect.y += aState.y; + PlaceChild(aPresContext, aState, kidFrame, kidRect, kidMol, aMaxElementSize, + kidMaxElementSize); + if (bottomMargin < 0) { + aState.prevMaxNegBottomMargin = -bottomMargin; + } else { + aState.prevMaxPosBottomMargin = bottomMargin; + } + topMargin = 0; + + mLastContentIsComplete = PRBool(status == frComplete); + if (frNotComplete == status) { + // Child didn't complete so create a continuing frame + kidPrevInFlow = kidFrame; + nsIFrame* continuingFrame = + kidFrame->CreateContinuingFrame(aPresContext, this); + + // Add the continuing frame to the sibling list + continuingFrame->SetNextSibling(kidFrame->GetNextSibling()); + kidFrame->SetNextSibling(continuingFrame); + prevKidFrame = kidFrame; + kidFrame = continuingFrame; + mChildCount++; + + /* + if (nsnull != pseudoFrame) { + pseudoFrame = (nsBlockFrame*) kidFrame; + } + */ + // XXX We probably shouldn't assume that there is no room for + // the continuation + } + } while (frNotComplete == status); + NS_RELEASE(kidStyleContext); + NS_RELEASE(kid); + + prevKidFrame = kidFrame; + kidPrevInFlow = nsnull; + + // Update the kidIndex + /* + if (nsnull != pseudoFrame) { + // Adjust kidIndex to reflect the number of children mapped by + // the pseudo frame + kidIndex = pseudoFrame->NextChildOffset(); + } else { + */ + kidIndex++; + /* + } + */ + } + +done: + // Update the content mapping + NS_ASSERTION(LastChild() == prevKidFrame, "bad last child"); + if (0 != mChildCount) { + SetLastContentOffset(prevKidFrame); + } +#ifdef NS_DEBUG + PRInt32 len = LengthOf(mFirstChild); + NS_ASSERTION(len == mChildCount, "bad child count"); + VerifyLastIsComplete(); +#endif + return result; +} + +/** Layout the entire row group. + * This method stacks rows vertically according to HTML 4.0 rules. + * Rows are responsible for layout of their children. + */ +nsIFrame::ReflowStatus +nsTableRowGroupFrame::ResizeReflow( nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ + if (gsDebug1==PR_TRUE) + printf("nsTableRowGroupFrame::ResizeReflow - aMaxSize = %d, %d\n", + aMaxSize.width, aMaxSize.height); +#ifdef NS_DEBUG + PreReflowCheck(); +#endif + + // Initialize out parameter + if (nsnull != aMaxElementSize) { + aMaxElementSize->width = 0; + aMaxElementSize->height = 0; + } + + PRBool reflowMappedOK = PR_TRUE; + ReflowStatus status = frComplete; + + // Check for an overflow list + MoveOverflowToChildList(); + + nsStyleMolecule* myMol = + (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID); + RowGroupReflowState state(aPresContext, aMaxSize, myMol); + + // Reflow the existing frames + if (nsnull != mFirstChild) { + reflowMappedOK = ReflowMappedChildren(aPresContext, state, aMaxElementSize); + if (PR_FALSE == reflowMappedOK) { + status = frNotComplete; + } + } + + // Did we successfully relow our mapped children? + if (PR_TRUE == reflowMappedOK) { + // Any space left? + if ((nsnull != mFirstChild) && (state.availSize.height <= 0)) { + // No space left. Don't try to pull-up children or reflow unmapped + if (NextChildOffset() < mContent->ChildCount()) { + status = frNotComplete; + } + } else if (NextChildOffset() < mContent->ChildCount()) { + // Try and pull-up some children from a next-in-flow + if ((nsnull == mNextInFlow) || + PullUpChildren(aPresContext, state, aMaxElementSize)) { + // If we still have unmapped children then create some new frames + if (NextChildOffset() < mContent->ChildCount()) { + status = ReflowUnmappedChildren(aPresContext, state, aMaxElementSize); + } + } else { + // We were unable to pull-up all the existing frames from the + // next in flow + status = frNotComplete; + } + } + } + + if (frComplete == status) { + // Don't forget to add in the bottom margin from our last child. + // Only add it in if there's room for it. + nscoord margin = state.prevMaxPosBottomMargin - + state.prevMaxNegBottomMargin; + if (state.availSize.height >= margin) { + state.y += margin; + } + } + + // Return our desired rect + NS_ASSERTION(0 +#include "nscore.h" +#include "..\..\src\nsCellMap.h" + +static FILE * out; + +class CellData +{ +public: + PRInt32 mID; + + CellData(PRInt32 aID) + { mID = aID;}; + +}; + +class BasicTest +{ +public: + BasicTest(); + virtual ~BasicTest() {}; + + void DumpCellMap(nsCellMap *aMap, PRInt32 aRows, PRInt32 aCols); + void VerifyRowsAndCols(nsCellMap *aMap, PRInt32 aRows, PRInt32 aCols); +}; + +BasicTest::BasicTest() +{ + PRInt32 rows = 3; + PRInt32 cols = 4; + nsCellMap *map = new nsCellMap(rows, cols); + fprintf(out, "\nCreating %d by %d table with these values...\n", rows, cols); + for (PRInt32 i=0; imID); + map->SetCellAt(cellData, i, j); + } + fprintf(out, "\n"); + } + // verify input + DumpCellMap(map, rows, cols); + VerifyRowsAndCols(map, rows, cols); + + // cell map's own output should match above output + map->DumpCellMap(); + + // append a column + fprintf(out, "\nadding a column, so cols=%d\n", cols); + cols++; + map->GrowTo(cols); + DumpCellMap(map, rows, cols); + VerifyRowsAndCols(map, rows, cols); + + // reset the map + rows++; cols++; + fprintf(out, "\nresetting the map to %d,%d\n", rows, cols); + map->Reset(rows, cols); + DumpCellMap(map, rows, cols); + VerifyRowsAndCols(map, rows, cols); + +} + +void BasicTest::DumpCellMap(nsCellMap *aMap, PRInt32 aRows, PRInt32 aCols) +{ + fprintf(out, "\nPrinting out %d by %d table...\n", aRows, aCols); + for (PRInt32 i=0; iGetCellAt(i, j); + if (nsnull!=cellData) + fprintf(out, "Cell_%d ", cellData->mID); + else + fprintf(out, "null "); + } + fprintf(out, "\n"); + } +} + +void BasicTest::VerifyRowsAndCols(nsCellMap *aMap, PRInt32 aRows, PRInt32 aCols) +{ + if (aMap->GetRowCount()!=aRows) + fprintf(out, "ERROR: map->mRowCount!=rows, %d != %d\n", aMap->GetRowCount(), aRows); + if (aMap->GetColCount()!=aCols) + fprintf(out, "ERROR: map->mColCount!=cols, %d != %d\n", aMap->GetColCount(), aCols); +} + +void main (int argc, char **argv) +{ + out = fopen("CellMapTest.txt", "w+t"); + if (nsnull==out) + { + printf("test failed to open output file\n"); + exit(-1); + } + fprintf(out, "Test starting...\n\n"); + BasicTest basicTest; + fprintf(out, "\nTest completed.\n"); +} + + + diff --git a/mozilla/layout/html/tests/Makefile b/mozilla/layout/html/tests/Makefile new file mode 100644 index 00000000000..bfff9337cfc --- /dev/null +++ b/mozilla/layout/html/tests/Makefile @@ -0,0 +1,64 @@ +#!gmake +# +# 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. + +DEPTH=../../.. + +include $(DEPTH)/config/config.mk + +CPPSRCS = \ + TestCSSParser.cpp \ + TestCSSPropertyLookup.cpp \ + TestCSSScanner.cpp \ + TestHTMLTagLookup.cpp \ + $(NULL) + +INCLUDES+=-I../src -I$(PUBLIC)/xpcom -I$(PUBLIC)/raptor + +DIRS = + +OBJS = $(CPPSRCS:.cpp=.o) + +EX_LIBS = \ + $(DIST)/lib/libraptorhtml.a \ + $(DIST)/lib/libraptorlayout_s.a \ + $(DIST)/lib/libraptorgfx.a \ + $(DIST)/lib/libraptorbase.a \ + $(DIST)/lib/libxpcom.a \ + $(DIST)/lib/libplc21.a \ + $(DIST)/lib/libplds21.a \ + $(DIST)/lib/libnspr21.a \ + $(NULL) + +PROGS = $(addprefix $(OBJDIR)/, $(CPPSRCS:.cpp=)) + +TARGETS = $(PROGS) + +include $(DEPTH)/config/rules.mk + +$(OBJDIR)/%.o: %.cpp + @$(MAKE_OBJDIR) + $(CCC) -o $@ $(CFLAGS) -c $*.cpp + +$(PROGS):$(OBJDIR)/%: $(OBJDIR)/%.o $(EX_LIBS) + @$(MAKE_OBJDIR) + $(CCC) -o $@ $@.o $(LDFLAGS) $(EX_LIBS) $(OS_LIBS) + +export:: + +install:: $(TARGETS) + $(INSTALL) $(TARGETS) $(DIST)/bin + diff --git a/mozilla/layout/html/tests/TestAttributes.cpp b/mozilla/layout/html/tests/TestAttributes.cpp new file mode 100644 index 00000000000..68e36ad453d --- /dev/null +++ b/mozilla/layout/html/tests/TestAttributes.cpp @@ -0,0 +1,276 @@ +/* -*- 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 +#include "nscore.h" +#include "nsIAtom.h" +#include "nsCRT.h" +#include "nsHTMLParts.h" +#include "nsIHTMLContent.h" +#include "nsIHTMLAttributes.h" +#include "nsITextContent.h" +#include "nsIUnicharInputStream.h" +#include "nsString.h" +#include "nsIDocument.h" +#include "nsISupportsArray.h" +#include "nsDocument.h" +#include "nsIURL.h" + +void testAttributes(nsIHTMLContent* content) { + nsIAtom* sBORDER = NS_NewAtom("BORDER"); + nsIAtom* sWIDTH = NS_NewAtom("WIDTH"); + nsIAtom* sHEIGHT = NS_NewAtom("HEIGHT"); + nsIAtom* sSRC = NS_NewAtom("SRC"); + nsIAtom* sBAD = NS_NewAtom("BADATTRIBUTE"); + nsString sempty(""); + nsString sfoo_gif("foo.gif"); + + content->SetAttribute(sBORDER); + content->SetAttribute(sWIDTH, nsHTMLValue(5, eHTMLUnit_Pixel)); + content->SetAttribute(sHEIGHT, sempty); + content->SetAttribute(sSRC, sfoo_gif); + + nsHTMLValue ret; + nsContentAttr rv; + rv = content->GetAttribute(sBORDER, ret); + if ((rv != eContentAttr_NoValue) || (ret.GetUnit() != eHTMLUnit_Null)) { + printf("test 0 failed\n"); + } + + rv = content->GetAttribute(sWIDTH, ret); + if ((rv != eContentAttr_HasValue) || (! (ret == nsHTMLValue(5, eHTMLUnit_Pixel)))) { + printf("test 1 failed\n"); + } + + rv = content->GetAttribute(sBAD, ret); + if (rv != eContentAttr_NotThere) { + printf("test 2 failed\n"); + } + + // Same, except different case strings + + nsString sborder("border"); + nsString strRet; + rv = ((nsIContent*)content)->GetAttribute(sborder, strRet); + if (rv != eContentAttr_NoValue) { + printf("test 3 (case comparison) failed\n"); + } + + content->UnsetAttribute(sWIDTH); + + nsISupportsArray* allNames; + NS_NewISupportsArray(&allNames); + + content->GetAllAttributeNames(allNames); + if (allNames->Count() != 3) { + printf("test 5 (unset attriubte) failed\n"); + } + + PRBool borderFound = PR_FALSE,heightFound = PR_FALSE,srcFound = PR_FALSE; + for (int n = 0; n < 3; n++) { + const nsIAtom* ident = (const nsIAtom*)allNames->ElementAt(n); + if (sBORDER == ident) { + borderFound = PR_TRUE; + } + if (sHEIGHT == ident) { + heightFound = PR_TRUE; + } + if (sSRC == ident) { + srcFound = PR_TRUE; + } + } + if (!(borderFound && heightFound && srcFound)) { + printf("test 6 failed\n"); + } + + NS_RELEASE(allNames); + + NS_RELEASE(sBORDER); + NS_RELEASE(sWIDTH); + NS_RELEASE(sHEIGHT); + NS_RELEASE(sSRC); +} + +void testStrings(nsIDocument* aDoc) { + printf("begin string tests\n"); + + PRBool val; + // regular Equals + val = (nsString("mrString")).Equals(nsString("mrString")); + if (PR_TRUE != val) { + printf("test 0 failed\n"); + } + val = (nsString("mrString")).Equals(nsString("MRString")); + if (PR_FALSE != val) { + printf("test 1 failed\n"); + } + val = (nsString("mrString")).Equals(nsString("mrStri")); + if (PR_FALSE != val) { + printf("test 2 failed\n"); + } + val = (nsString("mrStri")).Equals(nsString("mrString")); + if (PR_FALSE != val) { + printf("test 3 failed\n"); + } + // EqualsIgnoreCase + val = (nsString("mrString")).EqualsIgnoreCase("mrString"); + if (PR_TRUE != val) { + printf("test 4 failed\n"); + } + val = (nsString("mrString")).EqualsIgnoreCase("mrStrinG"); + if (PR_TRUE != val) { + printf("test 5 failed\n"); + } + val = (nsString("mrString")).EqualsIgnoreCase("mrStri"); + if (PR_FALSE != val) { + printf("test 6 failed\n"); + } + val = (nsString("mrStri")).EqualsIgnoreCase("mrString"); + if (PR_FALSE != val) { + printf("test 7 failed\n"); + } + // String vs. Ident + val = (nsString("mrString")).EqualsIgnoreCase(NS_NewAtom("mrString")); + if (PR_TRUE != val) { + printf("test 8 failed\n"); + } + val = (nsString("mrString")).EqualsIgnoreCase(NS_NewAtom("MRStrINg")); + if (PR_TRUE != val) { + printf("test 9 failed\n"); + } + val = (nsString("mrString")).EqualsIgnoreCase(NS_NewAtom("mrStri")); + if (PR_FALSE != val) { + printf("test 10 failed\n"); + } + val = (nsString("mrStri")).EqualsIgnoreCase(NS_NewAtom("mrString")); + if (PR_FALSE != val) { + printf("test 11 failed\n"); + } + + printf("string tests complete\n"); +} + +class MyDocument : public nsDocument { +public: + MyDocument(); + void LoadURL(nsIURL* aURL); + +protected: + virtual ~MyDocument(); +}; + +MyDocument::MyDocument() +{ +} + +MyDocument::~MyDocument() +{ +} + +void MyDocument::LoadURL(nsIURL* aURL) +{ +} + +int main(int argc, char** argv) +{ + // Create Byte2Unicode converter + nsresult rv; + nsIB2UConverter *converter; + rv = NS_NewB2UConverter(&converter,NULL); + if (NS_OK != rv) { + printf("Could not create converter.\n"); + return -1; + } + + // Create a unicode string + static const char* srcStr = "This is some meaningless text about nothing at all"; + PRInt32 rv2; + PRInt32 origSrcLen = nsCRT::strlen((char *)srcStr); + const int BUFFER_LENGTH = 100; + PRUnichar destStr[BUFFER_LENGTH]; + PRInt32 srcLen = origSrcLen; + PRInt32 destLen = BUFFER_LENGTH; + rv2 = converter->Convert(destStr,0,destLen,srcStr,0,srcLen); + if ((NS_OK != rv2) || (srcLen < origSrcLen)) { + printf("Failed to convert all characters to unicode.\n"); + return -1; + } + + delete converter; + + // Create test document. + MyDocument *myDoc = new MyDocument(); + + testStrings(myDoc); + + // Create a new text content object. + nsIHTMLContent *text; + rv = NS_NewHTMLText(&text,destStr,destLen); + if (NS_OK != rv) { + printf("Could not create text content.\n"); + return -1; + } + NS_ASSERTION(!text->CanContainChildren(),""); + text->SetDocument(myDoc); + +#if 0 + // Query ITextContent interface + static NS_DEFINE_IID(kITextContentIID, NS_ITEXTCONTENT_IID); + nsITextContent* textContent; + rv = text->QueryInterface(kITextContentIID,(void **)&textContent); + if (NS_OK != rv) { + printf("Created text content does not have the ITextContent interface.\n"); + return -1; + } + + // Print the contents. + nsAutoString stringBuf; + textContent->GetText(stringBuf,0,textContent->GetLength()); + if (!stringBuf.Equals(nsString(destStr,destLen))) { + printf("something wrong with the text in a text content\n"); + } +#endif + + // Create a simple container. + nsIHTMLContent* container; + nsIAtom* li = NS_NewAtom("LI"); + + rv = NS_NewHTMLContainer(&container,li); + if (NS_OK != rv) { + printf("Could not create container.\n"); + return -1; + } + NS_ASSERTION(container->CanContainChildren(),""); + container->SetDocument(myDoc); + + container->AppendChild(text); + if (container->ChildCount() != 1) { + printf("Container has wrong number of children."); + } + + printf("begin attribute tests\n"); + testAttributes(container); + printf("attribute tests complete\n"); + + + // Clean up memory. + text->Release(); // The textContent interface. + delete container; + delete text; + myDoc->Release(); + return 0; +} diff --git a/mozilla/layout/html/tests/TestCSSParser.cpp b/mozilla/layout/html/tests/TestCSSParser.cpp new file mode 100644 index 00000000000..8045885d409 --- /dev/null +++ b/mozilla/layout/html/tests/TestCSSParser.cpp @@ -0,0 +1,98 @@ +/* -*- 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 +#include "nsICSSParser.h" +#include "nsIStyleSheet.h" +#include "nsIURL.h" +#include "nsIInputStream.h" +#include "nsIUnicharInputStream.h" +#include "nsString.h" + +static void Usage(void) +{ + printf("usage: TestCSSParser [-v] url\n"); +} + +int main(int argc, char** argv) +{ + if (argc < 2 || argc > 3) { + Usage(); + return -1; + } + + PRBool verbose = PR_FALSE; + char* urlName; + if (argc == 3) { + if (strcmp(argv[1], "-v") == 0) { + verbose = PR_TRUE; + } else { + Usage(); + return -1; + } + urlName = argv[2]; + } else { + urlName = argv[1]; + } + + // Create url object + nsIURL* url; + nsresult rv = NS_NewURL(&url, nsnull, urlName); + if (NS_OK != rv) { + printf("invalid URL: '%s'\n", urlName); + return -1; + } + + // Get an input stream from the url + PRInt32 ec; + nsIInputStream* in = url->Open(&ec); + if (nsnull == in) { + printf("open of url('%s') failed: error=%x\n", urlName, ec); + return -1; + } + + // Translate the input using the argument character set id into unicode + nsIUnicharInputStream* uin; + rv = NS_NewConverterStream(&uin, nsnull, in); + if (NS_OK != rv) { + printf("can't create converter input stream: %d\n", rv); + return -1; + } + + // Create parser and set it up to process the input file + nsICSSParser* css; + rv = NS_NewCSSParser(&css); + if (NS_OK != rv) { + printf("can't create css parser: %d\n", rv); + return -1; + } + printf("CSS parser supports %x\n", css->GetInfoMask()); + + // Parse the input and produce a style set + nsIStyleSheet* sheet = css->Parse(&ec, uin, url); + if (verbose) { + sheet->List(); + } + + url->Release(); + in->Release(); + uin->Release(); + css->Release(); + sheet->Release(); + + return 0; +} diff --git a/mozilla/layout/html/tests/TestCSSPropertyLookup.cpp b/mozilla/layout/html/tests/TestCSSPropertyLookup.cpp new file mode 100644 index 00000000000..a989d6efdb9 --- /dev/null +++ b/mozilla/layout/html/tests/TestCSSPropertyLookup.cpp @@ -0,0 +1,135 @@ +/* -*- 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 +#include "plstr.h" +#include "nsCSSProps.h" +#include "nsCSSKeywords.h" + +static const char* kJunkNames[] = { + nsnull, + "", + "123", + "backgroundz", + "zzzzzz", + "#@$&@#*@*$@$#" +}; + +int TestProps() { + int rv = 0; + PRInt32 id; + + // First make sure we can find all of the tags that are supposed to + // be in the table. Futz with the case to make sure any case will + // work + const nsCSSProps::NameTableEntry* et = &nsCSSProps::kNameTable[0]; + const nsCSSProps::NameTableEntry* end = &nsCSSProps::kNameTable[PROP_MAX]; + while (et < end) { + char tagName[100]; + id = nsCSSProps::LookupName(et->name); + if (id < 0) { + printf("bug: can't find '%s'\n", et->name); + rv = -1; + } + if (et->id != id) { + printf("bug: name='%s' et->id=%d id=%d\n", et->name, et->id, id); + rv = -1; + } + + // fiddle with the case to make sure we can still find it + PL_strcpy(tagName, et->name); + tagName[0] = tagName[0] - 32; + id = nsCSSProps::LookupName(tagName); + if (id < 0) { + printf("bug: can't find '%s'\n", tagName); + rv = -1; + } + if (et->id != id) { + printf("bug: name='%s' et->id=%d id=%d\n", et->name, et->id, id); + rv = -1; + } + et++; + } + + // Now make sure we don't find some garbage + for (int i = 0; i < sizeof(kJunkNames) / sizeof(const char*); i++) { + const char* tag = kJunkNames[i]; + id = nsCSSProps::LookupName(tag); + if (id >= 0) { + printf("bug: found '%s'\n", tag ? tag : "(null)"); + rv = -1; + } + } + + return rv; +} + +int TestKeywords() { + int rv = 0; + PRInt32 id; + + // First make sure we can find all of the tags that are supposed to + // be in the table. Futz with the case to make sure any case will + // work + const nsCSSKeywords::NameTableEntry* et = &nsCSSKeywords::kNameTable[0]; + const nsCSSKeywords::NameTableEntry* end = &nsCSSKeywords::kNameTable[KEYWORD_MAX]; + while (et < end) { + char tagName[100]; + id = nsCSSKeywords::LookupName(et->name); + if (id < 0) { + printf("bug: can't find '%s'\n", et->name); + rv = -1; + } + if (et->id != id) { + printf("bug: name='%s' et->id=%d id=%d\n", et->name, et->id, id); + rv = -1; + } + + // fiddle with the case to make sure we can still find it + PL_strcpy(tagName, et->name); + tagName[0] = tagName[0] - 32; + id = nsCSSKeywords::LookupName(tagName); + if (id < 0) { + printf("bug: can't find '%s'\n", tagName); + rv = -1; + } + if (et->id != id) { + printf("bug: name='%s' et->id=%d id=%d\n", et->name, et->id, id); + rv = -1; + } + et++; + } + + // Now make sure we don't find some garbage + for (int i = 0; i < sizeof(kJunkNames) / sizeof(const char*); i++) { + const char* tag = kJunkNames[i]; + id = nsCSSKeywords::LookupName(tag); + if (id >= 0) { + printf("bug: found '%s'\n", tag ? tag : "(null)"); + rv = -1; + } + } + + return rv; +} + +int main(int argc, char** argv) +{ + TestProps(); + TestKeywords(); + return 0; +} diff --git a/mozilla/layout/html/tests/TestCSSScanner.cpp b/mozilla/layout/html/tests/TestCSSScanner.cpp new file mode 100644 index 00000000000..b3b561f59f4 --- /dev/null +++ b/mozilla/layout/html/tests/TestCSSScanner.cpp @@ -0,0 +1,103 @@ +/* -*- 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 +#include "nsCSSScanner.h" +#include "nsIURL.h" +#include "nsIInputStream.h" +#include "nsIUnicharInputStream.h" +#include "nsString.h" + +int main(int argc, char** argv) +{ + if (2 != argc) { + printf("usage: TestCSSScanner url\n"); + return -1; + } + + // Create url object + char* urlName = argv[1]; + nsIURL* url; + nsresult rv = NS_NewURL(&url, nsnull, urlName); + if (NS_OK != rv) { + printf("invalid URL: '%s'\n", urlName); + return -1; + } + + // Get an input stream from the url + PRInt32 ec; + nsIInputStream* in = url->Open(&ec); + if (nsnull == in) { + printf("open of url('%s') failed: error=%x\n", urlName, ec); + return -1; + } + + // Translate the input using the argument character set id into unicode + nsIUnicharInputStream* uin; + rv = NS_NewConverterStream(&uin, nsnull, in); + if (NS_OK != rv) { + printf("can't create converter input stream: %d\n", rv); + return -1; + } + + // Create scanner and set it up to process the input file + nsCSSScanner* css = new nsCSSScanner(); + css->Init(uin); + + // Scan the file and dump out the tokens + nsCSSToken tok; + for (;;) { + char buf[20]; + if (!css->Next(&ec, &tok)) { + break; + } + printf("%02d: ", tok.mType); + switch (tok.mType) { + case eCSSToken_Ident: + case eCSSToken_AtKeyword: + case eCSSToken_String: + case eCSSToken_WhiteSpace: + case eCSSToken_URL: + case eCSSToken_InvalidURL: + case eCSSToken_ID: + fputs(tok.mIdent, stdout); + fputs("\n", stdout); + break; + + case eCSSToken_Number: + printf("%g\n", tok.mNumber); + break; + case eCSSToken_Percentage: + printf("%g%%\n", tok.mNumber * 100.0f); + break; + case eCSSToken_Dimension: + tok.mIdent.ToCString(buf, sizeof(buf)); + printf("%g%s\n", tok.mNumber, buf); + break; + case eCSSToken_Symbol: + printf("%c (%x)\n", tok.mSymbol, tok.mSymbol); + break; + } + } + + delete css; + uin->Release(); + in->Release(); + url->Release(); + + return 0; +} diff --git a/mozilla/layout/html/tests/TestHTMLTagLookup.cpp b/mozilla/layout/html/tests/TestHTMLTagLookup.cpp new file mode 100644 index 00000000000..ea6cb6aeb09 --- /dev/null +++ b/mozilla/layout/html/tests/TestHTMLTagLookup.cpp @@ -0,0 +1,73 @@ +/* -*- 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 +#include "plstr.h" +#include "nsHTMLTags.h" + +static const char* kJunkNames[] = { + nsnull, + "", + "123", + "ab", + "zzzzzz", + "#@$&@#*@*$@$#" +}; + +int main(int argc, char** argv) +{ + PRInt32 id; + + // First make sure we can find all of the tags that are supposed to + // be in the table. Futz with the case to make sure any case will + // work + const nsHTMLTags::NameTableEntry* et = &nsHTMLTags::kNameTable[0]; + const nsHTMLTags::NameTableEntry* end = &nsHTMLTags::kNameTable[TAG_MAX]; + while (et < end) { + char tagName[100]; + id = nsHTMLTags::LookupName(et->name); + if (id < 0) { + printf("bug: can't find '%s'\n", et->name); + } + if (et->id != id) { + printf("bug: name='%s' et->id=%d id=%d\n", et->name, et->id, id); + } + + // fiddle with the case to make sure we can still find it + PL_strcpy(tagName, et->name); + tagName[0] = tagName[0] - 32; + id = nsHTMLTags::LookupName(tagName); + if (id < 0) { + printf("bug: can't find '%s'\n", tagName); + } + if (et->id != id) { + printf("bug: name='%s' et->id=%d id=%d\n", et->name, et->id, id); + } + et++; + } + + // Now make sure we don't find some garbage + for (int i = 0; i < sizeof(kJunkNames) / sizeof(const char*); i++) { + const char* tag = kJunkNames[i]; + id = nsHTMLTags::LookupName(tag); + if (id >= 0) { + printf("bug: found '%s'\n", tag ? tag : "(null)"); + } + } + + return 0; +} diff --git a/mozilla/layout/html/tests/TestInlineFrame.cpp b/mozilla/layout/html/tests/TestInlineFrame.cpp new file mode 100644 index 00000000000..3c6a01978f6 --- /dev/null +++ b/mozilla/layout/html/tests/TestInlineFrame.cpp @@ -0,0 +1,1647 @@ +/* -*- 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 +#include "nscore.h" +#include "nsCRT.h" +#include "nsHTMLParts.h" +#include "nsIHTMLContent.h" +#include "nsIDocument.h" +#include "nsVoidArray.h" +#include "nsDocument.h" +#include "nsHTMLTagContent.h" +#include "nscoord.h" +#include "nsSplittableFrame.h" +#include "nsIContentDelegate.h" +#include "nsIPresContext.h" +#include "nsInlineFrame.h" +#include "nsIAtom.h" + +static NS_DEFINE_IID(kIContentDelegateIID, NS_ICONTENTDELEGATE_IID); + +/////////////////////////////////////////////////////////////////////////////// +// + +class MyDocument : public nsDocument { +public: + MyDocument(); + + virtual void LoadURL(nsIURL* aURL); + +protected: + virtual ~MyDocument(); +}; + +MyDocument::MyDocument() +{ +} + +MyDocument::~MyDocument() +{ +} + +void MyDocument::LoadURL(nsIURL* aURL) +{ +} + +/////////////////////////////////////////////////////////////////////////////// +// + +// Frame with a fixed width, but that's optionally splittable +class FixedSizeFrame : public nsSplittableFrame { +public: + FixedSizeFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + ReflowStatus ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize); + + PRBool IsSplittable() const; +}; + +class FixedSizeContent : public nsHTMLTagContent { +public: + FixedSizeContent(nscoord aWidth, + nscoord aHeight, + PRBool aIsSplittable = PR_FALSE); + + nsIFrame* CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame); + + // Accessors + nscoord GetWidth() {return mWidth;} + void SetWidth(nscoord aWidth); + nscoord GetHeight() {return mHeight;} + void SetHeight(nscoord aHeight); + + void ToHTML(nsString& out); + PRBool IsSplittable() const {return mIsSplittable;} + void SetIsSplittable(PRBool aIsSplittable) {mIsSplittable = aIsSplittable;} + +private: + nscoord mWidth, mHeight; + PRBool mIsSplittable; +}; + +/////////////////////////////////////////////////////////////////////////////// +// + +FixedSizeFrame::FixedSizeFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) + : nsSplittableFrame(aContent, aIndexInParent, aParentFrame) +{ +} + +nsIFrame::ReflowStatus +FixedSizeFrame::ResizeReflow(nsIPresContext* aPresContext, + nsReflowMetrics& aDesiredSize, + const nsSize& aMaxSize, + nsSize* aMaxElementSize) +{ + NS_PRECONDITION((aMaxSize.width > 0) && (aMaxSize.height > 0), "bad max size"); + FixedSizeContent* content = (FixedSizeContent*)mContent; + ReflowStatus status = frComplete; + FixedSizeFrame* prevInFlow = (FixedSizeFrame*)mPrevInFlow; + + aDesiredSize.width = content->GetWidth(); + aDesiredSize.height = content->GetHeight(); + + // We can split once horizontally + if (nsnull != prevInFlow) { + aDesiredSize.width -= prevInFlow->mRect.width; + } else if ((aDesiredSize.width > aMaxSize.width) && content->IsSplittable()) { + aDesiredSize.width = aMaxSize.width; + status = frNotComplete; + } + + aDesiredSize.ascent = aDesiredSize.height; + aDesiredSize.descent = 0; + if (nsnull != aMaxElementSize) { + aMaxElementSize->width = aDesiredSize.width; + aMaxElementSize->height = aDesiredSize.height; + } + + return status; +} + +PRBool FixedSizeFrame::IsSplittable() const +{ + FixedSizeContent* content = (FixedSizeContent*)mContent; + + return content->IsSplittable(); +} + +/////////////////////////////////////////////////////////////////////////////// +// + +FixedSizeContent::FixedSizeContent(nscoord aWidth, + nscoord aHeight, + PRBool aIsSplittable) + : nsHTMLTagContent() +{ + mWidth = aWidth; + mHeight = aHeight; + mIsSplittable = aIsSplittable; +} + +nsIFrame* FixedSizeContent::CreateFrame(nsIPresContext* aPresContext, + PRInt32 aIndexInParent, + nsIFrame* aParentFrame) +{ + return new FixedSizeFrame(this, aIndexInParent, aParentFrame); +} + +// Change the width of the content triggering an incremental reflow +void FixedSizeContent::SetWidth(nscoord aWidth) +{ + NS_NOTYETIMPLEMENTED("set width"); +} + +// Change the width of the content triggering an incremental reflow +void FixedSizeContent::SetHeight(nscoord aHeight) +{ + NS_NOTYETIMPLEMENTED("set height"); +} + +void FixedSizeContent::ToHTML(nsString& out) +{ +} + +/////////////////////////////////////////////////////////////////////////////// +// + +class InlineFrame : public nsInlineFrame +{ +public: + InlineFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent); + + // Accessors to return protected state + nsIFrame* OverflowList() {return mOverflowList;} + void ClearOverflowList() {mOverflowList = nsnull;} + PRBool LastContentIsComplete() {return mLastContentIsComplete;} + + // Helper member functions + PRInt32 MaxChildWidth(); + PRInt32 MaxChildHeight(); +}; + +InlineFrame::InlineFrame(nsIContent* aContent, + PRInt32 aIndexInParent, + nsIFrame* aParent) + : nsInlineFrame(aContent, aIndexInParent, aParent) +{ +} + +PRInt32 InlineFrame::MaxChildWidth() +{ + PRInt32 maxWidth = 0; + + for (nsIFrame* f = FirstChild(); nsnull != f; f = f->GetNextSibling()) { + if (f->GetWidth() > maxWidth) { + maxWidth = f->GetWidth(); + } + } + + return maxWidth; +} + +PRInt32 InlineFrame::MaxChildHeight() +{ + PRInt32 maxHeight = 0; + + for (nsIFrame* f = FirstChild(); nsnull != f; f = f->GetNextSibling()) { + if (f->GetHeight() > maxHeight) { + maxHeight = f->GetHeight(); + } + } + + return maxHeight; +} + +/////////////////////////////////////////////////////////////////////////////// +// Helper functions + +// Compute the number of frames in the list +static PRInt32 +LengthOf(nsIFrame* aChildList) +{ + PRInt32 result = 0; + + while (nsnull != aChildList) { + aChildList = aChildList->GetNextSibling(); + result++; + } + + return result; +} + +/////////////////////////////////////////////////////////////////////////////// +// + +// Test basic reflowing of unmapped children. No borders/padding or child +// margins involved, and no splitting of child frames. b is an empty +// HTML container +// +// Here's what this function tests: +// - reflow unmapped maps all children and returns that it's complete +// - each child frame is placed and sized properly +// - the inline frame's desired width and height are correct +static PRBool +TestReflowUnmapped(nsIPresContext* presContext) +{ + // Create an HTML container + nsIHTMLContent* b; + NS_NewHTMLContainer(&b, NS_NewAtom("SPAN")); + + // Append three fixed width elements. + b->AppendChild(new FixedSizeContent(100, 100)); + b->AppendChild(new FixedSizeContent(300, 300)); + b->AppendChild(new FixedSizeContent(200, 200)); + + // Create an inline frame for the HTML container and set its + // style context + InlineFrame* f = new InlineFrame(b, 0, nsnull); + nsIStyleContext* styleContext = presContext->ResolveStyleContextFor(b, nsnull); + + f->SetStyleContext(styleContext); + + // Reflow the HTML container + nsReflowMetrics reflowMetrics; + nsSize maxSize(1000, 1000); + nsIFrame::ReflowStatus status; + + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + + // Make sure the frame is complete + if (status != nsIFrame::frComplete) { + printf("ReflowUnmapped: initial reflow not complete: %d\n", status); + return PR_FALSE; + } + + // Verify that all the children were mapped + if (f->ChildCount() != b->ChildCount()) { + printf("ReflowUnmapped: wrong number of child frames: %d\n", f->ChildCount()); + return PR_FALSE; + } + + // and that the last content offset is correct + if (f->GetLastContentOffset() != (b->ChildCount() - 1)) { + printf("ReflowUnmapped: wrong last content offset: %d\n", f->GetLastContentOffset()); + return PR_FALSE; + } + + // Verify that the width/height of each child frame is correct + for (PRInt32 i = 0; i < b->ChildCount(); i++) { + FixedSizeContent* childContent = (FixedSizeContent*)b->ChildAt(i); + nsIFrame* childFrame = f->ChildAt(i); + + if ((childFrame->GetWidth() != childContent->GetWidth()) || + (childFrame->GetHeight() != childContent->GetHeight())) { + printf("ReflowUnmapped: child frame size incorrect: %d\n", i); + return PR_FALSE; + } + } + + // Verify that the inline frame's desired height is correct + if (reflowMetrics.height != f->MaxChildHeight()) { + printf("ReflowUnmapped: wrong frame height: %d\n", reflowMetrics.height); + return PR_FALSE; + } + + // Verify that the frames are tiled horizontally with no space between frames + nscoord x = 0; + for (nsIFrame* child = f->FirstChild(); child; child = child->GetNextSibling()) { + nsPoint origin; + + child->GetOrigin(origin); + if (origin.x != x) { + printf("ReflowUnmapped: child x-origin is incorrect: %d\n", x); + return PR_FALSE; + } + + x += child->GetWidth(); + } + + // and that the inline frame's desired width is correct + if (reflowMetrics.width != x) { + printf("ReflowUnmapped: wrong frame width: %d\n", reflowMetrics.width); + return PR_FALSE; + } + + NS_RELEASE(b); + return PR_TRUE; +} + +// Test the case where the frame max size is too small for even one child frame. +// +// Here's what this function tests: +// 1. reflow unmapped with a max width narrower than the first child +// a) when there's only one content child +// b) when there's more than one content child +// 2. reflow unmapped when the height's too small +// 3. reflow mapped when the height's too small +// 4. reflow mapped with a max width narrower than the first child +static PRBool +TestChildrenThatDontFit(nsIPresContext* presContext) +{ + // Create an HTML container + nsIHTMLContent* b; + NS_NewHTMLContainer(&b, NS_NewAtom("SPAN")); + + // Add one fixed width element. + b->AppendChild(new FixedSizeContent(100, 100)); + + // Create an inline frame for the HTML container and set its + // style context + InlineFrame* f = new InlineFrame(b, 0, nsnull); + nsIStyleContext* styleContext = presContext->ResolveStyleContextFor(b, nsnull); + + f->SetStyleContext(styleContext); + + /////////////////////////////////////////////////////////////////////////// + // Test #1a + + // Reflow the frame with a width narrower than the first child frame. This + // tests how we handle one child that doesn't fit when reflowing unmapped + nsReflowMetrics reflowMetrics; + nsSize maxSize(10, 1000); + nsIFrame::ReflowStatus status; + + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + + // Verify that the inline frame is complete + if (status != nsIFrame::frComplete) { + printf("ChildrenThatDontFIt: reflow unmapped isn't complete (#1a): %d\n", status); + return PR_FALSE; + } + + // Verify that the desired width is the width of the first frame + if (reflowMetrics.width != f->FirstChild()->GetWidth()) { + printf("ChildrenThatDontFit: frame width is wrong (#1a): %d\n", f->FirstChild()->GetWidth()); + return PR_FALSE; + } + + /////////////////////////////////////////////////////////////////////////// + // Test #1b + + // Append two more fixed width elements. + b->AppendChild(new FixedSizeContent(300, 300)); + b->AppendChild(new FixedSizeContent(200, 200)); + + // Create a new inline frame for the HTML container + InlineFrame* f1 = new InlineFrame(b, 0, nsnull); + f1->SetStyleContext(styleContext); + + // Reflow the frame with a width narrower than the first child frame. This + // tests how we handle children that don't fit when reflowing unmapped + maxSize.SizeTo(10, 1000); + status = f1->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + + // Verify that the frame is not complete + if (status != nsIFrame::frNotComplete) { + printf("ChildrenThatDontFIt: reflow unmapped isn't not complete (#1b): %d\n", status); + return PR_FALSE; + } + + // Verify that the desired width is the width of the first frame + if (reflowMetrics.width != f1->FirstChild()->GetWidth()) { + printf("ChildrenThatDontFit: frame width is wrong (#1b): %d\n", f1->FirstChild()->GetWidth()); + return PR_FALSE; + } + + // Verify that the child count is only 1 + if (f1->ChildCount() != 1) { + printf("ChildrenThatDontFit: more than one child frame (#1b): %d\n", f1->ChildCount()); + return PR_FALSE; + } + + // and that there's no overflow list. If there's an overflow list that means + // we reflowed a second frame and we would have passed it a negative max size + // which is not a very nice thing to do + if (nsnull != f1->OverflowList()) { + printf("ChildrenThatDontFit: unexpected overflow list (#1b)\n"); + return PR_FALSE; + } + + /////////////////////////////////////////////////////////////////////////// + // Test #2 + + // Now reflow the frame wide enough so that all the frames fit. Make + // the height small enough so that no frames fit, so we can test that + // reflow unmapped handles that check correctly + maxSize.width = 1000; + maxSize.height = 10; + reflowMetrics.height = 0; + status = f1->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + + // Verify the frame is complete + if (status != nsIFrame::frComplete) { + printf("ChildrenThatDontFit: resize isn't complete (#2): %d\n", status); + return PR_FALSE; + } + + // Verify that all child frames are now there + if (f1->ChildCount() != b->ChildCount()) { + printf("ChildrenThatDontFit: wrong child count (#2): %d\n", f1->ChildCount()); + return PR_FALSE; + } + + // and that the frame's height is the right size + if (reflowMetrics.height != f1->MaxChildHeight()) { + printf("ChildrenThatDontFit: height is wrong (#2): %d\n", reflowMetrics.height); + return PR_FALSE; + } + + /////////////////////////////////////////////////////////////////////////// + // Test #3 + + // Now test reflow mapped against a height that's too small + nscoord oldHeight = reflowMetrics.height; + maxSize.height = 10; + reflowMetrics.height = 0; + status = f1->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + + // Verify the frame is complete and we still have all the child frames + if ((status != nsIFrame::frComplete) || (f1->ChildCount() != b->ChildCount())) { + printf("ChildrenThatDontFit: reflow mapped failed (#3)\n"); + return PR_FALSE; + } + + // Verify that the desired height of the frame is the same as before + if (reflowMetrics.height != oldHeight) { + printf("ChildrenThatDontFit: height is wrong (#3): %d\n", reflowMetrics.height); + return PR_FALSE; + } + + /////////////////////////////////////////////////////////////////////////// + // Test #4 + + // And finally test reflowing mapped with a max width narrower than the first + // child + maxSize.width = 10; + maxSize.height = 1000; + status = f1->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + + // Verify the frame is not complete + if (status != nsIFrame::frNotComplete) { + printf("ChildrenThatDontFIt: reflow mapped isn't not complete (#4): %d\n", status); + return PR_FALSE; + } + + // Verify that there's only one child + if (f1->ChildCount() > 1) { + printf("ChildrenThatDontFIt: reflow mapped too many children (#4): %d\n", f1->ChildCount()); + return PR_FALSE; + } + + // and that the desired width is the width of the first frame + if (reflowMetrics.width != f1->FirstChild()->GetWidth()) { + printf("ChildrenThatDontFit: frame width is wrong (#4): %d\n", f1->FirstChild()->GetWidth()); + return PR_FALSE; + } + + NS_RELEASE(b); + return PR_TRUE; +} + +// Test handling of the overflow list +// +// Here's what this function tests: +// 1. reflow unmapped places children whose width doesn't completely fit on +// the overflow list +// 2. frames use their own overflow list when reflowing mapped children +// 3. continuing frames should use the overflow list from their prev-in-flow +static PRBool +TestOverflow(nsIPresContext* presContext) +{ + // Create an HTML container + nsIHTMLContent* b; + NS_NewHTMLContainer(&b, NS_NewAtom("SPAN")); + + // Append three fixed width elements. + b->AppendChild(new FixedSizeContent(100, 100)); + b->AppendChild(new FixedSizeContent(300, 300)); + b->AppendChild(new FixedSizeContent(200, 200)); + + // Create an inline frame for the HTML container and set its + // style context + InlineFrame* f = new InlineFrame(b, 0, nsnull); + nsIStyleContext* styleContext = presContext->ResolveStyleContextFor(b, nsnull); + + f->SetStyleContext(styleContext); + + /////////////////////////////////////////////////////////////////////////// + // Test #1 + + // Reflow the frame so only half the second frame fits + nsReflowMetrics reflowMetrics; + nsSize maxSize(150, 1000); + nsIFrame::ReflowStatus status; + + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frNotComplete == status, "bad status"); + NS_ASSERTION(f->ChildCount() == 1, "bad child count"); + + // Verify that there's one frame on the overflow list + if ((nsnull == f->OverflowList()) || (LengthOf(f->OverflowList()) != 1)) { + printf("Overflow: no overflow list (#1)\n"); + return PR_FALSE; + } + + /////////////////////////////////////////////////////////////////////////// + // Test #2 + + // Reflow the frame again this time so all the child frames fit. The inline + // frame should use its own overflow list + maxSize.width = 1000; + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frComplete == status, "isn't complete"); + + // Verify the overflow list is now empty + if (nsnull != f->OverflowList()) { + printf("Overflow: overflow list should be empty (#2)\n"); + return PR_FALSE; + } + + /////////////////////////////////////////////////////////////////////////// + // Test #3 + + // Reflow the frame so that only the first frame fits. The rest of the + // children should go on the overflow list. This isn't interesting by + // itself, but it enables the next test + maxSize.width = f->FirstChild()->GetWidth(); + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION((f->ChildCount() == 1) && (LengthOf(f->OverflowList()) == 2), "bad overflow list"); + + // Create a continuing frame + InlineFrame* f1 = new InlineFrame(b, 0, nsnull); + + f1->SetStyleContext(f->GetStyleContext(presContext)); + f->SetNextSibling(f1); + f->SetNextInFlow(f1); + f1->SetPrevInFlow(f); + + // Reflow the continuing frame. It should get its children from the overflow list + maxSize.width = 1000; + status = f1->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frComplete == status, "bad continuing frame"); + + // Verify that the overflow list is now empty + if (nsnull != f->OverflowList()) { + printf("Overflow: overflow list should be empty (#3)\n"); + return PR_FALSE; + } + + // and that the continuing frame has the remaining children + if (f1->ChildCount() != (b->ChildCount() - f->ChildCount())) { + printf("Overflow: continuing frame child count is wrong (#3): %d\n", f1->ChildCount()); + return PR_FALSE; + } + + // Verify that the content offsets of the continuing frame are correct + if (f1->GetFirstContentOffset() != f1->FirstChild()->GetIndexInParent()) { + printf("Overflow: continuing frame bad first content offset (#3): %d\n", f1->GetFirstContentOffset()); + return PR_FALSE; + } + if (f1->GetLastContentOffset() != (f1->LastChild()->GetIndexInParent())) { + printf("Overflow: continuing frame bad last content offset (#3): %d\n", f1->GetLastContentOffset()); + return PR_FALSE; + } + + NS_RELEASE(b); + return PR_TRUE; +} + +// Test handling of pushing/pulling children +// +// Here's what this function tests: +// 1. continuing frames pick up where their prev-in-flow left off +// 2. pulling up a child from a next-in-flow +// 3. pushing a child frame to a next-in-flow that already has children +// 4. pushing a child frame to an empty next-in-flow +// 5. pulling up children from a next-in-flow that has an overflow list +// 6. pulling up all the children across an empty frame +// 7. pulling up only some of the children across an empty frame +// 8. partially pulling up a child from a next-in-flow +static PRBool +TestPushingPulling(nsIPresContext* presContext) +{ + // Create an HTML container + nsIHTMLContent* b; + NS_NewHTMLContainer(&b, NS_NewAtom("SPAN")); + + // Append three fixed width elements. + b->AppendChild(new FixedSizeContent(100, 100)); + b->AppendChild(new FixedSizeContent(300, 300)); + b->AppendChild(new FixedSizeContent(200, 200)); + + // Create an inline frame for the HTML container and set its + // style context + InlineFrame* f = new InlineFrame(b, 0, nsnull); + nsIStyleContext* styleContext = presContext->ResolveStyleContextFor(b, nsnull); + + f->SetStyleContext(styleContext); + + // Reflow the inline frame so only the first frame fits + nsReflowMetrics reflowMetrics; + nsSize maxSize(100, 1000); + nsIFrame::ReflowStatus status; + + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frNotComplete == status, "bad status"); + NS_ASSERTION(f->ChildCount() == 1, "bad child count"); + + /////////////////////////////////////////////////////////////////////////// + // Test #1 + + // Create a continuing inline frame and test that it picks up with the second + // child frame. See TestOverflow() for checking the case where the continuing + // frame uses the overflow list, and TestSplittableChildren() for the + // case where the last child isn't complete + NS_ASSERTION(nsnull == f->OverflowList(), "unexpected overflow list"); + InlineFrame* f1 = new InlineFrame(b, 0, nsnull); + + f1->SetStyleContext(f->GetStyleContext(presContext)); + f->SetNextSibling(f1); + f->SetNextInFlow(f1); + f1->SetPrevInFlow(f); + + // Reflow the continuing inline frame. It should have the remainder of the + // children + maxSize.width = 1000; + status = f1->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frComplete == status, "bad continuing frame"); + + // Verify that the continuing inline frame has the remaining children + if (f1->ChildCount() != (b->ChildCount() - f->ChildCount())) { + printf("PushPull: continuing frame child count is wrong (#1): %d\n", f1->ChildCount()); + return PR_FALSE; + } + + /////////////////////////////////////////////////////////////////////////// + // Test #2 + + // Reflow the first inline frame so that two child frames now fit. This tests + // pulling up a child frame from the next-in-flow + maxSize.width = 400; + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frNotComplete == status, "bad status"); + NS_ASSERTION(f->ChildCount() == 2, "bad child count"); + NS_ASSERTION(f1->ChildCount() == 1, "bad continuing child count"); + + // Verify the last content offset of the first inline frame + if (f->GetLastContentOffset() != (f->ChildCount() - 1)) { + printf("PushPull: bad last content offset (#2): %d\n", f->GetLastContentOffset()); + return PR_FALSE; + } + + // Verify that the first/last content offsets of the continuing inline frame + // were updated correctly after pulling up a child + if (f1->GetFirstContentOffset() != f1->FirstChild()->GetIndexInParent()) { + printf("PushPull: continuing frame bad first content offset (#2): %d\n", f1->GetFirstContentOffset()); + return PR_FALSE; + } + if (f1->GetLastContentOffset() != (f1->LastChild()->GetIndexInParent())) { + printf("PushPull: continuing frame bad last content offset (#2): %d\n", f1->GetLastContentOffset()); + return PR_FALSE; + } + + /////////////////////////////////////////////////////////////////////////// + // Test #3 + + // Now reflow the inline frame so only the first child fits and verify the pushing + // code works correctly. + // + // This tests the case where we're pushing to a next-in-flow that already has + // child frames + maxSize.width = f->FirstChild()->GetWidth(); + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frNotComplete == status, "bad status"); + NS_ASSERTION(f->ChildCount() == 1, "bad child count"); + + // Verify the last content offset of the first inline frame + if (f->GetLastContentOffset() != 0) { + printf("PushPull: bad last content offset after push (#3): %d\n", + f->GetLastContentOffset()); + return PR_FALSE; + } + + // Verify the continuing inline frame has two children + if (f1->ChildCount() != 2) { + printf("PushPull: continuing child bad child count after push (#3): %d\n", + f1->ChildCount()); + return PR_FALSE; + } + + // Verify its first content offset is correct + if (f1->GetFirstContentOffset() != f1->FirstChild()->GetIndexInParent()) { + printf("PushPull: continuing child bad first content offset after push (#3): %d\n", + f1->GetFirstContentOffset()); + return PR_FALSE; + } + + // and that the last content offset is correct + if (f1->GetLastContentOffset() != (f1->LastChild()->GetIndexInParent())) { + printf("PushPull: continuing child bad last content offset after push (#3): %d\n", + f1->GetLastContentOffset()); + return PR_FALSE; + } + + // Now pull all the frames back to the first inline frame + maxSize.width = 1000; + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frComplete == status, "bad status"); + + // Verify the child count and last content offset of the first inline frame + if ((f->ChildCount() != b->ChildCount()) || + (f->GetLastContentOffset() != (f->ChildCount() - 1))) { + printf("PushPull: failed to pull up all the child frames (#3)\n"); + return PR_FALSE; + } + + // The continuing inline frame should have no children + if (f1->ChildCount() != 0) { + printf("PushPull: continuing child is not empty after pulling up all children (#3)\n"); + return PR_FALSE; + } + + /////////////////////////////////////////////////////////////////////////// + // Test #4 + + // Now reflow the inline frame so only the first child fits and verify the pushing + // code works correctly. + // + // This tests the case where we're pushing to an empty next-in-flow + maxSize.width = f->FirstChild()->GetWidth(); + f1->SetFirstContentOffset(f->NextChildOffset()); // don't trigger pre-reflow check of next-in-flow + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frNotComplete == status, "bad status"); + NS_ASSERTION(f->ChildCount() == 1, "bad child count"); + + // Verify the continuing inline frame has two children + if (f1->ChildCount() != 2) { + printf("PushPull: continuing child bad child count after push (#4): %d\n", + f1->ChildCount()); + return PR_FALSE; + } + + // Verify its first content offset is correct + if (f1->GetFirstContentOffset() != f1->FirstChild()->GetIndexInParent()) { + printf("PushPull: continuing child bad first content offset after push (#4): %d\n", + f1->GetFirstContentOffset()); + return PR_FALSE; + } + + // and that the last content offset is correct + if (f1->GetLastContentOffset() != (f1->LastChild()->GetIndexInParent())) { + printf("PushPull: continuing child bad last content offset after push (#4): %d\n", + f1->GetLastContentOffset()); + return PR_FALSE; + } + + /////////////////////////////////////////////////////////////////////////// + // Test #5 + + // Test pulling up children from a next-in-flow that has an overflow list. + // Reflow f1 so only one child fits + maxSize.width = 300; + status = f1->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frNotComplete == status, "bad status"); + NS_ASSERTION((f1->ChildCount() == 1) && (f1->GetLastContentOffset() == 1), "bad reflow"); + NS_ASSERTION(nsnull != f1->OverflowList(), "no overflow list"); + + // Now reflow the first inline frame so it's wide enough for all the child frames + maxSize.width = 1000; + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frComplete == status, "bad status"); + NS_ASSERTION((f->ChildCount() == 3) && (f->GetLastContentOffset() == 2), "bad mapping"); + + // The second frame should be be empty, and it should not have an overflow list + if (f1->ChildCount() != 0) { + printf("PushPull: continuing child isn't empty (#5)\n"); + return PR_FALSE; + } + if (nsnull != f1->OverflowList()) { + printf("PushPull: continuing child still has overflow list (#5)\n"); + return PR_FALSE; + } + + /////////////////////////////////////////////////////////////////////////// + // Test #6 + + // Test pulling up all the child frames across an empty frame, i.e. a frame + // from which we've already pulled up all the children + // + // Set it up so that there's one frame in 'f' and one frame in 'f1' + maxSize.width = 100; + f1->BreakFromPrevFlow(); + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frNotComplete == status, "bad status"); + NS_ASSERTION((f->ChildCount() == 1) && (f->GetLastContentOffset() == 0), "bad mapping"); + + maxSize.width = 300; + f1->AppendToFlow(f); + status = f1->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frNotComplete == status, "bad status"); + NS_ASSERTION((f1->ChildCount() == 1) && (f1->GetLastContentOffset() == 1), "bad mapping"); + NS_ASSERTION(nsnull != f1->OverflowList(), "no overflow list"); + + // Now create a third inline frame and have it map the third child frame + InlineFrame* f2 = new InlineFrame(b, 0, nsnull); + + f2->SetStyleContext(f->GetStyleContext(presContext)); + f1->SetNextSibling(f2); + f1->SetNextInFlow(f2); + f2->SetPrevInFlow(f1); + + maxSize.width = 1000; + status = f2->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frComplete == status, "bad status"); + NS_ASSERTION(nsnull == f1->OverflowList(), "overflow list"); + + // Now reflow the first inline frame wide enough so all the child frames fit + // XXX This isn't enough and we need one more test. We need to first + // pull up just one child, then reflow the first frame again so all + // the child frames fit. + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + + // Verify that the inline frame is complete + if (nsIFrame::frComplete != status) { + printf("PushPull: failed to pull-up across empty frame (#6)\n"); + return PR_FALSE; + } + + // Verify the inline frame maps all the children + if ((f->ChildCount() != 3) || (f->GetLastContentOffset() != 2)) { + printf("PushPull: bad last content offset or child count (#6)\n"); + return PR_FALSE; + } + + // Verify that the next two inline frames are empty + if (f1->ChildCount() != 0) { + printf("PushPull: second frame isn't empty (#6)\n"); + return PR_FALSE; + } + if (f2->ChildCount() != 0) { + printf("PushPull: third frame isn't empty (#6)\n"); + return PR_FALSE; + } + + /////////////////////////////////////////////////////////////////////////// + // Test #7 + + // Test pulling up only some of the child frames across an empty frame, i.e. + // a frame from which we've already pulled up all the children + // + // Set it up so that there's one child frame in the first inline frame + maxSize.width = 100; + f1->BreakFromPrevFlow(); + f2->BreakFromPrevFlow(); + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frNotComplete == status, "bad status"); + NS_ASSERTION(f->ChildCount() == 1, "bad child count"); + NS_ASSERTION(f->GetLastContentOffset() == 0, "bad mapping"); + + // And one frame in f1 + maxSize.width = 300; + f1->AppendToFlow(f); + status = f1->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frNotComplete == status, "bad status"); + NS_ASSERTION(f1->ChildCount() == 1, "bad child count"); + NS_ASSERTION((f1->GetFirstContentOffset() == 1) && (f1->GetLastContentOffset() == 1), "bad mapping"); + + // And one frame in f2 + f2->AppendToFlow(f1); + maxSize.width = 1000; + status = f2->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frComplete == status, "bad status"); + NS_ASSERTION(f2->ChildCount() == 1, "bad child count"); + NS_ASSERTION((f2->GetFirstContentOffset() == 2) && (f2->GetLastContentOffset() == 2), "bad mapping"); + + // Now reflow the first inline frame wide enough so that the first two child + // frames fit + maxSize.width = 400; + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + + // Verify that the first inline frame is not complete + if (nsIFrame::frNotComplete != status) { + printf("PushPull: bad status (#7)\n"); + return PR_FALSE; + } + + // Verify the first inline frame maps two children + if ((f->ChildCount() != 2) || (f->GetLastContentOffset() != 1)) { + printf("PushPull: bad last content offset or child count (#7)\n"); + return PR_FALSE; + } + + // Verify that the second inline frame is empty + if (f1->ChildCount() != 0) { + printf("PushPull: second frame isn't empty (#7)\n"); + return PR_FALSE; + } + + // and that it's content offset must be correct, because the third inline + // frame isn't empty + // Note: don't check the last content offset, because for empty frames the value + // is undefined... + if (f1->GetFirstContentOffset() != f->NextChildOffset()) { + printf("PushPull: second frame bad first content offset (#7): %d\n", f1->GetFirstContentOffset()); + return PR_FALSE; + } + + // Verify that the third inline frame has one child frame + if (f2->ChildCount() != 1) { + printf("PushPull: third frame bad child count (#7): %d\n", f2->ChildCount()); + return PR_FALSE; + } + + // and that its content offsets are correct + if ((f2->GetFirstContentOffset() != 2) || (f2->GetLastContentOffset() != 2)) { + printf("PushPull: third frame bad content mapping (#7)\n"); + return PR_FALSE; + } + + /////////////////////////////////////////////////////////////////////////// + // Test #8 + + // Test partially pulling up a child. First get all the child frames back into + // the first inline frame, and get rid of the third inline frame + f2->BreakFromPrevFlow(); + f1->SetNextSibling(nsnull); + + maxSize.width = 1000; + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frComplete == status, "bad status"); + NS_ASSERTION(f->ChildCount() == 3, "bad child count"); + f1->SetFirstContentOffset(f->NextChildOffset()); // don't trigger pre-reflow checks below + + // Now reflow the first inline frame so there are two frames pushed to the + // next-in-flow + maxSize.width = 100; + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frNotComplete == status, "bad status"); + NS_ASSERTION((f->ChildCount() == 1) && (f1->ChildCount() == 2), "bad child count"); + + // Reflow the first inline frame so that part only part of the second child frame + // fits. In order to test this we need to make the second piece of content + // splittable + FixedSizeContent* c2 = (FixedSizeContent*)b->ChildAt(1); + c2->SetIsSplittable(PR_TRUE); + + maxSize.width = 250; + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frNotComplete == status, "bad status"); + + // The first inline frame should have two child frames + if (f->ChildCount() != 2) { + printf("PushPull: bad child count when pulling up (#8): %d\n", f->ChildCount()); + return PR_FALSE; + } + + // it should have a last content offset of 1, and it's last content should + // not be complete + if ((f->GetLastContentOffset() != 1) || f->LastContentIsComplete()) { + printf("PushPull: bad content mapping when pulling up (#8)\n"); + return PR_FALSE; + } + + // The continuing inline frame should also have two child frame + if (f1->ChildCount() != 2) { + printf("PushPull: continuing frame bad child count (#8): %d\n", f1->ChildCount()); + return PR_FALSE; + } + + // and correct content offsets + if ((f1->GetFirstContentOffset() != f1->FirstChild()->GetIndexInParent()) || + (f1->GetLastContentOffset() != (f1->LastChild()->GetIndexInParent()))) { + printf("PushPull: continuing frame bad mapping (#8)\n"); + return PR_FALSE; + } + + // The first child of f1 should be in the flow + if (f1->FirstChild()->GetPrevInFlow() != f->LastChild()) { + printf("PushPull: continuing frame bad flow (#8)\n"); + return PR_FALSE; + } + + NS_RELEASE(b); + return PR_TRUE; +} + +// Test handling of splittable children +// +// Here's what this function tests: +// 1. reflow unmapped correctly handles child frames that need to split +// 2. reflow mapped correctly handles when the last child is incomplete +// 3. reflow mapped correctly handles the case of a child that's incomplete +// and that already has a next-in-flow +// 4. reflow mapped handles the case where a child that's incomplete now fits +// when reflowed again +// a) when the child has a next-in-flow +// b) when the child doesn't have a next-in-flow +// 5. continuing frame checks its prev-in-flow's last child and if it's incomplete +// creates a continuing frame +// 6. reflow mapped correctly handles child frames that need to be continued +// 7. pulling up across empty frames resulting from deleting a child's next-in-flows +static PRBool +TestSplittableChildren(nsIPresContext* presContext) +{ + // Create an HTML container + nsIHTMLContent* b; + NS_NewHTMLContainer(&b, NS_NewAtom("SPAN")); + + // Append three fixed width elements that can split + b->AppendChild(new FixedSizeContent(100, 100, PR_TRUE)); + b->AppendChild(new FixedSizeContent(300, 300, PR_TRUE)); + b->AppendChild(new FixedSizeContent(200, 200, PR_TRUE)); + + // Create an inline frame for the HTML container and set its + // style context + InlineFrame* f = new InlineFrame(b, 0, nsnull); + nsIStyleContext* styleContext = presContext->ResolveStyleContextFor(b, nsnull); + + f->SetStyleContext(styleContext); + + /////////////////////////////////////////////////////////////////////////// + // Test #1 + + // Reflow the inline frame so only half of the first frame fits. This tests + // reflow unmapped + nsReflowMetrics reflowMetrics; + nsSize maxSize(50, 1000); + nsIFrame::ReflowStatus status; + + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(f->ChildCount() == 1, "bad child count"); + + // Verify that the inline frame isn't complete + if (nsIFrame::frNotComplete != status) { + printf("Splittable: inline frame should be incomplete (#1): %d\n", status); + return PR_FALSE; + } + + // Verify the last content offset is correct + if (f->GetLastContentOffset() != 0) { + printf("Splittable: wrong last content offset (#1): %d\n", f->GetLastContentOffset()); + return PR_FALSE; + } + + // Verify that the last child isn't complete + if (f->LastContentIsComplete()) { + printf("Splittable: child should not be complete (#1)\n"); + return PR_FALSE; + } + + /////////////////////////////////////////////////////////////////////////// + // Test #2 + + // Now reflow the inline frame again and test reflow mapped + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(f->ChildCount() == 1, "bad child count"); + + // The inline frame should still be incomplete with a last content offset of 0 + if ((nsIFrame::frNotComplete != status) || + (f->GetLastContentOffset() != 0) || (f->LastContentIsComplete())) { + printf("Splittable: reflow mapped failed (#2)\n"); + return PR_FALSE; + } + + // There should be an overflow list containing the first child's next-in-flow + if ((nsnull == f->OverflowList()) || + (f->OverflowList() != f->FirstChild()->GetNextInFlow())) { + printf("Splittable: should be an overflow list (#2)\n"); + return PR_FALSE; + } + + // Verify that the first child has a null next sibling. Children on the overflow + // list should be disconnected from the mapped children + if (nsnull != f->FirstChild()->GetNextSibling()) { + printf("Splittable: first child has overflow list as next sibling (#2)\n"); + return PR_FALSE; + } + + /////////////////////////////////////////////////////////////////////////// + // Test #3 + + // Reflow it again with the same size and make sure we don't add any more + // frames to the overflow list + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frNotComplete == status, "bad status"); + NS_ASSERTION(f->ChildCount() == 1, "bad child count"); + + // The inline frame should still have a last content offset of 0 and + // the last content child should still be incomplete + if ((f->GetLastContentOffset() != 0) || (f->LastContentIsComplete())) { + printf("Splittable: reflow mapped again failed (#3)\n"); + return PR_FALSE; + } + + // The overflow list should still have only one child + if (LengthOf(f->OverflowList()) != 1) { + printf("Splittable: reflow mapped again has bad overflow list (#3)\n"); + return PR_FALSE; + } + + /////////////////////////////////////////////////////////////////////////// + // Test #4a + + // Now reflow the inline frame so that the the first child now completely fits. + // This tests how reflow mapped handles the case of a child that's incomplete + // and has a next-in-flow, and when reflowed now fits. + maxSize.width = 100; + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frNotComplete == status, "bad status"); + NS_ASSERTION(f->ChildCount() == 1, "bad child count"); + + // The inline frame should have a last content offset of 0 + if (f->GetLastContentOffset() != 0) { + printf("Splittable: wrong last content offset (#4a): %d\n", + f->GetLastContentOffset()); + return PR_FALSE; + } + + // The first child should now be complete + if (!f->LastContentIsComplete()) { + printf("Splittable: last child isn't complete (#4a)\n"); + return PR_FALSE; + } + + // it should not have a next-in-flow + if (nsnull != f->FirstChild()->GetNextInFlow()) { + printf("Splittable: unexpected next-in-flow (#4a)\n"); + return PR_FALSE; + } + + // and there should be no overflow list + if (nsnull != f->OverflowList()) { + printf("Splittable: unexpected overflow list (#4a)\n"); + return PR_FALSE; + } + + /////////////////////////////////////////////////////////////////////////// + // Test #4b + + // This is a variation of the previous test where the child doesn't have + // a next-in-flow. Reflow the inline frame so the first child is incomplete + maxSize.width = 50; + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(!f->LastContentIsComplete(), "last child should be incomplete"); + NS_ASSERTION(nsnull != f->OverflowList(), "no overflow list"); + NS_ASSERTION(f->FirstChild()->GetNextInFlow() == f->OverflowList(), "bad next-in-flow"); + + // Now get rid of the overflow list and the first child's next-in-flow + f->FirstChild()->SetNextInFlow(nsnull); + f->ClearOverflowList(); + + // Now reflow the inline frame so the first child fits. This tests that we + // correctly reset mLastContentIsComplete when the frame that was incomplete + // doesn't have a next-in-flow + maxSize.width = 100; + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frNotComplete == status, "bad status"); + NS_ASSERTION(f->ChildCount() == 1, "bad child count"); + + // Verify that the first child is complete + if (!f->LastContentIsComplete()) { + printf("Splittable: last content is NOT complete (#4b)\n"); + return PR_FALSE; + } + + /////////////////////////////////////////////////////////////////////////// + // Test #5 + + // Create a continuing inline frame and have it pick up with the second + // child + InlineFrame* f1 = new InlineFrame(b, 0, nsnull); + + f1->SetStyleContext(f->GetStyleContext(presContext)); + f->SetNextSibling(f1); + f->SetNextInFlow(f1); + f1->SetPrevInFlow(f); + + // Reflow the continuing inline frame so its second frame is not complete + maxSize.width = 150; + status = f1->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frNotComplete == status, "bad status"); + NS_ASSERTION((f1->GetFirstContentOffset() == 1) && (f1->GetLastContentOffset() == 1), "bad offsets"); + NS_ASSERTION(!f1->LastContentIsComplete(), "should not be complete"); + + // Create a third continuing inline frame and verify that it picks up by continuing + // the second child frame. This tests the case where the prev-in-flow's last + // child isn't complete and there's no overflow list + NS_ASSERTION(nsnull == f1->OverflowList(), "unexpected overflow list"); + InlineFrame* f2 = new InlineFrame(b, 0, nsnull); + + f2->SetStyleContext(f->GetStyleContext(presContext)); + f1->SetNextSibling(f2); + f1->SetNextInFlow(f2); + f2->SetPrevInFlow(f1); + + // Make the width large enough for all the remaining frames to fit + maxSize.width = 1000; + status = f2->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frComplete == status, "bad status"); + + // Verify the first child is a continuing frame of its prev-in-flow's + // child + if (f2->FirstChild()->GetPrevInFlow() != f1->FirstChild()) { + printf("Splittable: child frame bad prev-in-flow (#5)\n"); + return PR_FALSE; + } + + // Verify the two child frames have the same content offset and so + // do their parents + if ((f2->FirstChild()->GetIndexInParent() != f1->FirstChild()->GetIndexInParent()) || + (f2->GetFirstContentOffset() != f1->GetFirstContentOffset())) { + printf("Splittable: bad content offset (#5)\n"); + return PR_FALSE; + } + + // Verify that the third continuing inline frame is complete and that it has two children + if ((nsnull != f2->FirstChild()->GetNextInFlow()) || (f2->ChildCount() != 2)) { + printf("Splittable: bad continuing frame (#5)\n"); + return PR_FALSE; + } + + /////////////////////////////////////////////////////////////////////////// + // Test #6 + + // Test how reflow mapped handles the case where an existing child doesn't + // fit when reflowed. We care about the case where the child doesn't have + // a continuing frame and so we have to create one + // + // Reflow the first inline frame so all the child frames fit + maxSize.width = 1000; + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frComplete == status, "bad status"); + NS_ASSERTION((f->ChildCount() == 3) && (f->GetLastContentOffset() == 2), "bad count"); + + f1->SetFirstContentOffset(f->NextChildOffset()); // don't trigger pre-reflow checks + f2->SetFirstContentOffset(f->NextChildOffset()); // don't trigger pre-reflow checks + + // Now reflow it so that the first child needs to be continued + maxSize.width = 50; + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frNotComplete == status, "bad status"); + + // Verify there's only one child in f + if (f->ChildCount() != 1) { + printf("Splittable: bad child count (#6): %d\n", f->ChildCount()); + return PR_FALSE; + } + + // Verify the last content offset and that the last content is not complete + if ((f->GetLastContentOffset() != 0) || f->LastContentIsComplete()) { + printf("Splittable: bad content mapping (#6)\n"); + return PR_FALSE; + } + + // Verify that there are three children in the next-in-flow, and that + // the first child is a continuing frame + if (f1->ChildCount() != 3) { + printf("Splittable: continuing frame bad child count (#6): %d\n", + f1->ChildCount()); + return PR_FALSE; + } + if (f1->FirstChild()->GetPrevInFlow() != f->LastChild()) { + printf("Splittable: continuing frame bad child flow (#6)\n"); + return PR_FALSE; + } + + // Verify the next-in-flow's content offsets + if ((f1->GetFirstContentOffset() != 0) || (f1->GetLastContentOffset() != 2)) { + printf("Splittable: continuing frame bad mapping (#6)\n"); + return PR_FALSE; + } + + /////////////////////////////////////////////////////////////////////////// + // Test #7 + + // Test pulling up across empty frames resulting from deleting a child + // frame's next-in-flows + // + // Reflow the first inline frame so all the child frames fit + maxSize.width = 1000; + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frComplete == status, "bad status"); + NS_ASSERTION((f->ChildCount() == 3) && (f->GetLastContentOffset() == 2), "bad count"); + + f1->SetFirstContentOffset(f->NextChildOffset()); // don't trigger pre-reflow checks + f2->SetFirstContentOffset(f->NextChildOffset()); // don't trigger pre-reflow checks + + // Now reflow the first inline frame so that the second child frame is continued + maxSize.width = 200; + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frNotComplete == status, "bad status"); + + // Verify the first inline frame's child count is correct + if (f->ChildCount() != 2) { + printf("Splittable: bad child count (#7): %d\n", f->ChildCount()); + return PR_FALSE; + } + + // Verify the last content offset and that the last frame isn't complete + if ((f->GetLastContentOffset() != 1) || (f->LastContentIsComplete())) { + printf("Splittable: bad mapping (#7)\n"); + return PR_FALSE; + } + + // The second inline frame should have two children as well + if (f1->ChildCount() != 2) { + printf("Splittable: continuing frame bad child count (#7): %d\n", f1->ChildCount()); + return PR_FALSE; + } + + // and that its content offsets are correct + if ((f1->GetFirstContentOffset() != 1) || (f1->GetLastContentOffset() != 2)) { + printf("Splittable: continuing frame bad mapping (#7)\n"); + return PR_FALSE; + } + + // Now reflow the second inline frame so that only the continuing child frame + // fits and the last frame is pushed to the third inline frame + maxSize.width = 200; + status = f1->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + NS_ASSERTION(nsIFrame::frNotComplete == status, "bad status"); + + // Verify the second inline frame's child count and last content offset + if ((f1->ChildCount() != 1) || (f1->GetLastContentOffset() != 1)) { + printf("Splittable: continuing frame bad child count or mapping (#7)\n"); + return PR_FALSE; + } + + // Verify the third inline frame maps the last child frame and has correct + // content offsets + if ((f2->ChildCount() != 1) || + (f2->GetFirstContentOffset() != 2) || (f2->GetLastContentOffset() != 2)) { + printf("Splittable: last continuing frame bad child count or mapping (#7)\n"); + return PR_FALSE; + } + + // Now the real test. Reflow the first inline frame so all the child frames fit. + // What we're testing is that the pull-up code correctly handles the case where + // there's an empty frame that results from the second child frame's next-in-flow + // being deleted + maxSize.width = 1000; + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, nsnull); + + // The inline frame should be complete and map all three child frames + if ((nsIFrame::frComplete != status) || (f->ChildCount() != 3)) { + printf("Splittable: first inline frame does not map all the child frames (#7)\n"); + return PR_FALSE; + } + + NS_RELEASE(b); + return PR_TRUE; +} + +// Test computing the max element size +// +// Here's what this function tests: +// 1. reflow unmapped correctly computes the max element size +// 2. reflow mapped correctly computes the max element size +// 3. reflow mapped/unmapped work together to compute the correct result +// 4. pulling-up children code computes the correct result +static PRBool +TestMaxElementSize(nsIPresContext* presContext) +{ + // Create an HTML container + nsIHTMLContent* b; + NS_NewHTMLContainer(&b, NS_NewAtom("SPAN")); + + // Append three fixed width elements. + b->AppendChild(new FixedSizeContent(100, 100)); + b->AppendChild(new FixedSizeContent(300, 300)); + b->AppendChild(new FixedSizeContent(200, 200)); + + // Create an inline frame for the HTML container and set its + // style context + InlineFrame* f = new InlineFrame(b, 0, nsnull); + nsIStyleContext* styleContext = presContext->ResolveStyleContextFor(b, nsnull); + + f->SetStyleContext(styleContext); + + /////////////////////////////////////////////////////////////////////////// + // Test #1 + + // Reflow the inline frame and check our max element size computation when reflowing + // unmapped children + // + // Note: we've already tested elsewhere that we correctly handle the case + // where aMaxElementSize is NULL and that we don't GPF... + nsSize maxElementSize(0, 0); + nsReflowMetrics reflowMetrics; + nsSize maxSize(1000, 1000); + nsIFrame::ReflowStatus status; + + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, &maxElementSize); + + // Verify that the max element size is correct + NS_ASSERTION(nsIFrame::frComplete == status, "isn't complete"); + if ((maxElementSize.width != f->MaxChildWidth()) || + (maxElementSize.height != f->MaxChildHeight())) { + printf("MaxElementSize: wrong result in reflow unmapped (#1): (%d, %d)\n", + maxElementSize.width, maxElementSize.height); + return PR_FALSE; + } + + /////////////////////////////////////////////////////////////////////////// + // Test #2 + + // Now compute it again and check the computation when reflowing + // mapped children + maxElementSize.SizeTo(0, 0); + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, &maxElementSize); + NS_ASSERTION(nsIFrame::frComplete == status, "isn't complete"); + + if ((maxElementSize.width != f->MaxChildWidth()) || + (maxElementSize.height != f->MaxChildHeight())) { + printf("MaxElementSize: wrong result in reflow mapped (#2): (%d, %d)\n", + maxElementSize.width, maxElementSize.height); + return PR_FALSE; + } + + /////////////////////////////////////////////////////////////////////////// + // Test #3 + + // Check that reflow mapped/unmapped work together. Reflow the inline frame + // so that only the first two frames (including the largest frame) fit + nsIFrame* maxChild = f->ChildAt(1); + nsPoint origin; + + maxChild->GetOrigin(origin); + maxSize.width = origin.x + maxChild->GetWidth(); + maxElementSize.SizeTo(0, 0); + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, &maxElementSize); + + if ((nsIFrame::frNotComplete != status) || (f->ChildCount() != 2)) { + printf("MaxElementSize: reflow failed (#3)\n"); + return PR_FALSE; + } + + // Now reflow it again and check that the maximum element size is correct + maxSize.width = 1000; + maxElementSize.SizeTo(0, 0); + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, &maxElementSize); + NS_ASSERTION(nsIFrame::frComplete == status, "isn't complete"); + + if ((maxElementSize.width != f->MaxChildWidth()) || + (maxElementSize.height != f->MaxChildHeight())) { + printf("MaxElementSize: wrong result in reflow mapped/unmapped (#3): (%d, %d)\n", + maxElementSize.width, maxElementSize.height); + return PR_FALSE; + } + + /////////////////////////////////////////////////////////////////////////// + // Test #4 + + // Last thing to check is pulling up children. Reflow it so only the first two + // frames (including the largest frame) fit + maxChild = f->ChildAt(1); + maxChild->GetOrigin(origin); + maxSize.width = origin.x + maxChild->GetWidth(); + maxElementSize.SizeTo(0, 0); + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, &maxElementSize); + NS_ASSERTION(f->ChildCount() == 2, "unexpected child count"); + + // Create a continuing inline frame and reflow it + InlineFrame* f1 = new InlineFrame(b, 0, nsnull); + + f1->SetStyleContext(f->GetStyleContext(presContext)); + f->SetNextSibling(f1); + f->SetNextInFlow(f1); + f1->SetPrevInFlow(f); + maxSize.width = 1000; + status = f1->ResizeReflow(presContext, reflowMetrics, maxSize, &maxElementSize); + NS_ASSERTION((nsIFrame::frComplete == status) && (f1->ChildCount() == 1), "bad continuing frame"); + + // Now reflow the first inline frame so all child frames fit, and verify the + // max element size is correct + maxElementSize.SizeTo(0, 0); + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, &maxElementSize); + NS_ASSERTION(nsIFrame::frComplete == status, "isn't complete"); + NS_ASSERTION(f1->ChildCount() == 0, "pull-up failed"); + + if ((maxElementSize.width != f->MaxChildWidth()) || + (maxElementSize.height != f->MaxChildHeight())) { + printf("MaxElementSize: wrong result in reflow mapped/pull-up (#4): (%d, %d)\n", + maxElementSize.width, maxElementSize.height); + return PR_FALSE; + } + + // Now reflow it so that the largest size frame is in the continuing inline frame + f1->SetFirstContentOffset(f->NextChildOffset()); // don't trigger pre-reflow checks + maxSize.width = f->FirstChild()->GetWidth(); + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, &maxElementSize); + NS_ASSERTION(f->ChildCount() == 1, "unexpected child count"); + NS_ASSERTION(f1->ChildCount() == 2, "unexpected child count"); + + // Now reflow the first inline frame so all child frames fit, and verify the + // max element size is correct + maxSize.width = 1000; + maxElementSize.SizeTo(0, 0); + status = f->ResizeReflow(presContext, reflowMetrics, maxSize, &maxElementSize); + NS_ASSERTION(nsIFrame::frComplete == status, "isn't complete"); + NS_ASSERTION(f1->ChildCount() == 0, "pull-up failed"); + + if ((maxElementSize.width != f->MaxChildWidth()) || + (maxElementSize.height != f->MaxChildHeight())) { + printf("MaxElementSize: wrong result in reflow mapped/pull-up (#4): (%d, %d)\n", + maxElementSize.width, maxElementSize.height); + return PR_FALSE; + } + + NS_RELEASE(b); + return PR_TRUE; +} + +int main(int argc, char** argv) +{ + // Create test document and presentation context + MyDocument *myDoc = new MyDocument(); + nsIPresContext* presContext; + + NS_NewGalleyContext(&presContext); + + // Test basic reflowing of unmapped children + if (!TestReflowUnmapped(presContext)) { + return -1; + } + + // Test the case where the frame max size is too small for even one child frame + if (!TestChildrenThatDontFit(presContext)) { + return -1; + } + + if (!TestOverflow(presContext)) { + return -1; + } + + if (!TestPushingPulling(presContext)) { + return -1; + } + + if (!TestSplittableChildren(presContext)) { + return -1; + } + + if (!TestMaxElementSize(presContext)) { + return -1; + } + + /* + if (!TestIncremental(presContext)) { + return -1; + } + + if (!TestBorderPadding(presContext)) { + return -1; + } + + if (!TestChildMargins(presContext)) { + return -1; + } + + if (!TestAlignment(presContext)) { + return -1; + } + + if (!TestDisplayNone(presContext)) { + return -1; + } + + if (!TestRelativePositioning(presContext)) { + return -1; + } + + if (!TestAbsolutePositiong(presContext)) { + return -1; + } + */ + + presContext->Release(); + myDoc->Release(); + return 0; +} diff --git a/mozilla/layout/html/tests/css/INVALID.css b/mozilla/layout/html/tests/css/INVALID.css new file mode 100644 index 00000000000..bdd29017096 --- /dev/null +++ b/mozilla/layout/html/tests/css/INVALID.css @@ -0,0 +1,391 @@ +/* + * 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. + */ +// Test of illegal CSS1 input. +// Illegal @ rules +@ignored; +P { color: purple } +@ignored [ skip me ]; +P { color: purple } +@ignored { skip me } +P { color: purple } +@ignored ( skip me too ); +P { color: purple } + +// Handle dangling semi-colons. Outside the scope of the CSS1 document +// but a reasonable parser should be able to eat them. +@extra-semicolon;; +P { color: purple } + +// These are all properties that have an extra keyword (fish) at the +// end. CSS1 says that such properties are to be ignored. Because the +// properties are all set in the BODY tag we can see if anything +// happens to invalid.html when this sheet is loaded (there should be +// no effect because the entire declaration block should be skipped). +BODY { + word-spacing: normal fish; + wOrd-spacing: 12.0em fish; + WoRd-Spacing: 12.0eX fish; + worD-Spacing: 12PX fish; + word-Spacing: 12.0In fish; + word-sPacing: 12.0cm fish; + word-spAcing: 12.0mm fish; + word-spaCing: 12.0pt fish; + word-spacIng: 12.0pc fish; + color: red fish; + color: rgb(0, 0, 0) fish; + color: rGb(110%, 23, 9123784328342834) fish; + color: #f00 fish; + color: #ff00ff fish; + background: red none repeat scroll 20% 30% fish; + background: none repeat scroll 20% 30% red fish; + background: repeat scroll 20% 30% red none fish; + background: scroll 20% 30% red none repeat fish; + background: 20% 30% red none repeat scroll fish; + background-color: blue fish; + background-color: rgb(0, 0, 0) fish; + background-color: rGb(110%, 23, 9123784328342834) fish; + BackGround-Color: Transparent fish; + background-image: none fish; + background-image: url(fowl.url) fish; + background-image: url( fowl.url ) fish; + background-image: url( "fowl.url" ) fish; + background-image: url( 'fowl.url' ) fish; + background-repeat: repeat fish; + background-repeat: repeat-x fish; + background-repeat: repeat-y fish; + background-repeat: no-repeat fish; + Background-Attachment: Scroll fish; + Background-Attachment: Fixed fish; + background-position: 73% fish; + background-position: -73% fish; + background-position: +3% fish; + background-position: +3.5% fish; + background-position: 10% 20% fish; + background-position: 10% 23in fish; + background-position: 23in fish; + background-position: 23in 10% fish; + Background-Position: 23IN 30CM fish; + Background-Position: top left fish; + Background-Position: left top fish; + Background-Position: top fish; + Background-Position: top center fish; + Background-Position: center top fish; + Background-Position: right top fish; + Background-Position: top right fish; + Background-Position: left fish; + Background-Position: left center fish; + Background-Position: center left fish; + Background-Position: right fish; + Background-Position: right center fish; + Background-Position: center right fish; + Background-Position: bottom fish; + Background-Position: bottom center fish; + Background-Position: center bottom fish; + Background-Position: bottom right fish; + Background-Position: right bottom fish; + font: italic small-caps bold 12pt helvetica + font: italic bold small-caps 12pt helvetica + font: small-caps bold italic 12pt helvetica + font: small-caps italic bold 12pt helvetica + font: bold italic small-caps 12pt helvetica + font: bold small-caps italic 12pt helvetica + font: bold 12pt helvetica + font: 12pt helvetica + font: 12pt/14pt sans-serif 27; + font: 80% sans-serif 27; + font: x-large/110% "new century schoolbook", serif 27; + font: bold italic large Palatino, serif 27; + font: normal small-caps 120%/120% fantasy 27; + font-family: gill, helvetica, times new roman, sans-serif 27; + font-style: normal fish; + font-style: italic fish; + font-style: oblique fish; + font-variant: normal fish; + font-variant: small-caps fish; + font-weight: normal fish; + font-weight: bold fish; + font-weight: bolder fish; + font-weight: lighter fish; + font-weight: 100 fish; + font-weight: 200 fish; + font-weight: 300 fish; + font-weight: 400 fish; + font-weight: 500 fish; + font-weight: 600 fish; + font-weight: 700 fish; + font-weight: 800 fish; + font-weight: 900 fish; + font-size: Xx-smAll fish; + font-size: x-Small fish; + font-size: Small fish; + font-size: Medium fish; + font-size: LaRgE fish; + font-size: x-LaRgE fish; + font-size: Xx-LaRgE fish; + font-size: LaRgEr fish; + font-size: smalLer fish; + font-size: 3.0in fish; + font-size: 120% fish; + letter-spacing: normal fish; + letter-spacing: 3.0in fish; + text-decoration: none fish; + text-decoration: underline fish; + text-decoration: overline underline fish; + text-decoration: line-through overline underline fish; + text-decoration: blink line-through overline underline fish; + vertical-align: baseline fish; + vertical-align: sub fish; + vertical-align: super fish; + vertical-align: top fish; + vertical-align: text-top fish; + vertical-align: middle fish; + vertical-align: bottom fish; + vertical-align: text-bottom fish; + vertical-align: 120% fish; + text-transform: capitalize fish; + text-transform: uppercase fish; + text-transform: lowercase fish; + text-transform: none fish; + text-align: left fish; + text-align: right fish; + text-align: center fish; + text-align: justify fish; + text-indent: 3.0in fish; + text-indent: 120% fish; + line-height: normal fish; + line-height: 17 fish; + line-height: 17.0in fish; + line-height: 17% fish; + margin-top: 17.0in fish; + margin-top: 120% fish; + margin-top: auto fish; + margin-right: 17.0in fish; + margin-right: 120% fish; + margin-right: auto fish; + margin-bottom: 17.0in fish; + margin-bottom: 120% fish; + margin-bottom: auto fish; + margin-left: 17.0in fish; + margin-left: 120% fish; + margin-left: auto fish; + margin: 17.0in fish; + margin: 120% fish; + margin: auto fish; + margin: 17.0in auto fish; + margin: 17.0in 120% fish; + margin: 17.0in 17.0in fish; + margin: 120% 17.0in fish; + margin: 120% auto fish; + margin: 120% 120% fish; + margin: auto 120% fish; + margin: auto 17.0in fish; + margin: auto auto fish; + margin: 17.0in 17.0in 17.0in fish; + margin: 17.0in 17.0in 120% fish; + margin: 17.0in 17.0in auto fish; + margin: 17.0in 120% 17.0in fish; + margin: 17.0in auto 17.0in fish; + margin: 17.0in 17.0in 17.0in 17.0in fish; + margin: 17.0in 120% 17.0in 17.0in fish; + margin: 120% 120% 17.0in 17.0in fish; + margin: 120% 120% 120% 17.0in fish; + margin: 120% 120% 120% 120% fish; + padding-top: 17.0in fish; + padding-top: 120% fish; + padding-right: 17.0in fish; + padding-right: 120% fish; + padding-bottom: 17.0in fish; + padding-bottom: 120% fish; + padding-left: 17.0in fish; + padding-left: 120% fish; + padding: 17.0in fish; + padding: 120% fish; + padding: 17.0in 120% fish; + padding: 17.0in 17.0in fish; + padding: 120% 17.0in fish; + padding: 120% 120% fish; + padding: 17.0in 17.0in 17.0in fish; + padding: 17.0in 17.0in 120% fish; + padding: 17.0in 120% 17.0in fish; + padding: 17.0in 17.0in 17.0in 17.0in fish; + padding: 17.0in 120% 17.0in 17.0in fish; + padding: 120% 120% 17.0in 17.0in fish; + padding: 120% 120% 120% 17.0in fish; + padding: 120% 120% 120% 120% fish; + border-top-width: thin fish; + border-top-width: medium fish; + border-top-width: thick fish; + border-top-width: 3.0in fish; + border-right-width: thin fish; + border-right-width: medium fish; + border-right-width: thick fish; + border-right-width: 3.0in fish; + border-bottom-width: thin fish; + border-bottom-width: medium fish; + border-bottom-width: thick fish; + border-bottom-width: 3.0in fish; + border-left-width: thin fish; + border-left-width: medium fish; + border-left-width: thick fish; + border-left-width: 3.0in fish; + border-width: thin fish; + border-width: 3.0in fish; + border-width: thick thick fish; + border-width: 3.0in thick fish; + border-width: thin 3.0in thick fish; + border-width: 3.0in thick thin fish; + border-width: 3.0in thick medium fish; + border-color: red fish; + border-color: red blue fish; + border-color: red blue rgb(0, 0, 0) fish; + border-color: red blue green yellow fish; + border-style: none fish; + border-style: dotted fish; + border-style: dashed fish; + border-style: solid fish; + border-style: double fish; + border-style: groove fish; + border-style: ridge fish; + border-style: inset fish; + border-style: outset fish; + border-style: dashed none fish; + border-style: dashed dotted none fish; + border-style: dashed dotted inset none fish; + border-top: 3.0in fish; + border-top: thin fish; + border-top: 3.0in dashed fish; + border-top: thin dotted fish; + border-top: 3.0in dashed red fish; + border-top: thin dotted green fish; + border-top: green thin dotted fish; + border-top: green dotted thin fish; + border-right: 3.0in fish; + border-right: thin fish; + border-right: 3.0in dashed fish; + border-right: thin dotted fish; + border-right: 3.0in dashed red fish; + border-right: thin dotted green fish; + border-right: green thin dotted fish; + border-right: green dotted thin fish; + border-bottom: 3.0in fish; + border-bottom: thin fish; + border-bottom: 3.0in dashed fish; + border-bottom: thin dotted fish; + border-bottom: 3.0in dashed red fish; + border-bottom: thin dotted green fish; + border-bottom: green thin dotted fish; + border-bottom: green dotted thin fish; + border-left: 3.0in fish; + border-left: thin fish; + border-left: 3.0in dashed fish; + border-left: thin dotted fish; + border-left: 3.0in dashed red fish; + border-left: thin dotted green fish; + border-left: green thin dotted fish; + border-left: green dotted thin fish; + border: 3.0in fish; + border: thin fish; + border: 3.0in dashed fish; + border: thin dotted fish; + border: 3.0in dashed red fish; + border: thin dotted green fish; + border: green thin dotted fish; + border: green dotted thin fish; + width: 3.0in fish; + width: 120% fish; + width: auto fish; + height: 3.0in fish; + height: auto fish; + float: left fish; + float: right fish; + float: none fish; + clear: none fish; + clear: left fish; + clear: right fish; + clear: both fish; + white-space: normal fish; + white-space: pre fish; + white-space: nowrap fish; + list-style-type: disc fish; + list-style-type: circle fish; + list-style-type: square fish; + list-style-type: decimal fish; + list-style-type: lower-roman fish; + list-style-type: upper-roman fish; + list-style-type: lower-alpha fish; + list-style-type: upper-alpha fish; + list-style-type: none fish; + list-style-image: none fish; + list-style-image: url(fowl.gif) fish; + list-style-position: inside fish; + list-style-position: outside fish; + list-style: disc fish; + list-style: disc inside fish; + list-style: inside disc fish; + list-style: inside disc url(fowl.gif) fish; + list-style: disc url(fowl.gif) inside fish; + list-style: url(fowl.gif) inside disc fish; +} +P { color: purple } + +// Illegal color values +InvalidColor { + color: RGB(110; + color: RGB(110,; + color: RGB(110, 23; + color: RGB(110, 23,; + color: RGB(110, 23, 37; + color: RGB(110, 23, fowl; + color: RGB(110%, 23); + color: RGB(110%); + color: #7xy; + color: #777888999; + color:; + color:#; + color:#x; + color:#7; +} +P { color: purple } + +// Illegal numeric values +InvalidNumber { + list-indent: 2..3; + list-indent: 17a; + list-indent: 1.0e25; + list-indent: 10quadloos; +} +P { color: purple } + +// Illegal url values +InvalidURL { + background-image: url; + background-image: url(goaway; + background-image: url( this (is) some nonsense ); +} +P { color: purple } + +// Illegal rules +P[align], UL { + color: red; + font-size: large +} +P { color: purple } + +!27 32 hike! { + color: red; +} +P { color: purple } diff --git a/mozilla/layout/html/tests/css/SELECTORS.css b/mozilla/layout/html/tests/css/SELECTORS.css new file mode 100644 index 00000000000..84a90807133 --- /dev/null +++ b/mozilla/layout/html/tests/css/SELECTORS.css @@ -0,0 +1,32 @@ +/* + * 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. + */ +// Combinatorics for selectors +Tag { color: purple } +Tag#Id { color: purple } +Tag#Id.Class { color: purple } +Tag#Id.Class:Pseudo { color: purple } +Tag#Id:Pseudo { color: purple } +Tag.Class { color: purple } +Tag.Class:Pseudo { color: purple } +Tag:Pseudo { color: purple } +#Id { color: purple } +#Id.Class { color: purple } +#Id.Class:Pseudo { color: purple } +#Id:Pseudo { color: purple } +.Class { color: purple } +.Class:Pseudo { color: purple } +:Pseudo { color: purple } diff --git a/mozilla/layout/html/tests/css/background-attachment.css b/mozilla/layout/html/tests/css/background-attachment.css new file mode 100644 index 00000000000..caf801e05df --- /dev/null +++ b/mozilla/layout/html/tests/css/background-attachment.css @@ -0,0 +1,28 @@ +/* + * 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. + */ +GOOD { Background-Attachment: Scroll; } +GOOD { Background-Attachment: Fixed; } +BAD { Background-Attachments: Fixed; } +BAD { Background-Attachment: Scroll Fixed; } +BAD { Background-Attachment: Fixed tiny; } +BAD { Background-Attachment: tiny Scroll; } +BAD { Background-Attachment: tiny Fixed; } +BAD { Background-Attachment: medium; } +BAD { Background-Attachment: 12pt; } +BAD { Background-Attachment: red; } +BAD { Background-Attachment: url("foo.html"); } +BAD { Background-Attachment: smelly; } diff --git a/mozilla/layout/html/tests/css/background-color.css b/mozilla/layout/html/tests/css/background-color.css new file mode 100644 index 00000000000..4175cdf90fb --- /dev/null +++ b/mozilla/layout/html/tests/css/background-color.css @@ -0,0 +1,24 @@ +/* + * 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. + */ +GOOD { background-color: blue; } +GOOD { background-color: rgb(0, 0, 0); } +GOOD { background-color: rGb(110%, 23, 9123784328342834); } +GOOD { BackGround-Color: Transparent; } +BAD { BackGround-Color: beeble; } +BAD { BackGround-Color: 27; } +BAD { BackGround-Color: #23; } +BAD { BackGround-Color: url(fish; } diff --git a/mozilla/layout/html/tests/css/background-image.css b/mozilla/layout/html/tests/css/background-image.css new file mode 100644 index 00000000000..5e273811cb3 --- /dev/null +++ b/mozilla/layout/html/tests/css/background-image.css @@ -0,0 +1,23 @@ +/* + * 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. + */ +GOOD { background-image: none; } +GOOD { background-image: url(fowl.url); } +GOOD { background-image: url( fowl.url ); } +GOOD { background-image: url( "fowl.url" ); } +GOOD { background-image: url( 'fowl.url' ); } +BAD { background-image: none url(fowl.url); } +BAD { background-image: url(fowl.url) none; } diff --git a/mozilla/layout/html/tests/css/background-position.css b/mozilla/layout/html/tests/css/background-position.css new file mode 100644 index 00000000000..0e6313dca74 --- /dev/null +++ b/mozilla/layout/html/tests/css/background-position.css @@ -0,0 +1,43 @@ +/* + * 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. + */ +GOOD { background-position: 73%; } +GOOD { background-position: -73%; } +GOOD { background-position: +3%; } +GOOD { background-position: +3.5%; } +GOOD { background-position: 10% 20%; } +GOOD { background-position: 10% 23in; } +GOOD { background-position: 23in; } +GOOD { background-position: 23in 10%; } +GOOD { Background-Position: 23IN 30CM; } +GOOD { Background-Position: top left; } +GOOD { Background-Position: left top; } +GOOD { Background-Position: top; } +GOOD { Background-Position: top center; } +GOOD { Background-Position: center top; } +GOOD { Background-Position: right top; } +GOOD { Background-Position: top right; } +GOOD { Background-Position: left; } +GOOD { Background-Position: left center; } +GOOD { Background-Position: center left; } +GOOD { Background-Position: right; } +GOOD { Background-Position: right center; } +GOOD { Background-Position: center right; } +GOOD { Background-Position: bottom; } +GOOD { Background-Position: bottom center; } +GOOD { Background-Position: center bottom; } +GOOD { Background-Position: bottom right; } +GOOD { Background-Position: right bottom; } diff --git a/mozilla/layout/html/tests/css/background-repeat.css b/mozilla/layout/html/tests/css/background-repeat.css new file mode 100644 index 00000000000..d8ff9010e80 --- /dev/null +++ b/mozilla/layout/html/tests/css/background-repeat.css @@ -0,0 +1,25 @@ +/* + * 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. + */ +GOOD { background-repeat: repeat; } +GOOD { background-repeat: repeat-x; } +GOOD { background-repeat: repeat-y; } +GOOD { background-repeat: no-repeat; } +BAD { background-repeat: medium; } +BAD { background-repeat: #23; } +BAD { background-repeat: 23pt; } +BAD { background-repeat: "foo"; } +BAD { background-repeat: repeat-x repeat-y; } diff --git a/mozilla/layout/html/tests/css/background.css b/mozilla/layout/html/tests/css/background.css new file mode 100644 index 00000000000..9919c28fd7e --- /dev/null +++ b/mozilla/layout/html/tests/css/background.css @@ -0,0 +1,32 @@ +/* + * 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. + */ +GOOD { background: red; } +GOOD { background: red repeat-x; } +GOOD { background: red fixed; } +GOOD { background: fixed 20% 30%; } +GOOD { background: red none repeat scroll 20% 30%; } +GOOD { background: none repeat scroll 20% 30% red; } +GOOD { background: repeat scroll 20% 30% red none; } +GOOD { background: scroll 20% 30% red none repeat; } +GOOD { background: 20% 30% red none repeat scroll; } +BAD { background: 20% 30% red none repeat scroll fish; } +BAD { background: 20% 30% red none repeat fish scroll; } +BAD { background: 20% 30% red none fish repeat scroll; } +BAD { background: 20% 30% red fish none repeat scroll; } +BAD { background: 20% 30% fish red none repeat scroll; } +BAD { background: 20% fish 30% red none repeat scroll; } +BAD { background: fish 20% 30% red none repeat scroll; } diff --git a/mozilla/layout/html/tests/css/border-bottom-width.css b/mozilla/layout/html/tests/css/border-bottom-width.css new file mode 100644 index 00000000000..d35cb0d9ec8 --- /dev/null +++ b/mozilla/layout/html/tests/css/border-bottom-width.css @@ -0,0 +1,23 @@ +/* + * 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. + */ +GOOD { border-bottom-width: thin; } +GOOD { border-bottom-width: medium; } +GOOD { border-bottom-width: thick; } +GOOD { border-bottom-width: 3.0in; } +BAD { border-bottom-width: narrow; } +BAD { border-bottom-width: "foo"; } +BAD { border-bottom-width: center; } diff --git a/mozilla/layout/html/tests/css/border-bottom.css b/mozilla/layout/html/tests/css/border-bottom.css new file mode 100644 index 00000000000..d1e4283fd10 --- /dev/null +++ b/mozilla/layout/html/tests/css/border-bottom.css @@ -0,0 +1,24 @@ +/* + * 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. + */ +GOOD { border-bottom: 3.0in; } +GOOD { border-bottom: thin; } +GOOD { border-bottom: 3.0in dashed; } +GOOD { border-bottom: thin dotted; } +GOOD { border-bottom: 3.0in dashed red; } +GOOD { border-bottom: thin dotted green; } +GOOD { border-bottom: green thin dotted; } +GOOD { border-bottom: green dotted thin; } diff --git a/mozilla/layout/html/tests/css/border-color.css b/mozilla/layout/html/tests/css/border-color.css new file mode 100644 index 00000000000..fdecde99399 --- /dev/null +++ b/mozilla/layout/html/tests/css/border-color.css @@ -0,0 +1,20 @@ +/* + * 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. + */ +GOOD { border-color: red; } +GOOD { border-color: red blue; } +GOOD { border-color: red blue rgb(0, 0, 0); } +GOOD { border-color: red blue green yellow; } diff --git a/mozilla/layout/html/tests/css/border-left-width.css b/mozilla/layout/html/tests/css/border-left-width.css new file mode 100644 index 00000000000..1923f205d26 --- /dev/null +++ b/mozilla/layout/html/tests/css/border-left-width.css @@ -0,0 +1,20 @@ +/* + * 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. + */ +GOOD { border-left-width: thin; } +GOOD { border-left-width: medium; } +GOOD { border-left-width: thick; } +GOOD { border-left-width: 3.0in; } diff --git a/mozilla/layout/html/tests/css/border-left.css b/mozilla/layout/html/tests/css/border-left.css new file mode 100644 index 00000000000..56204fb1f68 --- /dev/null +++ b/mozilla/layout/html/tests/css/border-left.css @@ -0,0 +1,24 @@ +/* + * 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. + */ +GOOD { border-left: 3.0in; } +GOOD { border-left: thin; } +GOOD { border-left: 3.0in dashed; } +GOOD { border-left: thin dotted; } +GOOD { border-left: 3.0in dashed red; } +GOOD { border-left: thin dotted green; } +GOOD { border-left: green thin dotted; } +GOOD { border-left: green dotted thin; } diff --git a/mozilla/layout/html/tests/css/border-right-width.css b/mozilla/layout/html/tests/css/border-right-width.css new file mode 100644 index 00000000000..b18d5c5923e --- /dev/null +++ b/mozilla/layout/html/tests/css/border-right-width.css @@ -0,0 +1,20 @@ +/* + * 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. + */ +GOOD { border-right-width: thin; } +GOOD { border-right-width: medium; } +GOOD { border-right-width: thick; } +GOOD { border-right-width: 3.0in; } diff --git a/mozilla/layout/html/tests/css/border-right.css b/mozilla/layout/html/tests/css/border-right.css new file mode 100644 index 00000000000..e58820e15a7 --- /dev/null +++ b/mozilla/layout/html/tests/css/border-right.css @@ -0,0 +1,24 @@ +/* + * 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. + */ +GOOD { border-right: 3.0in; } +GOOD { border-right: thin; } +GOOD { border-right: 3.0in dashed; } +GOOD { border-right: thin dotted; } +GOOD { border-right: 3.0in dashed red; } +GOOD { border-right: thin dotted green; } +GOOD { border-right: green thin dotted; } +GOOD { border-right: green dotted thin; } diff --git a/mozilla/layout/html/tests/css/border-style.css b/mozilla/layout/html/tests/css/border-style.css new file mode 100644 index 00000000000..aef6d55e79a --- /dev/null +++ b/mozilla/layout/html/tests/css/border-style.css @@ -0,0 +1,28 @@ +/* + * 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. + */ +GOOD { border-style: none; } +GOOD { border-style: dotted; } +GOOD { border-style: dashed; } +GOOD { border-style: solid; } +GOOD { border-style: double; } +GOOD { border-style: groove; } +GOOD { border-style: ridge; } +GOOD { border-style: inset; } +GOOD { border-style: outset; } +GOOD { border-style: dashed none; } +GOOD { border-style: dashed dotted none; } +GOOD { border-style: dashed dotted inset none; } diff --git a/mozilla/layout/html/tests/css/border-top-width.css b/mozilla/layout/html/tests/css/border-top-width.css new file mode 100644 index 00000000000..267ad2349d2 --- /dev/null +++ b/mozilla/layout/html/tests/css/border-top-width.css @@ -0,0 +1,20 @@ +/* + * 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. + */ +GOOD { border-top-width: thin; } +GOOD { border-top-width: medium; } +GOOD { border-top-width: thick; } +GOOD { border-top-width: 3.0in; } diff --git a/mozilla/layout/html/tests/css/border-top.css b/mozilla/layout/html/tests/css/border-top.css new file mode 100644 index 00000000000..341b6a09384 --- /dev/null +++ b/mozilla/layout/html/tests/css/border-top.css @@ -0,0 +1,24 @@ +/* + * 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. + */ +GOOD { border-top: 3.0in; } +GOOD { border-top: thin; } +GOOD { border-top: 3.0in dashed; } +GOOD { border-top: thin dotted; } +GOOD { border-top: 3.0in dashed red; } +GOOD { border-top: thin dotted green; } +GOOD { border-top: green thin dotted; } +GOOD { border-top: green dotted thin; } diff --git a/mozilla/layout/html/tests/css/border-width.css b/mozilla/layout/html/tests/css/border-width.css new file mode 100644 index 00000000000..dd8d8b04ca7 --- /dev/null +++ b/mozilla/layout/html/tests/css/border-width.css @@ -0,0 +1,25 @@ +/* + * 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. + */ +GOOD { border-width: thin; } +GOOD { border-width: medium; } +GOOD { border-width: thick; } +GOOD { border-width: 3.0in; } +GOOD { border-width: thin thin; } +GOOD { border-width: 3.0in thin; } +GOOD { border-width: thin 3.0in thin; } +GOOD { border-width: 3.0in thin thin; } +GOOD { border-width: 3.0in thin medium; } diff --git a/mozilla/layout/html/tests/css/border.css b/mozilla/layout/html/tests/css/border.css new file mode 100644 index 00000000000..86967fd2a40 --- /dev/null +++ b/mozilla/layout/html/tests/css/border.css @@ -0,0 +1,24 @@ +/* + * 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. + */ +GOOD { border: 3.0in; } +GOOD { border: thin; } +GOOD { border: 3.0in dashed; } +GOOD { border: thin dotted; } +GOOD { border: 3.0in dashed red; } +GOOD { border: thin dotted green; } +GOOD { border: green thin dotted; } +GOOD { border: green dotted thin; } diff --git a/mozilla/layout/html/tests/css/bugs/bug01.css b/mozilla/layout/html/tests/css/bugs/bug01.css new file mode 100644 index 00000000000..1a0a5d0223d --- /dev/null +++ b/mozilla/layout/html/tests/css/bugs/bug01.css @@ -0,0 +1,19 @@ +/* + * 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. + */ +/* 0 numbers were causing data to be eaten */ +DD { margin-top: 0; margin-left: .25in; } +A:link { color: blue; text-decoration: underline } diff --git a/mozilla/layout/html/tests/css/bugs/bug02.css b/mozilla/layout/html/tests/css/bugs/bug02.css new file mode 100644 index 00000000000..f3b0f6a391e --- /dev/null +++ b/mozilla/layout/html/tests/css/bugs/bug02.css @@ -0,0 +1,20 @@ +/* + * 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. + */ +/* This rule evaluates to just a margin-left value */ +DD { margin-top: 0pixels; margin-left: .25in; } +/* This rule evaluates to just a margin-top value */ +DD { margin-top: 0; margin-left: .25parsecs; } diff --git a/mozilla/layout/html/tests/css/clear.css b/mozilla/layout/html/tests/css/clear.css new file mode 100644 index 00000000000..7e6fec6a9b7 --- /dev/null +++ b/mozilla/layout/html/tests/css/clear.css @@ -0,0 +1,20 @@ +/* + * 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. + */ +GOOD { clear: none; } +GOOD { clear: left; } +GOOD { clear: right; } +GOOD { clear: both; } diff --git a/mozilla/layout/html/tests/css/clip.css b/mozilla/layout/html/tests/css/clip.css new file mode 100644 index 00000000000..eca71f1dd45 --- /dev/null +++ b/mozilla/layout/html/tests/css/clip.css @@ -0,0 +1,38 @@ +/* + * 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. + */ +GOOD { clip: auto; } +GOOD { clip: rect( auto auto auto auto ) } +GOOD { clip: rect(auto auto auto auto) } +GOOD { clip: rect( 12pt auto auto auto ) } + +GOOD { clip: rect( auto 12pt auto auto ) } +GOOD { clip: rect( auto auto 12pt auto ) } +GOOD { clip: rect( auto auto auto 12pt ) } +GOOD { clip: rect( 12pt 13em auto auto ) } + +GOOD { clip: rect( 12pt 13em 14pc auto ) } +GOOD { clip: rect( 12pt 13em 14pc 15in ) } +GOOD { clip: rect ( 12pt 13em 14pc 15in ) } + +BAD { clip: rect( 1pt ) } +BAD { clip: rect( 1pt 2pt ) } +BAD { clip: rect( 1pt 2pt 3pt ) } +BAD { clip: rect( 1 2 3 4 ) } +BAD { clip: rect( auto ) } +BAD { clip: rect( auto auto) } +BAD { clip: rect( auto auto auto) } +BAD { clip: rect( auto auto auto) } diff --git a/mozilla/layout/html/tests/css/color.css b/mozilla/layout/html/tests/css/color.css new file mode 100644 index 00000000000..c6b4c7e8f2a --- /dev/null +++ b/mozilla/layout/html/tests/css/color.css @@ -0,0 +1,22 @@ +/* + * 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. + */ +GOOD { color: red; } +GOOD { color: rgb(0, 0, 0); } +GOOD { color: rGb(110%, 23, 9123784328342834); } +GOOD { color: #f00; } +GOOD { color: #ff00ff; } +GOOD { color: #fff000fff; } /* Note: an extension */ diff --git a/mozilla/layout/html/tests/css/display.css b/mozilla/layout/html/tests/css/display.css new file mode 100644 index 00000000000..01cda2f1226 --- /dev/null +++ b/mozilla/layout/html/tests/css/display.css @@ -0,0 +1,20 @@ +/* + * 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. + */ +GOOD { display: none; } +GOOD { display: block; } +GOOD { display: inline; } +GOOD { display: list-item; } diff --git a/mozilla/layout/html/tests/css/float.css b/mozilla/layout/html/tests/css/float.css new file mode 100644 index 00000000000..b07e27e4a7a --- /dev/null +++ b/mozilla/layout/html/tests/css/float.css @@ -0,0 +1,20 @@ +/* + * 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. + */ +GOOD { float: none; } +GOOD { float: left; } +GOOD { float: right; } +BAD { float: medium; } diff --git a/mozilla/layout/html/tests/css/font-family.css b/mozilla/layout/html/tests/css/font-family.css new file mode 100644 index 00000000000..2dd8514b494 --- /dev/null +++ b/mozilla/layout/html/tests/css/font-family.css @@ -0,0 +1,17 @@ +/* + * 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. + */ +GOOD { font-family: gill, helvetica, times new roman, sans-serif; } diff --git a/mozilla/layout/html/tests/css/font-size.css b/mozilla/layout/html/tests/css/font-size.css new file mode 100644 index 00000000000..cb0c10a81e5 --- /dev/null +++ b/mozilla/layout/html/tests/css/font-size.css @@ -0,0 +1,29 @@ +/* + * 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. + */ +GOOD { font-size: Xx-smAll; } +GOOD { font-size: x-Small; } +GOOD { font-size: Small; } +GOOD { font-size: Medium; } +GOOD { font-size: LaRgE; } +GOOD { font-size: x-LaRgE; } +GOOD { font-size: Xx-LaRgE; } +GOOD { font-size: LaRgEr; } +GOOD { font-size: smalLer; } +GOOD { font-size: 3.0in; } +GOOD { font-size: 120%; } +BAD { font-size: green; } +BAD { font-size: 120% 240%; } diff --git a/mozilla/layout/html/tests/css/font-style.css b/mozilla/layout/html/tests/css/font-style.css new file mode 100644 index 00000000000..4f8b200abaa --- /dev/null +++ b/mozilla/layout/html/tests/css/font-style.css @@ -0,0 +1,23 @@ +/* + * 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. + */ +GOOD { font-style: normal; } +GOOD { font-style: italic; } +GOOD { font-style: oblique; } +BAD { font-style: green; } +BAD { font-style: 120% 240%; } +BAD { font-style: medium; } +BAD { font-style: "kanji"; } diff --git a/mozilla/layout/html/tests/css/font-variant.css b/mozilla/layout/html/tests/css/font-variant.css new file mode 100644 index 00000000000..302b44790a9 --- /dev/null +++ b/mozilla/layout/html/tests/css/font-variant.css @@ -0,0 +1,22 @@ +/* + * 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. + */ +GOOD { font-variant: normal; } +GOOD { font-variant: small-caps; } +BAD { font-variant: green; } +BAD { font-variant: 120% 240%; } +BAD { font-variant: medium; } +BAD { font-variant: "kanji"; } diff --git a/mozilla/layout/html/tests/css/font-weight.css b/mozilla/layout/html/tests/css/font-weight.css new file mode 100644 index 00000000000..fd7c8328960 --- /dev/null +++ b/mozilla/layout/html/tests/css/font-weight.css @@ -0,0 +1,31 @@ +/* + * 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. + */ +GOOD { font-weight: normal; } +GOOD { font-weight: bold; } +GOOD { font-weight: bolder; } +GOOD { font-weight: lighter; } +GOOD { font-weight: 100; } +GOOD { font-weight: 200; } +GOOD { font-weight: 300; } +GOOD { font-weight: 400; } +GOOD { font-weight: 500; } +GOOD { font-weight: 600; } +GOOD { font-weight: 700; } +GOOD { font-weight: 800; } +GOOD { font-weight: 900; } +BAD { font-weight: heavy; } +BAD { font-weight: 12.3em; } diff --git a/mozilla/layout/html/tests/css/font.css b/mozilla/layout/html/tests/css/font.css new file mode 100644 index 00000000000..98096fb7617 --- /dev/null +++ b/mozilla/layout/html/tests/css/font.css @@ -0,0 +1,29 @@ +/* + * 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. + */ +GOOD { font: italic small-caps bold 12pt helvetica } +GOOD { font: italic bold small-caps 12pt helvetica } +GOOD { font: small-caps bold italic 12pt helvetica } +GOOD { font: small-caps italic bold 12pt helvetica } +GOOD { font: bold italic small-caps 12pt helvetica } +GOOD { font: bold small-caps italic 12pt helvetica } +GOOD { font: bold 12pt helvetica } +GOOD { font: 12pt helvetica } +GOOD { font: 12pt/14pt sans-serif; } +GOOD { font: 80% sans-serif; } +GOOD { font: x-large/110% "new century schoolbook", serif; } +GOOD { font: bold italic large Palatino, serif; } +GOOD { font: normal small-caps 120%/120% fantasy; } diff --git a/mozilla/layout/html/tests/css/height.css b/mozilla/layout/html/tests/css/height.css new file mode 100644 index 00000000000..85c7a68af95 --- /dev/null +++ b/mozilla/layout/html/tests/css/height.css @@ -0,0 +1,18 @@ +/* + * 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. + */ +GOOD { height: 3.0in; } +GOOD { height: auto; } diff --git a/mozilla/layout/html/tests/css/left.css b/mozilla/layout/html/tests/css/left.css new file mode 100644 index 00000000000..227ff293e37 --- /dev/null +++ b/mozilla/layout/html/tests/css/left.css @@ -0,0 +1,19 @@ +/* + * 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. + */ +GOOD { left: auto; } +GOOD { left: 17.0in; } +GOOD { left: 120%; } diff --git a/mozilla/layout/html/tests/css/letter-spacing.css b/mozilla/layout/html/tests/css/letter-spacing.css new file mode 100644 index 00000000000..b3056ab3020 --- /dev/null +++ b/mozilla/layout/html/tests/css/letter-spacing.css @@ -0,0 +1,18 @@ +/* + * 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. + */ +GOOD { letter-spacing: normal; } +GOOD { letter-spacing: 3.0in; } diff --git a/mozilla/layout/html/tests/css/line-height.css b/mozilla/layout/html/tests/css/line-height.css new file mode 100644 index 00000000000..39c1c97ab8d --- /dev/null +++ b/mozilla/layout/html/tests/css/line-height.css @@ -0,0 +1,20 @@ +/* + * 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. + */ +GOOD { line-height: normal; } +GOOD { line-height: 17; } +GOOD { line-height: 17.0in; } +GOOD { line-height: 17%; } diff --git a/mozilla/layout/html/tests/css/list-style-image.css b/mozilla/layout/html/tests/css/list-style-image.css new file mode 100644 index 00000000000..cbc79581319 --- /dev/null +++ b/mozilla/layout/html/tests/css/list-style-image.css @@ -0,0 +1,18 @@ +/* + * 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. + */ +GOOD { list-style-image: none; } +GOOD { list-style-image: url(fowl.gif); } diff --git a/mozilla/layout/html/tests/css/list-style-position.css b/mozilla/layout/html/tests/css/list-style-position.css new file mode 100644 index 00000000000..f114339b063 --- /dev/null +++ b/mozilla/layout/html/tests/css/list-style-position.css @@ -0,0 +1,18 @@ +/* + * 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. + */ +GOOD { list-style-position: inside; } +GOOD { list-style-position: outside; } diff --git a/mozilla/layout/html/tests/css/list-style-type.css b/mozilla/layout/html/tests/css/list-style-type.css new file mode 100644 index 00000000000..7704ad65f49 --- /dev/null +++ b/mozilla/layout/html/tests/css/list-style-type.css @@ -0,0 +1,25 @@ +/* + * 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. + */ +GOOD { list-style-type: none; } +GOOD { list-style-type: disc; } +GOOD { list-style-type: circle; } +GOOD { list-style-type: square; } +GOOD { list-style-type: decimal; } +GOOD { list-style-type: lower-roman; } +GOOD { list-style-type: upper-roman; } +GOOD { list-style-type: lower-alpha; } +GOOD { list-style-type: upper-alpha; } diff --git a/mozilla/layout/html/tests/css/list-style.css b/mozilla/layout/html/tests/css/list-style.css new file mode 100644 index 00000000000..2c1e3df4823 --- /dev/null +++ b/mozilla/layout/html/tests/css/list-style.css @@ -0,0 +1,26 @@ +/* + * 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. + */ +GOOD { list-style: disc; } +GOOD { list-style: disc inside; } +GOOD { list-style: inside disc; } +GOOD { list-style: inside disc url(fowl.gif); } +GOOD { list-style: disc url(fowl.gif) inside; } +GOOD { list-style: url(fowl.gif) inside disc; } + +BAD { list-style: none inside disc; } +BAD { list-style: inside disc none; } +BAD { list-style: disc none inside; } diff --git a/mozilla/layout/html/tests/css/margin-bottom.css b/mozilla/layout/html/tests/css/margin-bottom.css new file mode 100644 index 00000000000..ac32d56d61f --- /dev/null +++ b/mozilla/layout/html/tests/css/margin-bottom.css @@ -0,0 +1,19 @@ +/* + * 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. + */ +GOOD { margin-bottom: 17.0in; } +GOOD { margin-bottom: 120%; } +GOOD { margin-bottom: auto; } diff --git a/mozilla/layout/html/tests/css/margin-left.css b/mozilla/layout/html/tests/css/margin-left.css new file mode 100644 index 00000000000..4696c491ea1 --- /dev/null +++ b/mozilla/layout/html/tests/css/margin-left.css @@ -0,0 +1,19 @@ +/* + * 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. + */ +GOOD { margin-left: 17.0in; } +GOOD { margin-left: 120%; } +GOOD { margin-left: auto; } diff --git a/mozilla/layout/html/tests/css/margin-right.css b/mozilla/layout/html/tests/css/margin-right.css new file mode 100644 index 00000000000..2672b4a2ae4 --- /dev/null +++ b/mozilla/layout/html/tests/css/margin-right.css @@ -0,0 +1,19 @@ +/* + * 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. + */ +GOOD { margin-right: 17.0in; } +GOOD { margin-right: 120%; } +GOOD { margin-right: auto; } diff --git a/mozilla/layout/html/tests/css/margin-top.css b/mozilla/layout/html/tests/css/margin-top.css new file mode 100644 index 00000000000..9ea23bbae00 --- /dev/null +++ b/mozilla/layout/html/tests/css/margin-top.css @@ -0,0 +1,19 @@ +/* + * 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. + */ +GOOD { margin-top: 17.0in; } +GOOD { margin-top: 120%; } +GOOD { margin-top: auto; } diff --git a/mozilla/layout/html/tests/css/margin.css b/mozilla/layout/html/tests/css/margin.css new file mode 100644 index 00000000000..febf50f6798 --- /dev/null +++ b/mozilla/layout/html/tests/css/margin.css @@ -0,0 +1,38 @@ +/* + * 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. + */ +GOOD { margin: 17.0in; } +GOOD { margin: 120%; } +GOOD { margin: auto; } +GOOD { margin: 17.0in auto; } +GOOD { margin: 17.0in 120%; } +GOOD { margin: 17.0in 17.0in; } +GOOD { margin: 120% 17.0in; } +GOOD { margin: 120% auto; } +GOOD { margin: 120% 120%; } +GOOD { margin: auto 120%; } +GOOD { margin: auto 17.0in; } +GOOD { margin: auto auto; } +GOOD { margin: 17.0in 17.0in 17.0in; } +GOOD { margin: 17.0in 17.0in 120%; } +GOOD { margin: 17.0in 17.0in auto; } +GOOD { margin: 17.0in 120% 17.0in; } +GOOD { margin: 17.0in auto 17.0in; } +GOOD { margin: 17.0in 17.0in 17.0in 17.0in; } +GOOD { margin: 17.0in 120% 17.0in 17.0in; } +GOOD { margin: 120% 120% 17.0in 17.0in; } +GOOD { margin: 120% 120% 120% 17.0in; } +GOOD { margin: 120% 120% 120% 120%; } diff --git a/mozilla/layout/html/tests/css/overflow.css b/mozilla/layout/html/tests/css/overflow.css new file mode 100644 index 00000000000..46e7fd682a1 --- /dev/null +++ b/mozilla/layout/html/tests/css/overflow.css @@ -0,0 +1,20 @@ +/* + * 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. + */ +GOOD { overflow: visible; } +GOOD { overflow: hidden; } +GOOD { overflow: scroll; } +GOOD { overflow: auto; } diff --git a/mozilla/layout/html/tests/css/padding-bottom.css b/mozilla/layout/html/tests/css/padding-bottom.css new file mode 100644 index 00000000000..b1efb0eb840 --- /dev/null +++ b/mozilla/layout/html/tests/css/padding-bottom.css @@ -0,0 +1,18 @@ +/* + * 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. + */ +GOOD { padding-bottom: 17.0in; } +GOOD { padding-bottom: 120%; } diff --git a/mozilla/layout/html/tests/css/padding-left.css b/mozilla/layout/html/tests/css/padding-left.css new file mode 100644 index 00000000000..3951f619078 --- /dev/null +++ b/mozilla/layout/html/tests/css/padding-left.css @@ -0,0 +1,18 @@ +/* + * 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. + */ +GOOD { padding-left: 17.0in; } +GOOD { padding-left: 120%; } diff --git a/mozilla/layout/html/tests/css/padding-right.css b/mozilla/layout/html/tests/css/padding-right.css new file mode 100644 index 00000000000..b20297318d5 --- /dev/null +++ b/mozilla/layout/html/tests/css/padding-right.css @@ -0,0 +1,18 @@ +/* + * 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. + */ +GOOD { padding-right: 17.0in; } +GOOD { padding-right: 120%; } diff --git a/mozilla/layout/html/tests/css/padding-top.css b/mozilla/layout/html/tests/css/padding-top.css new file mode 100644 index 00000000000..7ff1a36b66d --- /dev/null +++ b/mozilla/layout/html/tests/css/padding-top.css @@ -0,0 +1,18 @@ +/* + * 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. + */ +GOOD { padding-top: 17.0in; } +GOOD { padding-top: 120%; } diff --git a/mozilla/layout/html/tests/css/padding.css b/mozilla/layout/html/tests/css/padding.css new file mode 100644 index 00000000000..9541aeae23b --- /dev/null +++ b/mozilla/layout/html/tests/css/padding.css @@ -0,0 +1,30 @@ +/* + * 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. + */ +GOOD { padding: 17.0in; } +GOOD { padding: 120%; } +GOOD { padding: 17.0in 120%; } +GOOD { padding: 17.0in 17.0in; } +GOOD { padding: 120% 17.0in; } +GOOD { padding: 120% 120%; } +GOOD { padding: 17.0in 17.0in 17.0in; } +GOOD { padding: 17.0in 17.0in 120%; } +GOOD { padding: 17.0in 120% 17.0in; } +GOOD { padding: 17.0in 17.0in 17.0in 17.0in; } +GOOD { padding: 17.0in 120% 17.0in 17.0in; } +GOOD { padding: 120% 120% 17.0in 17.0in; } +GOOD { padding: 120% 120% 120% 17.0in; } +GOOD { padding: 120% 120% 120% 120%; } diff --git a/mozilla/layout/html/tests/css/position.css b/mozilla/layout/html/tests/css/position.css new file mode 100644 index 00000000000..e4f176c6d67 --- /dev/null +++ b/mozilla/layout/html/tests/css/position.css @@ -0,0 +1,21 @@ +/* + * 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. + */ +GOOD { position: static; } +GOOD { position: relative; } +GOOD { position: absolute; } +BAD { position: 12; } +BAD { position: medium; } diff --git a/mozilla/layout/html/tests/css/text-align.css b/mozilla/layout/html/tests/css/text-align.css new file mode 100644 index 00000000000..0c78292c178 --- /dev/null +++ b/mozilla/layout/html/tests/css/text-align.css @@ -0,0 +1,20 @@ +/* + * 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. + */ +GOOD { text-align: left; } +GOOD { text-align: right; } +GOOD { text-align: center; } +GOOD { text-align: justify; } diff --git a/mozilla/layout/html/tests/css/text-decoration.css b/mozilla/layout/html/tests/css/text-decoration.css new file mode 100644 index 00000000000..c4c835534d8 --- /dev/null +++ b/mozilla/layout/html/tests/css/text-decoration.css @@ -0,0 +1,26 @@ +/* + * 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. + */ +GOOD { text-decoration: none; } +GOOD { text-decoration: underline; } +GOOD { text-decoration: overline; } +GOOD { text-decoration: line-through; } +GOOD { text-decoration: blink; } +GOOD { text-decoration: overline underline; } +GOOD { text-decoration: line-through overline underline; } +GOOD { text-decoration: blink line-through overline underline; } +BAD { text-decoration: blink fish line-through overline underline; } +BAD { text-decoration: none blink; } diff --git a/mozilla/layout/html/tests/css/text-indent.css b/mozilla/layout/html/tests/css/text-indent.css new file mode 100644 index 00000000000..17bc36e0647 --- /dev/null +++ b/mozilla/layout/html/tests/css/text-indent.css @@ -0,0 +1,18 @@ +/* + * 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. + */ +GOOD { text-indent: 3.0in; } +GOOD { text-indent: 120%; } diff --git a/mozilla/layout/html/tests/css/text-transform.css b/mozilla/layout/html/tests/css/text-transform.css new file mode 100644 index 00000000000..7fae9a04625 --- /dev/null +++ b/mozilla/layout/html/tests/css/text-transform.css @@ -0,0 +1,21 @@ +/* + * 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. + */ +GOOD { text-transform: none; } +GOOD { text-transform: capitalize; } +GOOD { text-transform: lowercase; } +GOOD { text-transform: uppercase; } +BAD { text-transform: capitalize lowercase } diff --git a/mozilla/layout/html/tests/css/top.css b/mozilla/layout/html/tests/css/top.css new file mode 100644 index 00000000000..5f45d8db192 --- /dev/null +++ b/mozilla/layout/html/tests/css/top.css @@ -0,0 +1,19 @@ +/* + * 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. + */ +GOOD { top: auto; } +GOOD { top: 17.0in; } +GOOD { top: 120%; } diff --git a/mozilla/layout/html/tests/css/vertical-align.css b/mozilla/layout/html/tests/css/vertical-align.css new file mode 100644 index 00000000000..591cf4e42d6 --- /dev/null +++ b/mozilla/layout/html/tests/css/vertical-align.css @@ -0,0 +1,25 @@ +/* + * 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. + */ +GOOD { vertical-align: baseline; } +GOOD { vertical-align: sub; } +GOOD { vertical-align: super; } +GOOD { vertical-align: top; } +GOOD { vertical-align: text-top; } +GOOD { vertical-align: middle; } +GOOD { vertical-align: text-bottom; } +GOOD { vertical-align: bottom; } +GOOD { vertical-align: 120%; } diff --git a/mozilla/layout/html/tests/css/visibility.css b/mozilla/layout/html/tests/css/visibility.css new file mode 100644 index 00000000000..16c409e3afb --- /dev/null +++ b/mozilla/layout/html/tests/css/visibility.css @@ -0,0 +1,19 @@ +/* + * 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. + */ +GOOD { visibility: inherit; } +GOOD { visibility: visible; } +GOOD { visibility: hidden; } diff --git a/mozilla/layout/html/tests/css/white-space.css b/mozilla/layout/html/tests/css/white-space.css new file mode 100644 index 00000000000..e1b61a8a619 --- /dev/null +++ b/mozilla/layout/html/tests/css/white-space.css @@ -0,0 +1,19 @@ +/* + * 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. + */ +GOOD { white-space: normal; } +GOOD { white-space: pre; } +GOOD { white-space: nowrap; } diff --git a/mozilla/layout/html/tests/css/width.css b/mozilla/layout/html/tests/css/width.css new file mode 100644 index 00000000000..f1122d4fc23 --- /dev/null +++ b/mozilla/layout/html/tests/css/width.css @@ -0,0 +1,19 @@ +/* + * 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. + */ +GOOD { width: 3.0in; } +GOOD { width: 120%; } +GOOD { width: auto; } diff --git a/mozilla/layout/html/tests/css/word-spacing.css b/mozilla/layout/html/tests/css/word-spacing.css new file mode 100644 index 00000000000..057882d3c72 --- /dev/null +++ b/mozilla/layout/html/tests/css/word-spacing.css @@ -0,0 +1,25 @@ +/* + * 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. + */ +GOOD { word-spacing: normal; } +GOOD { wOrd-spacing: 12.0em; } +GOOD { WoRd-Spacing: 12.0eX; } +GOOD { worD-Spacing: 12PX; } +GOOD { word-Spacing: 12.0In; } +GOOD { word-sPacing: 12.0cm; } +GOOD { word-spAcing: 12.0mm; } +GOOD { word-spaCing: 12.0pt; } +GOOD { word-spacIng: 12.0pc; } diff --git a/mozilla/layout/html/tests/css/z-index.css b/mozilla/layout/html/tests/css/z-index.css new file mode 100644 index 00000000000..e33879cc405 --- /dev/null +++ b/mozilla/layout/html/tests/css/z-index.css @@ -0,0 +1,20 @@ +/* + * 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. + */ +GOOD { z-index: auto } +GOOD { z-index: 123456789 } +BAD { z-index: 12.3pt } +BAD { z-index: 12.3 } diff --git a/mozilla/layout/html/tests/makefile.win b/mozilla/layout/html/tests/makefile.win new file mode 100644 index 00000000000..3efe665cb83 --- /dev/null +++ b/mozilla/layout/html/tests/makefile.win @@ -0,0 +1,95 @@ +#!nmake +# +# 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. + +DEPTH=..\..\.. + +MAKE_OBJ_TYPE = EXE +PROG1 = .\$(OBJDIR)\TestCSSScanner.exe +PROG2 = .\$(OBJDIR)\TestHTMLTagLookup.exe +PROG3 = .\$(OBJDIR)\TestCSSPropertyLookup.exe +PROG4 = .\$(OBJDIR)\TestCSSParser.exe +PROG5 = .\$(OBJDIR)\TestAttributes.exe +PROG6 = .\$(OBJDIR)\TestInlineFrame.exe +PROGRAMS = $(PROG1) $(PROG2) $(PROG3) $(PROG4) $(PROG5) $(PROG6) + +DEFINES = -D_IMPL_NS_HTML + +LCFLAGS = \ + $(LCFLAGS) \ + $(DEFINES) \ + $(NULL) + +LINCS=-I$(PUBLIC)\xpcom -I$(PUBLIC)\raptor -I..\base\src -I..\style\src -I$(PUBLIC)\dom + +LLIBS= \ + $(DIST)\lib\raptorhtmlbase_s.lib \ + $(DIST)\lib\raptorhtmlstyle_s.lib \ + $(DIST)\lib\raptorlayout_s.lib \ + $(DIST)\lib\raptorgfx.lib \ + $(DIST)\lib\raptorbase.lib \ + $(DIST)\lib\img3240.lib \ + $(DIST)\lib\util.lib \ + $(DIST)\lib\xpcom32.lib \ + $(DIST)\lib\jsdom.lib \ + $(LIBNSPR) \ + $(DIST)\lib\libplc21.lib + +include <$(DEPTH)\config\rules.mak> + +install:: $(PROGRAMS) + $(MAKE_INSTALL) $(PROG1) $(DIST)\bin + $(MAKE_INSTALL) $(PROG2) $(DIST)\bin + $(MAKE_INSTALL) $(PROG3) $(DIST)\bin + $(MAKE_INSTALL) $(PROG4) $(DIST)\bin + $(MAKE_INSTALL) $(PROG5) $(DIST)\bin + $(MAKE_INSTALL) $(PROG6) $(DIST)\bin + +clobber:: + rm -f $(DIST)\bin\TestCSSScanner.exe + rm -f $(DIST)\bin\TestHTMLTagLookup.exe + rm -f $(DIST)\bin\TestCSSPropertyLookup.exe + rm -f $(DIST)\bin\TestCSSParser.exe + rm -f $(DIST)\bin\TestAttributes.exe + rm -f $(DIST)\bin\TestInlineFrame.exe + +# Move this into config/obj.inc when it's allowed +.cpp{.\$(OBJDIR)\}.exe: + -$(CC) @<<$(CFGFILE) + $(CFLAGS) + $(LCFLAGS) + $(LINCS) + $(LINCS_1) + $(INCS) + $(LLIBS) + $(OS_LIBS) + -Fd$(PBDFILE) + -Fe.\$(OBJDIR)\ + -Fo.\$(OBJDIR)\ + $(CURDIR)$(*B).cpp +< +#include "nscore.h" +#include "nsIAtom.h" +#include "nsStringBuf.h" +#include "nsDocument.h" +#include "nsIPresShell.h" +#include "nsIPresContext.h" +#include "nsIContentDelegate.h" +#include "nsIViewManager.h" +#include "nsIView.h" +#include "nsViewsCID.h" +#include "nsIFrame.h" +#include "nsIStyleSet.h" +#include "nsHTMLParts.h" +#include "nsIHTMLContent.h" +#include "..\..\..\src\nsTablePart.h" + + +static FILE * out; + + +class BasicTest : public nsDocument // yep, I'm a document +{ +public: + BasicTest(); + virtual ~BasicTest() {}; + + nsresult AppendSimpleSpan(nsIContent* aContainer, const char* aTag, const char* aText); + + void CreateCorrectContent(PRInt32 aRows, PRInt32 aCols); + void CreateCorrectFullContent(PRInt32 aRows, PRInt32 aCols); + void CreateOutOfOrderContent(PRInt32 aRows, PRInt32 aCols); + void CreateIllegalContent(PRInt32 aRows, PRInt32 aCols); + + void VerifyContent(PRInt32 aRows, PRInt32 aCols); + + void TestGeometry(); +}; + +class GeometryTest +{ +public: + GeometryTest(BasicTest *aDoc); + + virtual ~GeometryTest() {}; + + void CreateGeometry(BasicTest *aDoc, nsIPresContext *aPC); + + void VerifyGeometry(BasicTest *aDoc, nsIPresContext *aPC); + + nsIPresShell * mShell; + nsIViewManager * mViewManager; + nsIFrame * mRootFrame; +}; + +/* ---------- BasicTest Definitions ---------- */ + +BasicTest::BasicTest() + : nsDocument() +{ + Init(); + + PRInt32 rows = 3; + PRInt32 cols = 4; + + // Build a basic table content model the "right" way + CreateCorrectContent(rows, cols); + VerifyContent(rows, cols); + nsIContent *root; + root = GetRootContent(); + if (nsnull!=root && 1==root->ChildCount()) + root->RemoveChildAt(0); + else + { + fprintf(out, "corrupt root after CreateCorrectContent\n"); + NS_ASSERTION(PR_FALSE, ""); + } + + // Build a content model the "right" way with every kind of table object + CreateCorrectFullContent(rows, cols); + VerifyContent(rows, cols); + root = GetRootContent(); + if (nsnull!=root && 1==root->ChildCount()) + root->RemoveChildAt(0); + else + { + fprintf(out, "corrupt root after CreateCorrectFullContent\n"); + NS_ASSERTION(PR_FALSE, ""); + } + + // Build a content model with things out of order + CreateOutOfOrderContent(rows, cols); + VerifyContent(rows, cols); + root = GetRootContent(); + if (nsnull!=root && 1==root->ChildCount()) + root->RemoveChildAt(0); + else + { + fprintf(out, "corrupt root after CreateOutOfOrderContent\n"); + NS_ASSERTION(PR_FALSE, ""); + } + + // Build a content model with illegal things + /* not ready for prime time... + CreateIllegalContent(rows, cols); + VerifyContent(rows, cols); + root = GetRootContent(); + if (nsnull!=root && 1==root->ChildCount()) + root->RemoveChildAt(0); + else + { + fprintf(out, "corrupt root after CreateIllegalContent\n"); + NS_ASSERTION(PR_FALSE); + } + */ + + TestGeometry(); +} + +nsresult BasicTest::AppendSimpleSpan(nsIContent* aContainer, const char* aTag, const char* aText) +{ + nsIHTMLContent* span; + nsIHTMLContent* text; + nsIAtom* atom = NS_NewAtom(aTag); + nsresult rv = NS_NewHTMLContainer(&span, atom); + if (NS_OK == rv) { + nsStringBuf tmp; + tmp.Append(aText); + rv = NS_NewHTMLText(&text, tmp.GetUnicode(), tmp.Length()); + if (NS_OK == rv) { + span->AppendChild(text); + NS_RELEASE(text); + } + aContainer->AppendChild(span); + NS_RELEASE(span); + } + NS_RELEASE(atom); + return rv; +} + +void BasicTest::CreateCorrectContent(int aRows, int aCols) +{ + fprintf(out, "CreateCorrectContent %d %d\n", aRows, aCols); + nsIHTMLContent* root; + nsresult rv = NS_NewRootPart(&root, this); // does a SetRootPart on the returned root object + if (NS_OK != rv) { + fprintf(out, "NS_NewRootPart failed\n"); + NS_ASSERTION(PR_FALSE, "NS_NewRootPart failed"); + } + + nsIHTMLContent* body; + nsIAtom* atom = NS_NewAtom("BODY"); + rv = NS_NewBodyPart(&body, atom); + if (NS_OK != rv) { + fprintf(out, "NS_NewBodyPart failed\n"); + NS_ASSERTION(PR_FALSE, "NS_NewBodyPart failed"); + } + NS_RELEASE(atom); + + nsIHTMLContent* table; + nsIHTMLContent* row; + nsIHTMLContent* cell; + + nsIAtom* tatom = NS_NewAtom("TABLE"); + rv = NS_NewTablePart(&table, tatom); + NS_RELEASE(tatom); + if (NS_OK == rv) { + PRInt32 rowIndex; + for (rowIndex = 0; (NS_OK == rv) && (rowIndex < aRows); rowIndex++) { + nsIAtom* tratom = NS_NewAtom("TR"); + rv = NS_NewTableRowPart(&row, tratom); + NS_RELEASE(tratom); + if (NS_OK == rv) { + PRInt32 colIndex; + for (colIndex = 0; (NS_OK == rv) && (colIndex < aCols); colIndex++) { + nsIAtom* tdatom = NS_NewAtom("TD"); + rv = NS_NewTableCellPart(&cell, tdatom); + NS_RELEASE(tdatom); + if (NS_OK == rv) { + rv = AppendSimpleSpan (cell, "P", "test"); + } + row->AppendChild(cell); + NS_RELEASE(cell); + } + table->AppendChild(row); + NS_RELEASE(row); + } + } + ((nsTablePart *)table)->GetMaxColumns(); // has important side effect of creating pseudo-columns + body->AppendChild(table); + NS_RELEASE(table); + } + root->AppendChild(body); + NS_RELEASE(body); +} + +void BasicTest::CreateCorrectFullContent(int aRows, int aCols) +{ + fprintf(out, "CreateCorrectFullContent %d %d, 1 caption\n", aRows, aCols); + nsIHTMLContent* root; + nsresult rv = NS_NewRootPart(&root, this); // does a SetRootPart on the returned root object + if (NS_OK != rv) { + fprintf(out, "NS_NewRootPart failed\n"); + NS_ASSERTION(PR_FALSE, "NS_NewRootPart failed\n"); + } + + nsIHTMLContent* body; + nsIAtom* atom = NS_NewAtom("BODY"); + rv = NS_NewBodyPart(&body, atom); + if (NS_OK != rv) { + fprintf(out, "NS_NewBodyPart failed\n"); + NS_ASSERTION(PR_FALSE, "NS_NewBodyPart failed\n"); + } + NS_RELEASE(atom); + + nsIHTMLContent* table; + nsIHTMLContent* caption; + nsIHTMLContent* colGroup; + nsIHTMLContent* col; + nsIHTMLContent* row; + nsIHTMLContent* cell; + + nsIAtom* tatom = NS_NewAtom("TABLE"); + rv = NS_NewTablePart(&table, tatom); + NS_RELEASE(tatom); + + // add caption + nsIAtom* captionAtom = NS_NewAtom("CAPTION"); + rv = NS_NewTableCaptionPart(&caption, captionAtom); + NS_RELEASE(captionAtom); + table->AppendChild(caption); + + // add column group + PRInt32 colIndex; + nsIAtom* colGroupAtom = NS_NewAtom("COLGROUP"); + rv = NS_NewTableColGroupPart(&colGroup, colGroupAtom); + NS_RELEASE(colGroupAtom); + table->AppendChild(colGroup); + + // add columns + nsIAtom* colAtom = NS_NewAtom("COL"); + for (colIndex = 0; (NS_OK == rv) && (colIndex < aCols); colIndex++) { + rv = NS_NewTableColPart(&col, colAtom); + colGroup->AppendChild(col); + } + NS_RELEASE(colAtom); + + // add rows and cells + if (NS_OK == rv) { + PRInt32 rowIndex; + for (rowIndex = 0; (NS_OK == rv) && (rowIndex < aRows); rowIndex++) { + nsIAtom* tratom = NS_NewAtom("TR"); + rv = NS_NewTableRowPart(&row, tratom); + NS_RELEASE(tratom); + if (NS_OK == rv) { + for (colIndex = 0; (NS_OK == rv) && (colIndex < aCols); colIndex++) { + nsIAtom* tdatom = NS_NewAtom("TD"); + rv = NS_NewTableCellPart(&cell, tdatom); + NS_RELEASE(tdatom); + if (NS_OK == rv) { + rv = AppendSimpleSpan (cell, "P", "test"); + } + row->AppendChild(cell); + NS_RELEASE(cell); + } + table->AppendChild(row); + NS_RELEASE(row); + } + } + body->AppendChild(table); + NS_RELEASE(table); + } + root->AppendChild(body); + NS_RELEASE(body); +} + + +void BasicTest::CreateOutOfOrderContent(int aRows, int aCols) +{ + fprintf(out, "CreateOutOfOrderContent %d %d, 2 captions\n", aRows, aCols); + nsIHTMLContent* root; + nsresult rv = NS_NewRootPart(&root, this); // does a SetRootPart on the returned root object + if (NS_OK != rv) { + fprintf(out, "NS_NewRootPart failed\n"); + NS_ASSERTION(PR_FALSE, "NS_NewRootPart failed\n"); + } + + nsIHTMLContent* body; + nsIAtom* atom = NS_NewAtom("BODY"); + rv = NS_NewBodyPart(&body, atom); + if (NS_OK != rv) { + fprintf(out, "NS_NewBodyPart failed\n"); + NS_ASSERTION(PR_FALSE, "NS_NewBodyPart failed\n"); + } + NS_RELEASE(atom); + + nsIHTMLContent* table; + nsIHTMLContent* caption; + nsIHTMLContent* colGroup; + nsIHTMLContent* col; + nsIHTMLContent* row; + nsIHTMLContent* cell; + + nsIAtom* tatom = NS_NewAtom("TABLE"); + rv = NS_NewTablePart(&table, tatom); + NS_RELEASE(tatom); + + // add rows and cells + if (NS_OK == rv) { + PRInt32 rowIndex; + for (rowIndex = 0; (NS_OK == rv) && (rowIndex < aRows); rowIndex++) { + nsIAtom* tratom = NS_NewAtom("TR"); + rv = NS_NewTableRowPart(&row, tratom); + NS_RELEASE(tratom); + if (NS_OK == rv) { + for (PRInt32 colIndex = 0; (NS_OK == rv) && (colIndex < aCols); colIndex++) { + nsIAtom* tdatom = NS_NewAtom("TD"); + rv = NS_NewTableCellPart(&cell, tdatom); + NS_RELEASE(tdatom); + if (NS_OK == rv) { + rv = AppendSimpleSpan (cell, "P", "test"); + } + row->AppendChild(cell); + NS_RELEASE(cell); + if (1==rowIndex && 0==colIndex) + { + // add column after cell[1,0], force implicit column group to be built + PRInt32 colIndex; + nsIAtom* colGroupAtom = NS_NewAtom("COLGROUP"); + rv = NS_NewTableColGroupPart(&colGroup, colGroupAtom); + NS_RELEASE(colGroupAtom); + table->AppendChild(colGroup); + } + } + table->AppendChild(row); + NS_RELEASE(row); + } + } + ((nsTablePart *)table)->GetMaxColumns(); // has important side effect of creating pseudo-columns + body->AppendChild(table); + } + root->AppendChild(body); + + // add caption in middle + nsIAtom* captionAtom = NS_NewAtom("CAPTION"); + rv = NS_NewTableCaptionPart(&caption, captionAtom); + NS_RELEASE(captionAtom); + table->AppendChild(caption); + + // add columns + nsIAtom* colAtom = NS_NewAtom("COL"); + for (PRInt32 colIndex = 0; (NS_OK == rv) && (colIndex < aCols); colIndex++) { + rv = NS_NewTableColPart(&col, colAtom); + colGroup->AppendChild(col); + } + NS_RELEASE(colAtom); + + // add caption at end + captionAtom = NS_NewAtom("CAPTION"); + rv = NS_NewTableCaptionPart(&caption, captionAtom); + NS_RELEASE(captionAtom); + table->AppendChild(caption); + + NS_RELEASE(table); + NS_RELEASE(body); +} + +void BasicTest::CreateIllegalContent(int aRows, int aCols) +{ +} + +void BasicTest::VerifyContent(PRInt32 aRows, PRInt32 aCols) +{ + nsIContent* root = GetRootContent(); + if (nsnull==root) + { + fprintf(out, "GetRootContent failed\n"); + NS_ASSERTION(PR_FALSE, "GetRootContent failed\n"); + } + fprintf(out, "VerifyContent for rows=%d, cols=%d\n", aRows, aCols); + root->List(out); +} + +void BasicTest::TestGeometry() +{ + GeometryTest test(this); +} + +/* ---------- GeometryTest Definitions ---------- */ + +GeometryTest::GeometryTest(BasicTest *aDoc) +{ + PRInt32 rows = 4; + PRInt32 cols = 3; + +#if 0 + NS_InitToolkit(PR_GetCurrentThread()); + + //NS_NewDeviceContext(&scribbleData.mContext); + static NS_DEFINE_IID(kIWidgetIID, NS_IWIDGET_IID); + NS_NewWindow(NULL, kIWidgetIID, nsnull); + +#endif + + nsIPresContext * pc = nsnull; + nsresult status = NS_NewGalleyContext(&pc); + if ((NS_FAILED(status)) || nsnull==pc) + { + fprintf(out, "bad galley pc"); + NS_ASSERTION(PR_FALSE, "bad galley pc"); + } + + // create a view manager + nsIViewManager * vm = nsnull; + + static NS_DEFINE_IID(kViewManagerCID, NS_VIEW_MANAGER_CID); + static NS_DEFINE_IID(kIViewManagerIID, NS_IVIEWMANAGER_IID); + + status = NSRepository::CreateInstance(kViewManagerCID, + nsnull, + kIViewManagerIID, + (void **)&vm); + + if ((NS_FAILED(status)) || nsnull==vm) + { + fprintf(out, "bad view manager"); + NS_ASSERTION(PR_FALSE, "bad view manager"); + } + vm->Init(pc); + + nsIView * rootView = nsnull; + + // Create a view + static NS_DEFINE_IID(kScrollingViewCID, NS_SCROLLING_VIEW_CID); + static NS_DEFINE_IID(kIViewIID, NS_IVIEW_IID); + + status = NSRepository::CreateInstance(kScrollingViewCID, + nsnull, + kIViewIID, + (void **)&rootView); + + if ((NS_FAILED(status)) || nsnull==rootView) + { + fprintf(out, "bad view"); + NS_ASSERTION(PR_FALSE, "bad view"); + } + nsRect bounds(0, 0, 10000, 10000); + rootView->Init(vm, bounds, nsnull); + + vm->SetRootView(rootView); + + nsIStyleSet * ss = nsnull; + status = NS_NewStyleSet(&ss); + if ((NS_FAILED(status)) || nsnull==ss) + { + fprintf(out, "bad style set"); + NS_ASSERTION(PR_FALSE, "bad style set"); + } + + mShell = nsnull; + status = NS_NewPresShell(&mShell); + if ((NS_FAILED(status)) || nsnull==mShell) + { + fprintf(out, "bad presentation shell."); + NS_ASSERTION(PR_FALSE, ""); + } + mShell->Init(aDoc, pc, vm, ss); + + aDoc->CreateCorrectContent(rows, cols); + CreateGeometry(aDoc, pc); + VerifyGeometry(aDoc, pc); + + aDoc->CreateCorrectFullContent(rows, cols); + CreateGeometry(aDoc, pc); + VerifyGeometry(aDoc, pc); + + /* paginated tests not ready yet... + NS_RELEASE(pc); + pc = nsnull; + status = NS_NewPrintPreviewContext(&pc); + if ((NS_FAILED(status)) || nsnull==pc) + { + fprintf(out, "bad paginated pc"); + NS_ASSERTION(PR_FALSE, ""); + } + aDoc->CreateCorrectContent(rows, cols); + CreateGeometry(aDoc, pc); + VerifyGeometry(aDoc, pc); + + aDoc->CreateCorrectFullContent(rows, cols); + CreateGeometry(aDoc, pc); + VerifyGeometry(aDoc, pc); + */ +} + +/** given a content model, create a geometry model */ +void GeometryTest::CreateGeometry(BasicTest * aDoc, nsIPresContext *aPC) +{ + nsIContent *root = aDoc->GetRootContent(); + nsIContentDelegate* cd = root->GetDelegate(aPC); + if (nsnull != cd) { + mRootFrame = cd->CreateFrame(aPC, root, -1, nsnull); + NS_RELEASE(cd); + if (nsnull==mRootFrame) + { + fprintf(out, "mRootFrame failed\n"); + NS_ASSERTION(PR_FALSE, "mRootFrame failed\n"); + } + + // Bind root frame to root view (and root window) + mViewManager = mShell->GetViewManager(); + if (nsnull==mViewManager) + { + fprintf(out, "bad view manager"); + NS_ASSERTION(PR_FALSE, ""); + } + nsIView* rootView = mViewManager->GetRootView(); + NS_ASSERTION(nsnull!=rootView, "bad root view"); + mRootFrame->SetView(rootView); + NS_RELEASE(rootView); + } + else { + fprintf(out, "ERROR: no root delegate\n"); + NS_ASSERTION(PR_FALSE, "no root delegate"); + } + NS_RELEASE(root); + + nsReflowMetrics desiredSize; + nsSize maxSize(400, 600); + nsSize maxElementSize; + + + mRootFrame->ResizeReflow(aPC, desiredSize, maxSize, &maxElementSize); + + +} + +void GeometryTest::VerifyGeometry(BasicTest *aDoc, nsIPresContext *aPC) +{ + mRootFrame->List(out); +} + + +/* ---------- Global Functions ---------- */ + +void main (int argc, char **argv) +{ + out = fopen("TableContentTest.txt", "w+t"); + if (nsnull==out) + { + fprintf(out, "test failed to open output file\n"); + NS_ASSERTION(PR_FALSE, "test failed to open output file\n"); + } + fprintf(out, "Test starting...\n\n"); + BasicTest basicTest; + fprintf(out, "\nTest completed.\n"); +} + + + + + + diff --git a/mozilla/layout/html/tests/table/testcases/nestedTables.html b/mozilla/layout/html/tests/table/testcases/nestedTables.html new file mode 100644 index 00000000000..78f7cbe008b --- /dev/null +++ b/mozilla/layout/html/tests/table/testcases/nestedTables.html @@ -0,0 +1,337 @@ + + + + + + table + + +  + + + + + + + + + + + + + + + + + + + + + + + + +
    Cell oneCell2Cell 3
    Cell 4Cell 5Cell 6
    + + + + + + + + + + + + + + + + + + + + + + + + +
    123
    4 + + + + + + + + + + + + + + + + + + + + + + + + +
    1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    12345
    67 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    abcde
    fghij
    kl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    abcde
    fghij
    kl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    abcde
    fghij
    klmno
    pqrst
    uvwxy
    no
    pqrst
    uvwxy
    no
    pqrst
    uvwxy
    90
    abcde
    fghij
    klmno
    3
    456
    789
    6
    789
    89
    +  + + diff --git a/mozilla/layout/html/tests/table/testcases/slashlogo.html b/mozilla/layout/html/tests/table/testcases/slashlogo.html new file mode 100644 index 00000000000..ade83d2d41f --- /dev/null +++ b/mozilla/layout/html/tests/table/testcases/slashlogo.html @@ -0,0 +1,3471 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
    \ No newline at end of file diff --git a/mozilla/layout/html/tests/table/testcases/wa_table_thtd_rowspan.html b/mozilla/layout/html/tests/table/testcases/wa_table_thtd_rowspan.html new file mode 100644 index 00000000000..1b069be225b --- /dev/null +++ b/mozilla/layout/html/tests/table/testcases/wa_table_thtd_rowspan.html @@ -0,0 +1,472 @@ + + + + Web Browser Web View (HTML): Table + + + + +

    Acceptance Test Case
    Web Browser: Web View (HTML)

    +

    +Table: <TH> & <TD> ROWSPAN + +


    +This acceptance test case tests the optional <TH> & <TD> tag ROWSPAN attribute which, +when placed in a table header or data tag, specifies how many rows the table header or data cell will span. The +ROWSPAN attribute is set to an integer value equal the number of rows the table header or data cell spans. +

    +Test Instructions: +

      +
    1. Verify that the sample text displays as stated in each of the following test cases:
    2. +

      + + + + + + + + + + + + + +
      Test Case #1table with header cells spanning multiple rows
      Test Case #2table with data cells spanning multiple rows
      Test Case #3table with nested header & data cells spanning multiple rows
      +

      +

    3. Verify that the table is maintained when you minimize/maximize the screen.
    4. +
    5. Verify that the table is maintained when you re-size left & right the screen.
    6. +
    7. Verify that the table is maintained when you re-size top & bottom the screen.
    8. +
    9. Verify re-draw takes place correctly after maximizing the screen.
    10. +
    11. Verify reload works.
    12. +
    + +
    +

    + + +
    +Test Case #1: table with header cells spanning multiple rows +(using <TH ROWSPAN=integer value> tag) +
    +

    +
    + + +
    In the following sample table you should see that the ROWSPAN +attribute applies an integer value equal to the number of rows the HEADER cell is to span. This +tells the browser to make the table header cell occupy the same vertical space as the integer number of cells specified in rows +above or below it. The browser flows the contents of the spanning cell to occupy the entire spanned space. +
    + +



    +

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Table Header Cells spanning multiple rows
      Header 1
      span=2 rows
      col 1col 2col 3col 4col 5col 6col 7col 8col 9
      col 1col 2col 3col 4col 5col 6col 7col 8col 9
      Header 2
      span=5 rows
      col 1col 2col 3col 4col 5col 6col 7col 8col 9
      col 1col 2col 3col 4col 5col 6col 7col 8col 9
      col 1col 2col 3col 4col 5col 6col 7col 8col 9
      col 1col 2col 3col 4col 5col 6col 7col 8col 9
      col 1col 2col 3col 4col 5col 6col 7col 8col 9
      Header 3
      span=3 rows
      col 1col 2col 3col 4col 5col 6col 7col 8col 9
      col 1col 2col 3col 4col 5col 6col 7col 8col 9
      col 1col 2col 3col 4col 5col 6col 7col 8col 9
      +
    + +

    +


    +

    + + +
    +Test Case #2: table with data cells spanning multiple rows +(using <TD ROWSPAN=integer value> tag) +
    +

    +
    + + +
    In the following sample table you should see that the ROWSPAN +attribute applies an integer value equal to the number of rows the DATA cell is to span. This +tells the browser to make the table data cell occupy the same vertical space as the integer number of cells specified in rows +above or below it. The browser flows the contents of the spanning cell to occupy the entire spanned space. +
    + +



    +

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Table Data Cells spanning multiple rows
      HeadData 1
      span=2 rows
      col 1col 2col 3col 4col 5col 6col 7col 8col 9
      Headcol 1col 2col 3col 4col 5col 6col 7col 8col 9
      HeadData 2
      span=5 rows
      col 1col 2col 3col 4col 5col 6col 7col 8col 9
      Headcol 1col 2col 3col 4col 5col 6col 7col 8col 9
      Headcol 1col 2col 3col 4col 5col 6col 7col 8col 9
      Headcol 1col 2col 3col 4col 5col 6col 7col 8col 9
      Headcol 1col 2col 3col 4col 5col 6col 7col 8col 9
      HeadData 3
      span=3 rows
      col 1col 2col 3col 4col 5col 6col 7col 8col 9
      Headcol 1col 2col 3col 4col 5col 6col 7col 8col 9
      Headcol 1col 2col 3col 4col 5col 6col 7col 8col 9
      +
    + +

    +


    +

    + + +
    +Test Case #3: table with nested header & data cells spanning multiple rows +(using <TH ROWSPAN=integer value> <TD ROWSPAN=integer value> tag) +
    + +



    +

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Nested Table Header Cells & Data Cells spanning multiple rows
      Header 1
      span=7 rows +
      Data 1
      span=2 rows
      col 1col 2col 3col 4col 5col 6col 7col 8col 9
      col 1col 2col 3col 4col 5col 6col 7col 8col 9
      Data 2
      span=5 rows
      col 1col 2col 3col 4col 5col 6col 7col 8col 9
      col 1col 2col 3col 4col 5col 6col 7col 8col 9
      col 1col 2col 3col 4col 5col 6col 7col 8col 9
      col 1col 2col 3col 4col 5col 6col 7col 8col 9
      col 1col 2col 3col 4col 5col 6col 7col 8col 9
      Header 2
      span=3 rows +
      Data 3
      span=3 rows
      col 1col 2col 3col 4col 5col 6col 7col 8col 9
      col 1col 2col 3col 4col 5col 6col 7col 8col 9
      col 1col 2col 3col 4col 5col 6col 7col 8col 9
      +
    + +

    +


    + Created 9/19/96 by Ronald Greti
    +

    +

    +

    CONFIDENTIAL AND PROPRIETARY TEST SCRIPT OF NETSCAPE COMMUNICATIONS CORP.
    Copyright © 1996 Netscape Communications Corp. All Rights Reserved.
    Use of this Test Script is subject to the terms of the applicable license agreement from Netscape Communications Corp.
    + + + + diff --git a/mozilla/layout/html/tests/table/testcases/wa_table_tr_align.html b/mozilla/layout/html/tests/table/testcases/wa_table_tr_align.html new file mode 100644 index 00000000000..5fe7808de3b --- /dev/null +++ b/mozilla/layout/html/tests/table/testcases/wa_table_tr_align.html @@ -0,0 +1,106 @@ + + + + Web Browser Web View (HTML): Table + + + + +

    Acceptance Test Case
    Web Browser: Web View (HTML)

    +

    +Table: <TR> ALIGN + +


    +This acceptance test case tests the optional <TR> tag ALIGN attribute which controls the +horizontal alignment of all the cells in a row. This cause the contents of each cell in the row to be aligned +either LEFT|CENTER|RIGHT with respect to the current left and right margins of the display window. +The Header cells by default are aligned CENTER while the Data cells by default are aligned LEFT. +

    +Test Instructions: +

      +
    1. Verify that the sample text displays as stated in each of the following test cases:
    2. +

      + + + + + + + + + +
      Test Case #1Table displaying Header "CENTER "& Data "LEFT" default horizontal row alignment
      Test Case #2Tables displaying Header & Data "LEFT|CENTER|RIGHT" horizontal row alignment
      +

      +

    3. Verify that the table is maintained when you minimize/maximize the screen.
    4. +
    5. Verify that the table is maintained when you re-size left & right the screen.
    6. +
    7. Verify that the table is maintained when you re-size top & bottom the screen.
    8. +
    9. Verify re-draw takes place correctly after maximizing the screen.
    10. +
    11. Verify reload works.
    12. +
    + +
    +

    + + +
    +Test Case #1: Table displaying Header "CENTER "& Data "LEFT" default horizontal row alignment +(using <TR> tag) +
    +

    + + + + +
    Default Horizontal Row Alignment
    row head 1row head 2row head 3
    row data 1row data 2row data 3
    + +


    +

    + + +
    +Test Case #2: Tables displaying Header & Data "LEFT|CENTER|RIGHT" horizontal row alignment +(using <TR ALIGN=LEFT|CENTER|RIGHT> tag) +
    + +

    + + + + + + +
    Horizontal Row Alignment=LEFT
    row head 1row head 2row head 3
    row data 1row data 2row data 3
    + +Note: The attribute ALIGN=LEFT has no special effect on the row data since it simply reiterates the default horizontal row alignment! +

    +

    + +

    + + + + + +
    Horizontal Row Alignment=CENTER
    row head 1row head 2row head 3
    row data 1row data 2row data 3
    + +Note: The attribute ALIGN=CENTER has no special effect on the row head since it simply reiterates the default horizontal row alignment! +

    +

    + +

    + + + + +
    Horizontal Row Alignment=RIGHT
    row head 1row head 2row head 3
    row data 1row data 2row data 3
    + +

    +


    + Created 9/9/96 by Ronald Greti
    +

    +

    +

    CONFIDENTIAL AND PROPRIETARY TEST SCRIPT OF NETSCAPE COMMUNICATIONS CORP.
    Copyright © 1996 Netscape Communications Corp. All Rights Reserved.
    Use of this Test Script is subject to the terms of the applicable license agreement from Netscape Communications Corp.
    + + + + diff --git a/mozilla/layout/html/tests/table/testcases/wf_table_index.html b/mozilla/layout/html/tests/table/testcases/wf_table_index.html new file mode 100644 index 00000000000..9064fd8782b --- /dev/null +++ b/mozilla/layout/html/tests/table/testcases/wf_table_index.html @@ -0,0 +1,177 @@ + + + + + + + Web Browser Web View (HTML): DocType + + + + + + + +

    Functional Test
    Web Browser: Web View (HTML)

    + +

    + +Tables + + + +


    + +Objective: Tests the Simple HTML Table Model. + +

    + +Syntax: The Simple Table Model is the table model that most browsers currently support. + +The model is from the HTML 3.2 Draft specifications which describes tables in terms of table cells + +grouped into row-based cell layouts. + +

    + +Based on the simple table model, you can create a wide variety of tables with only five tags: + +

      + +
    1. the <TABLE> tag, which encapsulates a table and its elements in the HTML document's body content;
    2. + +
    3. the <TR> tag, which defines a table row;
    4. + +
    5. the <TH> tag, which define the table header;
    6. + +
    7. the <TD> tag, which define the table data cell;
    8. + +
    9. the <CAPTION> tag, which defines a table title (caption); + +
    + +Each tag has one or more required and optional attributes, some of which affect not only the tag itself, but related tags. + +

    + +Procedure: Click each link in the Special Case column to verify that the expected results match the resulting display. + +


    + + + + + +

    + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Special CaseExpected Results
    Table with background color
  • Verify what happens when you use the Edit|Preferences|Appearance|Color checkbox.
  • Table with Mixed Widths
  • Verify what happens when you have mixed absolute and relative table cell widths?.
  • Large Table
  • Verify that you can load a table with a large number of rows & columns.
  • Character Styles inside Tables
  • Verify that tables can contain character styles.[from Character Styles Functional Test Case]
  • Images inside Tables
  • Verify that images can be contained inside tables.[from Image Functional Test Case]
  • Multicolumns inside a Table
  • Verify that multicolumns can be contained inside a table.[from Multicolumn Functional Test Case]
  • Table with Plug-ins
  • Verify that multimedia plug-ins can be contained inside a table.
  • Nested Tables
  • Verify that tables can be nested inside other tables.
  • Invalid Table Tags
  • Verify that table will NOT crash when closing table tags were missing.
  • Image/table overlapping
  • Verify that Image and table text should NOT co-exist in the same space.
  • + +
    + + + +

    + +
    + +

    + + + + + + + + + + + + + +
    + back to Body
    +
    +
    + back to Functional Test Suite + + + back to Tag Index + +   + back to Acceptance Test + + + on to Stress Test + +
    + +
    + + + +
    + Created 5/13/96 by Ronald Greti
    + Modified 11/03/96 by Ronald Greti
    + Modified 12/08/96 by Robert Wehrfritz
    + Modified 03/04/97 by Chitra Natarajan
    + Modified 1/13/98 by Fenella Gor
    +

    + +

    +

    CONFIDENTIAL AND PROPRIETARY TEST SCRIPT OF NETSCAPE COMMUNICATIONS CORP.
    Copyright © 1996 Netscape Communications Corp. All Rights Reserved.
    Use of this Test Script is subject to the terms of the applicable license agreement from Netscape Communications Corp.
    diff --git a/mozilla/layout/makefile.win b/mozilla/layout/makefile.win new file mode 100644 index 00000000000..0e5c931a894 --- /dev/null +++ b/mozilla/layout/makefile.win @@ -0,0 +1,23 @@ +#!nmake +# +# 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. + +DEPTH=.. +IGNORE_MANIFEST=1 + +DIRS=base html build + +include <$(DEPTH)\config\rules.mak> diff --git a/mozilla/layout/style/nsCSSDeclaration.cpp b/mozilla/layout/style/nsCSSDeclaration.cpp new file mode 100644 index 00000000000..2f9d7ac6155 --- /dev/null +++ b/mozilla/layout/style/nsCSSDeclaration.cpp @@ -0,0 +1,1350 @@ +/* -*- 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 "nsICSSDeclaration.h" +#include "nsString.h" +#include "nsCRT.h" +#include "nsCSSProps.h" +#include "nsCSSPropIDs.h" +#include "nsUnitConversion.h" + +static NS_DEFINE_IID(kCSSFontSID, NS_CSS_FONT_SID); +static NS_DEFINE_IID(kCSSColorSID, NS_CSS_COLOR_SID); +static NS_DEFINE_IID(kCSSTextSID, NS_CSS_TEXT_SID); +static NS_DEFINE_IID(kCSSMarginSID, NS_CSS_MARGIN_SID); +static NS_DEFINE_IID(kCSSPositionSID, NS_CSS_POSITION_SID); +static NS_DEFINE_IID(kCSSListSID, NS_CSS_LIST_SID); +static NS_DEFINE_IID(kICSSDeclarationIID, NS_ICSS_DECLARATION_IID); + + +nsCSSValue::nsCSSValue(void) + : mUnit(eCSSUnit_Null) +{ + mValue.mInt = 0; +} + +nsCSSValue::nsCSSValue(PRInt32 aValue, nsCSSUnit aUnit) + : mUnit(aUnit) +{ + mValue.mInt = aValue; +} + +nsCSSValue::nsCSSValue(float aValue, nsCSSUnit aUnit) + : mUnit(aUnit) +{ + mValue.mFloat = aValue; +} + +nsCSSValue::nsCSSValue(const nsString& aValue) + : mUnit(eCSSUnit_String) +{ + mValue.mString = aValue.ToNewString(); +} + +nsCSSValue::nsCSSValue(nscolor aValue) + : mUnit(eCSSUnit_Color) +{ + mValue.mColor = aValue; +} + +nsCSSValue::nsCSSValue(const nsCSSValue& aCopy) + : mUnit(aCopy.mUnit) +{ + if (eCSSUnit_String == mUnit) { + if (nsnull != aCopy.mValue.mString) { + mValue.mString = (aCopy.mValue.mString)->ToNewString(); + } + else { + mValue.mString = nsnull; + } + } + else if ((eCSSUnit_Absolute <= mUnit) && (mUnit <= eCSSUnit_Enumerated)) { + mValue.mInt = aCopy.mValue.mInt; + } + else if (eCSSUnit_Color == mUnit){ + mValue.mColor = aCopy.mValue.mColor; + } + else { + mValue.mFloat = aCopy.mValue.mFloat; + } +} + +nsCSSValue::~nsCSSValue(void) +{ + Reset(); +} + +nsCSSValue& nsCSSValue::operator=(const nsCSSValue& aCopy) +{ + Reset(); + mUnit = aCopy.mUnit; + if (eCSSUnit_String == mUnit) { + if (nsnull != aCopy.mValue.mString) { + mValue.mString = (aCopy.mValue.mString)->ToNewString(); + } + } + else if ((eCSSUnit_Absolute <= mUnit) && (mUnit <= eCSSUnit_Enumerated)) { + mValue.mInt = aCopy.mValue.mInt; + } + else if (eCSSUnit_Color == mUnit){ + mValue.mColor = aCopy.mValue.mColor; + } + else { + mValue.mFloat = aCopy.mValue.mFloat; + } + return *this; +} + +PRBool nsCSSValue::operator==(const nsCSSValue& aOther) const +{ + if (mUnit == aOther.mUnit) { + if (eCSSUnit_String == mUnit) { + if (nsnull == mValue.mString) { + if (nsnull == aOther.mValue.mString) { + return PR_TRUE; + } + } + else if (nsnull != aOther.mValue.mString) { + return mValue.mString->Equals(*(aOther.mValue.mString)); + } + } + else if ((eCSSUnit_Absolute <= mUnit) && (mUnit < eCSSUnit_Percent)) { + return PRBool(mValue.mInt == aOther.mValue.mInt); + } + else if (eCSSUnit_Color == mUnit){ + return PRBool(mValue.mColor == aOther.mValue.mColor); + } + else { + return PRBool(mValue.mFloat == aOther.mValue.mFloat); + } + } + return PR_FALSE; +} + +nscoord nsCSSValue::GetLengthTwips(void) const +{ + NS_ASSERTION(IsFixedLengthUnit(), "not a fixed length unit"); + + if (IsFixedLengthUnit()) { + switch (mUnit) { + case eCSSUnit_Inch: + return (nscoord)NS_INCHES_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Foot: + return (nscoord)NS_FEET_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Mile: + return (nscoord)NS_MILES_TO_TWIPS(mValue.mFloat); + + case eCSSUnit_Millimeter: + return (nscoord)NS_MILLIMETERS_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Centimeter: + return (nscoord)NS_CENTIMETERS_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Meter: + return (nscoord)NS_METERS_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Kilometer: + return (nscoord)NS_KILOMETERS_TO_TWIPS(mValue.mFloat); + + case eCSSUnit_Point: + return (nscoord)NS_POINTS_TO_TWIPS_FLOAT(mValue.mFloat); + case eCSSUnit_Pica: + return (nscoord)NS_PICAS_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Didot: + return (nscoord)NS_DIDOTS_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Cicero: + return (nscoord)NS_CICEROS_TO_TWIPS(mValue.mFloat); + } + } + return 0; +} + +void nsCSSValue::Reset(void) +{ + if ((eCSSUnit_String == mUnit) && (nsnull != mValue.mString)) { + delete mValue.mString; + } + mUnit = eCSSUnit_Null; + mValue.mInt = 0; +}; + +void nsCSSValue::Set(PRInt32 aValue, nsCSSUnit aUnit) +{ + Reset(); + mUnit = aUnit; + mValue.mInt = aValue; +} + +void nsCSSValue::Set(float aValue, nsCSSUnit aUnit) +{ + Reset(); + mUnit = aUnit; + mValue.mFloat = aValue; +} + +void nsCSSValue::Set(const nsString& aValue) +{ + Reset(); + mUnit = eCSSUnit_String; + mValue.mString = aValue.ToNewString(); +} + +void nsCSSValue::Set(nscolor aValue) +{ + Reset(); + mUnit = eCSSUnit_Color; + mValue.mColor = aValue; +} + +void nsCSSValue::AppendToString(nsString& aBuffer, PRInt32 aPropID) const +{ + if (eCSSUnit_Null == mUnit) { + return; + } + + if (-1 < aPropID) { + aBuffer.Append(nsCSSProps::kNameTable[aPropID].name); + aBuffer.Append(": "); + } + + if (eCSSUnit_String == mUnit) { + if (nsnull != mValue.mString) { + aBuffer.Append('"'); + aBuffer.Append(*(mValue.mString)); + aBuffer.Append('"'); + } + else { + aBuffer.Append("null str"); + } + } + else if ((eCSSUnit_Absolute <= mUnit) && (mUnit <= eCSSUnit_Enumerated)) { + aBuffer.Append(mValue.mInt, 10); + aBuffer.Append("[0x"); + aBuffer.Append(mValue.mInt, 16); + aBuffer.Append(']'); + } + else if (eCSSUnit_Color == mUnit){ + aBuffer.Append("(0x"); + aBuffer.Append(NS_GET_R(mValue.mColor), 16); + aBuffer.Append(" 0x"); + aBuffer.Append(NS_GET_G(mValue.mColor), 16); + aBuffer.Append(" 0x"); + aBuffer.Append(NS_GET_B(mValue.mColor), 16); + aBuffer.Append(" 0x"); + aBuffer.Append(NS_GET_A(mValue.mColor), 16); + aBuffer.Append(')'); + } + else if (eCSSUnit_Percent <= mUnit) { + aBuffer.Append(mValue.mFloat); + } + + switch (mUnit) { + case eCSSUnit_Null: break; + case eCSSUnit_Auto: aBuffer.Append("auto"); break; + case eCSSUnit_String: break; + case eCSSUnit_Absolute: aBuffer.Append("abs"); break; + case eCSSUnit_Enumerated: aBuffer.Append("enum"); break; + case eCSSUnit_Color: aBuffer.Append("rbga"); break; + case eCSSUnit_Percent: aBuffer.Append("%"); break; + case eCSSUnit_Number: aBuffer.Append("#"); break; + case eCSSUnit_Inch: aBuffer.Append("in"); break; + case eCSSUnit_Foot: aBuffer.Append("ft"); break; + case eCSSUnit_Mile: aBuffer.Append("mi"); break; + case eCSSUnit_Millimeter: aBuffer.Append("mm"); break; + case eCSSUnit_Centimeter: aBuffer.Append("cm"); break; + case eCSSUnit_Meter: aBuffer.Append("m"); break; + case eCSSUnit_Kilometer: aBuffer.Append("km"); break; + case eCSSUnit_Point: aBuffer.Append("pt"); break; + case eCSSUnit_Pica: aBuffer.Append("pc"); break; + case eCSSUnit_Didot: aBuffer.Append("dt"); break; + case eCSSUnit_Cicero: aBuffer.Append("cc"); break; + case eCSSUnit_EM: aBuffer.Append("em"); break; + case eCSSUnit_EN: aBuffer.Append("en"); break; + case eCSSUnit_XHeight: aBuffer.Append("ex"); break; + case eCSSUnit_CapHeight: aBuffer.Append("cap"); break; + case eCSSUnit_Pixel: aBuffer.Append("px"); break; + } + aBuffer.Append(' '); +} + +void nsCSSValue::ToString(nsString& aBuffer, PRInt32 aPropID) const +{ + aBuffer.SetLength(0); + AppendToString(aBuffer, aPropID); +} + +const nsID& nsCSSFont::GetID(void) +{ + return kCSSFontSID; +} + +void nsCSSFont::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + nsAutoString buffer; + + mFamily.AppendToString(buffer, PROP_FONT_FAMILY); + mStyle.AppendToString(buffer, PROP_FONT_STYLE); + mVariant.AppendToString(buffer, PROP_FONT_VARIANT); + mWeight.AppendToString(buffer, PROP_FONT_WEIGHT); + mSize.AppendToString(buffer, PROP_FONT_SIZE); + fputs(buffer, out); +} + + +const nsID& nsCSSColor::GetID(void) +{ + return kCSSColorSID; +} + +void nsCSSColor::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + nsAutoString buffer; + + mColor.AppendToString(buffer, PROP_COLOR); + mBackColor.AppendToString(buffer, PROP_BACKGROUND_COLOR); + mBackImage.AppendToString(buffer, PROP_BACKGROUND_IMAGE); + mBackRepeat.AppendToString(buffer, PROP_BACKGROUND_REPEAT); + mBackAttachment.AppendToString(buffer, PROP_BACKGROUND_ATTACHMENT); + mBackPositionX.AppendToString(buffer, PROP_BACKGROUND_X_POSITION); + mBackPositionY.AppendToString(buffer, PROP_BACKGROUND_Y_POSITION); + mBackFilter.AppendToString(buffer, PROP_BACKGROUND_FILTER); + fputs(buffer, out); +} + +const nsID& nsCSSText::GetID(void) +{ + return kCSSTextSID; +} + +void nsCSSText::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + nsAutoString buffer; + + mWordSpacing.AppendToString(buffer, PROP_WORD_SPACING); + mLetterSpacing.AppendToString(buffer, PROP_LETTER_SPACING); + mDecoration.AppendToString(buffer, PROP_TEXT_DECORATION); + mVertAlign.AppendToString(buffer, PROP_VERTICAL_ALIGN); + mTransform.AppendToString(buffer, PROP_TEXT_TRANSFORM); + mHorzAlign.AppendToString(buffer, PROP_TEXT_ALIGN); + mIndent.AppendToString(buffer, PROP_TEXT_INDENT); + mLineHeight.AppendToString(buffer, PROP_LINE_HEIGHT); + mWhiteSpace.AppendToString(buffer, PROP_WHITE_SPACE); + fputs(buffer, out); +} + +void nsCSSRect::List(FILE* out, PRInt32 aPropID, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + nsAutoString buffer; + + if (-1 < aPropID) { + buffer.Append(nsCSSProps::kNameTable[aPropID].name); + buffer.Append(": "); + } + + mTop.AppendToString(buffer); + mRight.AppendToString(buffer); + mBottom.AppendToString(buffer); + mLeft.AppendToString(buffer); + fputs(buffer, out); +} + +nsCSSMargin::nsCSSMargin(void) + : mMargin(nsnull), mPadding(nsnull), mBorder(nsnull), mColor(nsnull), mStyle(nsnull) +{ +} + +nsCSSMargin::~nsCSSMargin(void) +{ + if (nsnull != mMargin) { + delete mMargin; + } + if (nsnull != mPadding) { + delete mPadding; + } + if (nsnull != mBorder) { + delete mBorder; + } + if (nsnull != mColor) { + delete mColor; + } + if (nsnull != mStyle) { + delete mStyle; + } +} + +const nsID& nsCSSMargin::GetID(void) +{ + return kCSSMarginSID; +} + +void nsCSSMargin::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + if (nsnull != mMargin) { + mMargin->List(out, PROP_MARGIN, aIndent); + } + if (nsnull != mPadding) { + mPadding->List(out, PROP_PADDING, aIndent); + } + if (nsnull != mBorder) { + mBorder->List(out, PROP_BORDER_WIDTH, aIndent); + } + if (nsnull != mColor) { + mColor->List(out, PROP_BORDER_COLOR, aIndent); + } + if (nsnull != mStyle) { + mStyle->List(out, PROP_BORDER_STYLE, aIndent); + } +} + +nsCSSPosition::nsCSSPosition(void) + : mClip(nsnull) +{ +} + +nsCSSPosition::~nsCSSPosition(void) +{ + if (nsnull != mClip) { + delete mClip; + } +} + +const nsID& nsCSSPosition::GetID(void) +{ + return kCSSPositionSID; +} + +void nsCSSPosition::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + nsAutoString buffer; + + mPosition.AppendToString(buffer, PROP_POSITION); + mWidth.AppendToString(buffer, PROP_WIDTH); + mHeight.AppendToString(buffer, PROP_HEIGHT); + mLeft.AppendToString(buffer, PROP_LEFT); + mTop.AppendToString(buffer, PROP_TOP); + fputs(buffer, out); + if (nsnull != mClip) { + mClip->List(out, PROP_CLIP); + } + buffer.SetLength(0); + mOverflow.AppendToString(buffer, PROP_OVERFLOW); + mZIndex.AppendToString(buffer, PROP_OVERFLOW); + mVisibility.AppendToString(buffer, PROP_VISIBILITY); + mFloat.AppendToString(buffer, PROP_FLOAT); + mClear.AppendToString(buffer, PROP_CLEAR); + mDisplay.AppendToString(buffer, PROP_DISPLAY); + mFilter.AppendToString(buffer, PROP_FILTER); + fputs(buffer, out); +} + +const nsID& nsCSSList::GetID(void) +{ + return kCSSListSID; +} + +void nsCSSList::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + nsAutoString buffer; + + mType.AppendToString(buffer, PROP_LIST_STYLE_TYPE); + mImage.AppendToString(buffer, PROP_LIST_STYLE_IMAGE); + mPosition.AppendToString(buffer, PROP_LIST_STYLE_POSITION); + fputs(buffer, out); +} + + + +class CSSDeclarationImpl : public nsICSSDeclaration { +public: + void* operator new(size_t size); + + CSSDeclarationImpl(void); + ~CSSDeclarationImpl(void); + + NS_DECL_ISUPPORTS + + nsresult GetData(const nsID& aSID, nsCSSStruct** aData); + nsresult EnsureData(const nsID& aSID, nsCSSStruct** aData); + + nsresult AddValue(const char* aProperty, const nsCSSValue& aValue); + nsresult AddValue(PRInt32 aProperty, const nsCSSValue& aValue); + nsresult GetValue(const char* aProperty, nsCSSValue& aValue); + nsresult GetValue(PRInt32 aProperty, nsCSSValue& aValue); + + void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + +private: + CSSDeclarationImpl(const CSSDeclarationImpl& aCopy); + CSSDeclarationImpl& operator=(const CSSDeclarationImpl& aCopy); + PRBool operator==(const CSSDeclarationImpl& aCopy) const; + +protected: + nsCSSFont* mFont; + nsCSSColor* mColor; + nsCSSText* mText; + nsCSSMargin* mMargin; + nsCSSPosition* mPosition; + nsCSSList* mList; +}; + +void* CSSDeclarationImpl::operator new(size_t size) +{ + void* result = new char[size]; + + nsCRT::zero(result, size); + return result; +} + +CSSDeclarationImpl::CSSDeclarationImpl(void) +{ + NS_INIT_REFCNT(); +} + +CSSDeclarationImpl::~CSSDeclarationImpl(void) +{ + if (nsnull != mFont) { + delete mFont; + } + if (nsnull != mColor) { + delete mColor; + } + if (nsnull != mText) { + delete mText; + } + if (nsnull != mMargin) { + delete mMargin; + } + if (nsnull != mPosition) { + delete mPosition; + } + if (nsnull != mList) { + delete mList; + } +} + +NS_IMPL_ISUPPORTS(CSSDeclarationImpl, kICSSDeclarationIID); + +nsresult CSSDeclarationImpl::GetData(const nsID& aSID, nsCSSStruct** aDataPtr) +{ + if (nsnull == aDataPtr) { + return NS_ERROR_NULL_POINTER; + } + + if (aSID.Equals(kCSSFontSID)) { + *aDataPtr = mFont; + } + else if (aSID.Equals(kCSSColorSID)) { + *aDataPtr = mColor; + } + else if (aSID.Equals(kCSSTextSID)) { + *aDataPtr = mText; + } + else if (aSID.Equals(kCSSMarginSID)) { + *aDataPtr = mMargin; + } + else if (aSID.Equals(kCSSPositionSID)) { + *aDataPtr = mPosition; + } + else if (aSID.Equals(kCSSListSID)) { + *aDataPtr = mList; + } + else { + return NS_NOINTERFACE; + } + return NS_OK; +} + +nsresult CSSDeclarationImpl::EnsureData(const nsID& aSID, nsCSSStruct** aDataPtr) +{ + if (nsnull == aDataPtr) { + return NS_ERROR_NULL_POINTER; + } + + if (aSID.Equals(kCSSFontSID)) { + if (nsnull == mFont) { + mFont = new nsCSSFont(); + } + *aDataPtr = mFont; + } + else if (aSID.Equals(kCSSColorSID)) { + if (nsnull == mColor) { + mColor = new nsCSSColor(); + } + *aDataPtr = mColor; + } + else if (aSID.Equals(kCSSTextSID)) { + if (nsnull == mText) { + mText = new nsCSSText(); + } + *aDataPtr = mText; + } + else if (aSID.Equals(kCSSMarginSID)) { + if (nsnull == mMargin) { + mMargin = new nsCSSMargin(); + } + *aDataPtr = mMargin; + } + else if (aSID.Equals(kCSSPositionSID)) { + if (nsnull == mPosition) { + mPosition = new nsCSSPosition(); + } + *aDataPtr = mPosition; + } + else if (aSID.Equals(kCSSListSID)) { + if (nsnull == mList) { + mList = new nsCSSList(); + } + *aDataPtr = mList; + } + else { + return NS_NOINTERFACE; + } + if (nsnull == *aDataPtr) { + return NS_ERROR_OUT_OF_MEMORY; + } + return NS_OK; +} + +nsresult CSSDeclarationImpl::AddValue(const char* aProperty, const nsCSSValue& aValue) +{ + return AddValue(nsCSSProps::LookupName(aProperty), aValue); +} + +nsresult CSSDeclarationImpl::AddValue(PRInt32 aProperty, const nsCSSValue& aValue) +{ + nsresult result = NS_OK; + + switch (aProperty) { + // nsCSSFont + case PROP_FONT_FAMILY: + case PROP_FONT_STYLE: + case PROP_FONT_VARIANT: + case PROP_FONT_WEIGHT: + case PROP_FONT_SIZE: + if (nsnull == mFont) { + mFont = new nsCSSFont(); + } + if (nsnull != mFont) { + switch (aProperty) { + case PROP_FONT_FAMILY: mFont->mFamily = aValue; break; + case PROP_FONT_STYLE: mFont->mStyle = aValue; break; + case PROP_FONT_VARIANT: mFont->mVariant = aValue; break; + case PROP_FONT_WEIGHT: mFont->mWeight = aValue; break; + case PROP_FONT_SIZE: mFont->mSize = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + // nsCSSColor + case PROP_COLOR: + case PROP_BACKGROUND_COLOR: + case PROP_BACKGROUND_IMAGE: + case PROP_BACKGROUND_REPEAT: + case PROP_BACKGROUND_ATTACHMENT: + case PROP_BACKGROUND_X_POSITION: + case PROP_BACKGROUND_Y_POSITION: + case PROP_BACKGROUND_FILTER: + if (nsnull == mColor) { + mColor = new nsCSSColor(); + } + if (nsnull != mColor) { + switch (aProperty) { + case PROP_COLOR: mColor->mColor = aValue; break; + case PROP_BACKGROUND_COLOR: mColor->mBackColor = aValue; break; + case PROP_BACKGROUND_IMAGE: mColor->mBackImage = aValue; break; + case PROP_BACKGROUND_REPEAT: mColor->mBackRepeat = aValue; break; + case PROP_BACKGROUND_ATTACHMENT: mColor->mBackAttachment = aValue; break; + case PROP_BACKGROUND_X_POSITION: mColor->mBackPositionX = aValue; break; + case PROP_BACKGROUND_Y_POSITION: mColor->mBackPositionY = aValue; break; + case PROP_BACKGROUND_FILTER: mColor->mBackFilter = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + // nsCSSText + case PROP_WORD_SPACING: + case PROP_LETTER_SPACING: + case PROP_TEXT_DECORATION: + case PROP_VERTICAL_ALIGN: + case PROP_TEXT_TRANSFORM: + case PROP_TEXT_ALIGN: + case PROP_TEXT_INDENT: + case PROP_LINE_HEIGHT: + case PROP_WHITE_SPACE: + if (nsnull == mText) { + mText = new nsCSSText(); + } + if (nsnull != mText) { + switch (aProperty) { + case PROP_WORD_SPACING: mText->mWordSpacing = aValue; break; + case PROP_LETTER_SPACING: mText->mLetterSpacing = aValue; break; + case PROP_TEXT_DECORATION: mText->mDecoration = aValue; break; + case PROP_VERTICAL_ALIGN: mText->mVertAlign = aValue; break; + case PROP_TEXT_TRANSFORM: mText->mTransform = aValue; break; + case PROP_TEXT_ALIGN: mText->mHorzAlign = aValue; break; + case PROP_TEXT_INDENT: mText->mIndent = aValue; break; + case PROP_LINE_HEIGHT: mText->mLineHeight = aValue; break; + case PROP_WHITE_SPACE: mText->mWhiteSpace = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + // nsCSSMargin + case PROP_MARGIN_TOP: + case PROP_MARGIN_RIGHT: + case PROP_MARGIN_BOTTOM: + case PROP_MARGIN_LEFT: + if (nsnull == mMargin) { + mMargin = new nsCSSMargin(); + } + if (nsnull != mMargin) { + if (nsnull == mMargin->mMargin) { + mMargin->mMargin = new nsCSSRect(); + } + if (nsnull != mMargin->mMargin) { + switch (aProperty) { + case PROP_MARGIN_TOP: mMargin->mMargin->mTop = aValue; break; + case PROP_MARGIN_RIGHT: mMargin->mMargin->mRight = aValue; break; + case PROP_MARGIN_BOTTOM: mMargin->mMargin->mBottom = aValue; break; + case PROP_MARGIN_LEFT: mMargin->mMargin->mLeft = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + case PROP_PADDING_TOP: + case PROP_PADDING_RIGHT: + case PROP_PADDING_BOTTOM: + case PROP_PADDING_LEFT: + if (nsnull == mMargin) { + mMargin = new nsCSSMargin(); + } + if (nsnull != mMargin) { + if (nsnull == mMargin->mPadding) { + mMargin->mPadding = new nsCSSRect(); + } + if (nsnull != mMargin->mPadding) { + switch (aProperty) { + case PROP_PADDING_TOP: mMargin->mPadding->mTop = aValue; break; + case PROP_PADDING_RIGHT: mMargin->mPadding->mRight = aValue; break; + case PROP_PADDING_BOTTOM: mMargin->mPadding->mBottom = aValue; break; + case PROP_PADDING_LEFT: mMargin->mPadding->mLeft = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + case PROP_BORDER_TOP_WIDTH: + case PROP_BORDER_RIGHT_WIDTH: + case PROP_BORDER_BOTTOM_WIDTH: + case PROP_BORDER_LEFT_WIDTH: + if (nsnull == mMargin) { + mMargin = new nsCSSMargin(); + } + if (nsnull != mMargin) { + if (nsnull == mMargin->mBorder) { + mMargin->mBorder = new nsCSSRect(); + } + if (nsnull != mMargin->mBorder) { + switch (aProperty) { + case PROP_BORDER_TOP_WIDTH: mMargin->mBorder->mTop = aValue; break; + case PROP_BORDER_RIGHT_WIDTH: mMargin->mBorder->mRight = aValue; break; + case PROP_BORDER_BOTTOM_WIDTH: mMargin->mBorder->mBottom = aValue; break; + case PROP_BORDER_LEFT_WIDTH: mMargin->mBorder->mLeft = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + case PROP_BORDER_TOP_COLOR: + case PROP_BORDER_RIGHT_COLOR: + case PROP_BORDER_BOTTOM_COLOR: + case PROP_BORDER_LEFT_COLOR: + if (nsnull == mMargin) { + mMargin = new nsCSSMargin(); + } + if (nsnull != mMargin) { + if (nsnull == mMargin->mColor) { + mMargin->mColor = new nsCSSRect(); + } + if (nsnull != mMargin->mColor) { + switch (aProperty) { + case PROP_BORDER_TOP_COLOR: mMargin->mColor->mTop = aValue; break; + case PROP_BORDER_RIGHT_COLOR: mMargin->mColor->mRight = aValue; break; + case PROP_BORDER_BOTTOM_COLOR: mMargin->mColor->mBottom = aValue; break; + case PROP_BORDER_LEFT_COLOR: mMargin->mColor->mLeft = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + case PROP_BORDER_TOP_STYLE: + case PROP_BORDER_RIGHT_STYLE: + case PROP_BORDER_BOTTOM_STYLE: + case PROP_BORDER_LEFT_STYLE: + if (nsnull == mMargin) { + mMargin = new nsCSSMargin(); + } + if (nsnull != mMargin) { + if (nsnull == mMargin->mStyle) { + mMargin->mStyle = new nsCSSRect(); + } + if (nsnull != mMargin->mStyle) { + switch (aProperty) { + case PROP_BORDER_TOP_STYLE: mMargin->mStyle->mTop = aValue; break; + case PROP_BORDER_RIGHT_STYLE: mMargin->mStyle->mRight = aValue; break; + case PROP_BORDER_BOTTOM_STYLE: mMargin->mStyle->mBottom = aValue; break; + case PROP_BORDER_LEFT_STYLE: mMargin->mStyle->mLeft = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + // nsCSSPosition + case PROP_POSITION: + case PROP_WIDTH: + case PROP_HEIGHT: + case PROP_LEFT: + case PROP_TOP: + case PROP_OVERFLOW: + case PROP_Z_INDEX: + case PROP_VISIBILITY: + case PROP_FLOAT: + case PROP_CLEAR: + case PROP_DISPLAY: + case PROP_FILTER: + if (nsnull == mPosition) { + mPosition = new nsCSSPosition(); + } + if (nsnull != mPosition) { + switch (aProperty) { + case PROP_POSITION: mPosition->mPosition = aValue; break; + case PROP_WIDTH: mPosition->mWidth = aValue; break; + case PROP_HEIGHT: mPosition->mHeight = aValue; break; + case PROP_LEFT: mPosition->mLeft = aValue; break; + case PROP_TOP: mPosition->mTop = aValue; break; + case PROP_OVERFLOW: mPosition->mOverflow = aValue; break; + case PROP_Z_INDEX: mPosition->mZIndex = aValue; break; + case PROP_VISIBILITY: mPosition->mVisibility = aValue; break; + case PROP_FLOAT: mPosition->mFloat = aValue; break; + case PROP_CLEAR: mPosition->mClear = aValue; break; + case PROP_DISPLAY: mPosition->mDisplay = aValue; break; + case PROP_FILTER: mPosition->mFilter = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + case PROP_CLIP_TOP: + case PROP_CLIP_RIGHT: + case PROP_CLIP_BOTTOM: + case PROP_CLIP_LEFT: + if (nsnull == mPosition) { + mPosition = new nsCSSPosition(); + } + if (nsnull != mPosition) { + if (nsnull == mPosition->mClip) { + mPosition->mClip = new nsCSSRect(); + } + if (nsnull != mPosition->mClip) { + switch(aProperty) { + case PROP_CLIP_TOP: mPosition->mClip->mTop = aValue; break; + case PROP_CLIP_RIGHT: mPosition->mClip->mRight = aValue; break; + case PROP_CLIP_BOTTOM: mPosition->mClip->mBottom = aValue; break; + case PROP_CLIP_LEFT: mPosition->mClip->mLeft = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + // nsCSSList + case PROP_LIST_STYLE_TYPE: + case PROP_LIST_STYLE_IMAGE: + case PROP_LIST_STYLE_POSITION: + if (nsnull == mList) { + mList = new nsCSSList(); + } + if (nsnull != mList) { + switch (aProperty) { + case PROP_LIST_STYLE_TYPE: mList->mType = aValue; break; + case PROP_LIST_STYLE_IMAGE: mList->mImage = aValue; break; + case PROP_LIST_STYLE_POSITION: mList->mPosition = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + case PROP_BACKGROUND: + case PROP_BORDER: + case PROP_CLIP: + case PROP_FONT: + case PROP_LIST_STYLE: + case PROP_MARGIN: + case PROP_PADDING: + case PROP_BACKGROUND_POSITION: + case PROP_BORDER_TOP: + case PROP_BORDER_RIGHT: + case PROP_BORDER_BOTTOM: + case PROP_BORDER_LEFT: + case PROP_BORDER_COLOR: + case PROP_BORDER_STYLE: + case PROP_BORDER_WIDTH: + NS_ERROR("can't query for shorthand properties"); + default: + result = NS_ERROR_ILLEGAL_VALUE; + break; + } + return result; +} + +nsresult CSSDeclarationImpl::GetValue(const char* aProperty, nsCSSValue& aValue) +{ + return GetValue(nsCSSProps::LookupName(aProperty), aValue); +} + +nsresult CSSDeclarationImpl::GetValue(PRInt32 aProperty, nsCSSValue& aValue) +{ + nsresult result = NS_OK; + + switch (aProperty) { + // nsCSSFont + case PROP_FONT_FAMILY: + case PROP_FONT_STYLE: + case PROP_FONT_VARIANT: + case PROP_FONT_WEIGHT: + case PROP_FONT_SIZE: + if (nsnull != mFont) { + switch (aProperty) { + case PROP_FONT_FAMILY: aValue = mFont->mFamily; break; + case PROP_FONT_STYLE: aValue = mFont->mStyle; break; + case PROP_FONT_VARIANT: aValue = mFont->mVariant; break; + case PROP_FONT_WEIGHT: aValue = mFont->mWeight; break; + case PROP_FONT_SIZE: aValue = mFont->mSize; break; + } + } + else { + aValue.Reset(); + } + break; + + // nsCSSColor + case PROP_COLOR: + case PROP_BACKGROUND_COLOR: + case PROP_BACKGROUND_IMAGE: + case PROP_BACKGROUND_REPEAT: + case PROP_BACKGROUND_ATTACHMENT: + case PROP_BACKGROUND_X_POSITION: + case PROP_BACKGROUND_Y_POSITION: + case PROP_BACKGROUND_FILTER: + if (nsnull != mColor) { + switch (aProperty) { + case PROP_COLOR: aValue = mColor->mColor; break; + case PROP_BACKGROUND_COLOR: aValue = mColor->mBackColor; break; + case PROP_BACKGROUND_IMAGE: aValue = mColor->mBackImage; break; + case PROP_BACKGROUND_REPEAT: aValue = mColor->mBackRepeat; break; + case PROP_BACKGROUND_ATTACHMENT: aValue = mColor->mBackAttachment; break; + case PROP_BACKGROUND_X_POSITION: aValue = mColor->mBackPositionX; break; + case PROP_BACKGROUND_Y_POSITION: aValue = mColor->mBackPositionY; break; + case PROP_BACKGROUND_FILTER: aValue = mColor->mBackFilter; break; + } + } + else { + aValue.Reset(); + } + break; + + // nsCSSText + case PROP_WORD_SPACING: + case PROP_LETTER_SPACING: + case PROP_TEXT_DECORATION: + case PROP_VERTICAL_ALIGN: + case PROP_TEXT_TRANSFORM: + case PROP_TEXT_ALIGN: + case PROP_TEXT_INDENT: + case PROP_LINE_HEIGHT: + case PROP_WHITE_SPACE: + if (nsnull != mText) { + switch (aProperty) { + case PROP_WORD_SPACING: aValue = mText->mWordSpacing; break; + case PROP_LETTER_SPACING: aValue = mText->mLetterSpacing; break; + case PROP_TEXT_DECORATION: aValue = mText->mDecoration; break; + case PROP_VERTICAL_ALIGN: aValue = mText->mVertAlign; break; + case PROP_TEXT_TRANSFORM: aValue = mText->mTransform; break; + case PROP_TEXT_ALIGN: aValue = mText->mHorzAlign; break; + case PROP_TEXT_INDENT: aValue = mText->mIndent; break; + case PROP_LINE_HEIGHT: aValue = mText->mLineHeight; break; + case PROP_WHITE_SPACE: aValue = mText->mWhiteSpace; break; + } + } + else { + aValue.Reset(); + } + break; + + // nsCSSMargin + case PROP_MARGIN_TOP: + case PROP_MARGIN_RIGHT: + case PROP_MARGIN_BOTTOM: + case PROP_MARGIN_LEFT: + if ((nsnull != mMargin) && (nsnull != mMargin->mMargin)) { + switch (aProperty) { + case PROP_MARGIN_TOP: aValue = mMargin->mMargin->mTop; break; + case PROP_MARGIN_RIGHT: aValue = mMargin->mMargin->mRight; break; + case PROP_MARGIN_BOTTOM: aValue = mMargin->mMargin->mBottom; break; + case PROP_MARGIN_LEFT: aValue = mMargin->mMargin->mLeft; break; + } + } + else { + aValue.Reset(); + } + break; + + case PROP_PADDING_TOP: + case PROP_PADDING_RIGHT: + case PROP_PADDING_BOTTOM: + case PROP_PADDING_LEFT: + if ((nsnull != mMargin) && (nsnull != mMargin->mPadding)) { + switch (aProperty) { + case PROP_PADDING_TOP: aValue = mMargin->mPadding->mTop; break; + case PROP_PADDING_RIGHT: aValue = mMargin->mPadding->mRight; break; + case PROP_PADDING_BOTTOM: aValue = mMargin->mPadding->mBottom; break; + case PROP_PADDING_LEFT: aValue = mMargin->mPadding->mLeft; break; + } + } + else { + aValue.Reset(); + } + break; + + case PROP_BORDER_TOP_WIDTH: + case PROP_BORDER_RIGHT_WIDTH: + case PROP_BORDER_BOTTOM_WIDTH: + case PROP_BORDER_LEFT_WIDTH: + if ((nsnull != mMargin) && (nsnull != mMargin->mBorder)) { + switch (aProperty) { + case PROP_BORDER_TOP_WIDTH: aValue = mMargin->mBorder->mTop; break; + case PROP_BORDER_RIGHT_WIDTH: aValue = mMargin->mBorder->mRight; break; + case PROP_BORDER_BOTTOM_WIDTH: aValue = mMargin->mBorder->mBottom; break; + case PROP_BORDER_LEFT_WIDTH: aValue = mMargin->mBorder->mLeft; break; + } + } + else { + aValue.Reset(); + } + break; + + case PROP_BORDER_TOP_COLOR: + case PROP_BORDER_RIGHT_COLOR: + case PROP_BORDER_BOTTOM_COLOR: + case PROP_BORDER_LEFT_COLOR: + if ((nsnull != mMargin) && (nsnull != mMargin->mColor)) { + switch (aProperty) { + case PROP_BORDER_TOP_COLOR: aValue = mMargin->mColor->mTop; break; + case PROP_BORDER_RIGHT_COLOR: aValue = mMargin->mColor->mRight; break; + case PROP_BORDER_BOTTOM_COLOR: aValue = mMargin->mColor->mBottom; break; + case PROP_BORDER_LEFT_COLOR: aValue = mMargin->mColor->mLeft; break; + } + } + else { + aValue.Reset(); + } + break; + + case PROP_BORDER_TOP_STYLE: + case PROP_BORDER_RIGHT_STYLE: + case PROP_BORDER_BOTTOM_STYLE: + case PROP_BORDER_LEFT_STYLE: + if ((nsnull != mMargin) && (nsnull != mMargin->mStyle)) { + switch (aProperty) { + case PROP_BORDER_TOP_STYLE: aValue = mMargin->mStyle->mTop; break; + case PROP_BORDER_RIGHT_STYLE: aValue = mMargin->mStyle->mRight; break; + case PROP_BORDER_BOTTOM_STYLE: aValue = mMargin->mStyle->mBottom; break; + case PROP_BORDER_LEFT_STYLE: aValue = mMargin->mStyle->mLeft; break; + } + } + else { + aValue.Reset(); + } + break; + + // nsCSSPosition + case PROP_POSITION: + case PROP_WIDTH: + case PROP_HEIGHT: + case PROP_LEFT: + case PROP_TOP: + case PROP_OVERFLOW: + case PROP_Z_INDEX: + case PROP_VISIBILITY: + case PROP_FLOAT: + case PROP_CLEAR: + case PROP_DISPLAY: + case PROP_FILTER: + if (nsnull != mPosition) { + switch (aProperty) { + case PROP_POSITION: aValue = mPosition->mPosition; break; + case PROP_WIDTH: aValue = mPosition->mWidth; break; + case PROP_HEIGHT: aValue = mPosition->mHeight; break; + case PROP_LEFT: aValue = mPosition->mLeft; break; + case PROP_TOP: aValue = mPosition->mTop; break; + case PROP_OVERFLOW: aValue = mPosition->mOverflow; break; + case PROP_Z_INDEX: aValue = mPosition->mZIndex; break; + case PROP_VISIBILITY: aValue = mPosition->mVisibility; break; + case PROP_FLOAT: aValue = mPosition->mFloat; break; + case PROP_CLEAR: aValue = mPosition->mClear; break; + case PROP_DISPLAY: aValue = mPosition->mDisplay; break; + case PROP_FILTER: aValue = mPosition->mFilter; break; + } + } + else { + aValue.Reset(); + } + break; + + case PROP_CLIP_TOP: + case PROP_CLIP_RIGHT: + case PROP_CLIP_BOTTOM: + case PROP_CLIP_LEFT: + if ((nsnull != mPosition) && (nsnull != mPosition->mClip)) { + switch(aProperty) { + case PROP_CLIP_TOP: aValue = mPosition->mClip->mTop; break; + case PROP_CLIP_RIGHT: aValue = mPosition->mClip->mRight; break; + case PROP_CLIP_BOTTOM: aValue = mPosition->mClip->mBottom; break; + case PROP_CLIP_LEFT: aValue = mPosition->mClip->mLeft; break; + } + } + else { + aValue.Reset(); + } + break; + + // nsCSSList + case PROP_LIST_STYLE_TYPE: + case PROP_LIST_STYLE_IMAGE: + case PROP_LIST_STYLE_POSITION: + if (nsnull != mList) { + switch (aProperty) { + case PROP_LIST_STYLE_TYPE: aValue = mList->mType; break; + case PROP_LIST_STYLE_IMAGE: aValue = mList->mImage; break; + case PROP_LIST_STYLE_POSITION: aValue = mList->mPosition; break; + } + } + else { + aValue.Reset(); + } + break; + + case PROP_BACKGROUND: + case PROP_BORDER: + case PROP_CLIP: + case PROP_FONT: + case PROP_LIST_STYLE: + case PROP_MARGIN: + case PROP_PADDING: + case PROP_BACKGROUND_POSITION: + case PROP_BORDER_TOP: + case PROP_BORDER_RIGHT: + case PROP_BORDER_BOTTOM: + case PROP_BORDER_LEFT: + case PROP_BORDER_COLOR: + case PROP_BORDER_STYLE: + case PROP_BORDER_WIDTH: + NS_ERROR("can't query for shorthand properties"); + default: + result = NS_ERROR_ILLEGAL_VALUE; + break; + } + return result; +} + +void CSSDeclarationImpl::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + fputs("{ ", out); + + if (nsnull != mFont) { + mFont->List(out); + } + if (nsnull != mColor) { + mColor->List(out); + } + if (nsnull != mText) { + mText->List(out); + } + if (nsnull != mMargin) { + mMargin->List(out); + } + if (nsnull != mPosition) { + mPosition->List(out); + } + if (nsnull != mList) { + mList->List(out); + } + + fputs("}", out); +} + +NS_HTML nsresult + NS_NewCSSDeclaration(nsICSSDeclaration** aInstancePtrResult) +{ + if (aInstancePtrResult == nsnull) { + return NS_ERROR_NULL_POINTER; + } + + CSSDeclarationImpl *it = new CSSDeclarationImpl(); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(kICSSDeclarationIID, (void **) aInstancePtrResult); +} + + +/* +font +=========== + +'font-family', string (list) +'font-style', enum +'font-variant' enum (ie: small caps) +'font-weight' enum +'font-size' abs, pct, enum, +-1 + + +color/background +============= + +color: color +background-color: color +background-image: url(string) +background-repeat: enum +background-attachment: enum +background-position-x -y: abs, pct, enum (left/top center right/bottom (pct?)) + + + +text +======= +word-spacing: abs, "normal" +letter-spacing: abs, "normal" +text-decoration: enum +vertical-align: enum, pct +text-transform: enum +text-align: enum +text-indent: abs, pct +line-height: "normal", abs, pct, number-factor +white-space: enum + +margin +======= +margin-top -right -bottom -left: "auto", abs, pct +padding-top -right -bottom -left: abs, pct +border-top -right -bottom -left-width: enum, abs +border-top -right -bottom -left-color: color +border-top -right -bottom -left-style: enum + +size +======= +position: enum +width: abs, pct, "auto" +height: abs, pct, "auto" +left: abs, pct, "auto" +top: abs, pct, "auto" +clip: shape, "auto" (shape: rect - abs, auto) +overflow: enum +z-index: int, auto +visibity: enum + +float: enum +clear: enum + +display: enum + +filter: string + +list +======== +list-style-type: enum +list-style-image: url, "none" +list-style-position: enum (bool? in/out) + +*/ + + + diff --git a/mozilla/layout/style/nsCSSKeywords.cpp b/mozilla/layout/style/nsCSSKeywords.cpp new file mode 100644 index 00000000000..e5f8c9b2654 --- /dev/null +++ b/mozilla/layout/style/nsCSSKeywords.cpp @@ -0,0 +1,389 @@ + +/* +** This is a generated file, do not edit it. This file is created by +** genhash.pl +*/ + +#include "plstr.h" +#include "nsCSSKeywords.h" +#define TOTAL_KEYWORDS 86 +#define MIN_WORD_LENGTH 2 +#define MAX_WORD_LENGTH 12 +#define MIN_HASH_VALUE 8 +#define MAX_HASH_VALUE 322 +/* maximum key range = 315, duplicates = 0 */ + + +struct StaticNameTable { + char* tag; + PRInt32 id; +}; + +static const unsigned char kLowerLookup[256] = { + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, + 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, + 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, + 64, + 97,98,99,100,101,102,103,104,105,106,107,108,109, + 110,111,112,113,114,115,116,117,118,119,120,121,122, + + 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, + + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 +}; + +#define MYLOWER(x) kLowerLookup[((x) & 0x7f)] + +/** + * Map a name to an ID or -1 + */ +PRInt32 nsCSSKeywords::LookupName(const char* str) +{ + static unsigned short asso_values[] = + { + 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 15, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, + 323, 323, 323, 323, 323, 323, 323, 5, 125, 115, + 35, 0, 5, 55, 60, 110, 0, 5, 0, 5, + 75, 0, 90, 5, 0, 25, 0, 27, 0, 90, + 10, 0, 323, 323, 323, 323, 323, 323, + }; + static unsigned char lengthtable[] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 8, 4, 5, 6, 2, 0, + 0, 0, 0, 2, 0, 0, 0, 11, 2, 0, 0, 0, 11, 0, + 0, 0, 0, 0, 7, 6, 7, 0, 4, 0, 0, 0, 5, 0, + 7, 8, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, + 0, 7, 0, 7, 0, 6, 0, 6, 0, 5, 0, 0, 6, 0, + 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 6, 0, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0, 6, 0, + 8, 9, 0, 0, 0, 0, 9, 0, 6, 7, 8, 0, 0, 11, + 2, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, + 0, 2, 0, 0, 0, 6, 7, 0, 0, 5, 6, 0, 0, 0, + 0, 0, 7, 0, 0, 0, 6, 5, 0, 9, 5, 6, 0, 0, + 4, 0, 6, 7, 0, 0, 0, 0, 0, 8, 4, 5, 0, 0, + 0, 9, 5, 0, 7, 0, 0, 0, 11, 0, 0, 0, 5, 0, + 0, 3, 0, 10, 0, 0, 0, 4, 0, 6, 0, 0, 0, 0, + 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 5, 6, 0, 0, 0, 10, 9, 0, 0, + 0, 0, 0, 0, 11, 0, 0, 6, 0, 0, 0, 0, 6, 0, + 8, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 4, 0, 0, + 7, 0, 0, 0, 9, 0, 0, 0, 0, 6, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 6, 0, 0, 4, 0, 0, 0, 11, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, + 2, + }; + static struct StaticNameTable wordlist[] = + { + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"relative", 56}, + {"left", 32}, + {"large", 30}, + {"larger", 31}, + {"em", 18}, + {"",}, {"",}, {"",}, {"",}, + {"mm", 41}, + {"",}, {"",}, {"",}, + {"transparent", 76}, + {"ex", 19}, + {"",}, {"",}, {"",}, + {"text-bottom", 71}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"x-large", 82}, + {"outset", 48}, + {"outside", 49}, + {"",}, + {"auto", 1}, + {"",}, {"",}, {"",}, + {"small", 63}, + {"",}, + {"smaller", 65}, + {"xx-small", 85}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"medium", 39}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"x-small", 83}, + {"",}, + {"justify", 29}, + {"",}, + {"groove", 21}, + {"",}, + {"square", 67}, + {"",}, + {"solid", 66}, + {"",}, {"",}, + {"double", 17}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"dotted", 16}, + {"",}, {"",}, {"",}, {"",}, + {"normal", 44}, + {"",}, + {"overline", 50}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"pt", 54}, + {"pre", 53}, + {"",}, {"",}, + {"repeat", 57}, + {"",}, + {"xx-large", 84}, + {"no-repeat", 42}, + {"",}, {"",}, {"",}, {"",}, + {"lowercase", 38}, + {"",}, + {"dashed", 13}, + {"noshade", 45}, + {"text-top", 72}, + {"",}, {"",}, + {"lower-alpha", 36}, + {"px", 55}, + {"repeat-y", 59}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"repeat-x", 58}, + {"",}, {"",}, {"",}, + {"cm", 12}, + {"",}, {"",}, {"",}, + {"bolder", 6}, + {"oblique", 47}, + {"",}, {"",}, + {"block", 4}, + {"bottom", 8}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"visible", 81}, + {"",}, {"",}, {"",}, + {"scroll", 62}, + {"super", 70}, + {"",}, + {"list-item", 35}, + {"ridge", 60}, + {"static", 68}, + {"",}, {"",}, + {"none", 43}, + {"",}, + {"middle", 40}, + {"decimal", 14}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"absolute", 0}, + {"bold", 5}, + {"fixed", 20}, + {"",}, {"",}, {"",}, + {"paragraph", 51}, + {"right", 61}, + {"",}, + {"lighter", 33}, + {"",}, {"",}, {"",}, + {"lower-roman", 37}, + {"",}, {"",}, {"",}, + {"thick", 73}, + {"",}, {"",}, + {"top", 75}, + {"",}, + {"small-caps", 64}, + {"",}, {"",}, {"",}, + {"both", 7}, + {"",}, + {"inline", 25}, + {"",}, {"",}, {"",}, {"",}, + {"center", 10}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + + {"inset", 26}, + {"inside", 27}, + {"",}, {"",}, {"",}, + {"capitalize", 9}, + {"uppercase", 80}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"upper-alpha", 78}, + {"",}, {"",}, + {"circle", 11}, + {"",}, {"",}, {"",}, {"",}, + {"italic", 28}, + {"",}, + {"baseline", 2}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"blink", 3}, + {"",}, {"",}, {"",}, + {"thin", 74}, + {"",}, {"",}, + {"inherit", 24}, + {"",}, {"",}, {"",}, + {"underline", 77}, + {"",}, {"",}, {"",}, {"",}, + {"nowrap", 46}, + {"in", 23}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"hidden", 22}, + {"",}, {"",}, + {"disc", 15}, + {"",}, {"",}, {"",}, + {"upper-roman", 79}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, + {"sub", 69}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, + {"line-through", 34}, + {"",}, {"",}, {"",}, {"",}, + {"pc", 52}, + }; + + if (str != NULL) { + int len = PL_strlen(str); + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) { + register int hval = len; + + switch (hval) + { + default: + case 7: + hval += asso_values[MYLOWER(str[6])]; + case 6: + case 5: + case 4: + case 3: + hval += asso_values[MYLOWER(str[2])]; + case 2: + hval += asso_values[MYLOWER(str[1])]; + case 1: + hval += asso_values[MYLOWER(str[0])]; + break; + } + hval += asso_values[MYLOWER(str[len - 1])]; + if (hval <= MAX_HASH_VALUE && hval >= MIN_HASH_VALUE) { + if (len == lengthtable[hval]) { + register const char *tag = wordlist[hval].tag; + + /* + ** While not at the end of the string, if they ever differ + ** they are not equal. We know "tag" is already lower case. + */ + while ((*tag != '\0')&&(*str != '\0')) { + if (*tag != (char) MYLOWER(*str)) { + return -1; + } + tag++; + str++; + } + + /* + ** One of the strings has ended, if they are both ended, then they + ** are equal, otherwise not. + */ + if ((*tag == '\0')&&(*str == '\0')) { + return wordlist[hval].id; + } + } + } + } + } + return -1; +} + +const nsCSSKeywords::NameTableEntry nsCSSKeywords::kNameTable[] = { + { "absolute", 0 }, + { "auto", 1 }, + { "baseline", 2 }, + { "blink", 3 }, + { "block", 4 }, + { "bold", 5 }, + { "bolder", 6 }, + { "both", 7 }, + { "bottom", 8 }, + { "capitalize", 9 }, + { "center", 10 }, + { "circle", 11 }, + { "cm", 12 }, + { "dashed", 13 }, + { "decimal", 14 }, + { "disc", 15 }, + { "dotted", 16 }, + { "double", 17 }, + { "em", 18 }, + { "ex", 19 }, + { "fixed", 20 }, + { "groove", 21 }, + { "hidden", 22 }, + { "in", 23 }, + { "inherit", 24 }, + { "inline", 25 }, + { "inset", 26 }, + { "inside", 27 }, + { "italic", 28 }, + { "justify", 29 }, + { "large", 30 }, + { "larger", 31 }, + { "left", 32 }, + { "lighter", 33 }, + { "line-through", 34 }, + { "list-item", 35 }, + { "lower-alpha", 36 }, + { "lower-roman", 37 }, + { "lowercase", 38 }, + { "medium", 39 }, + { "middle", 40 }, + { "mm", 41 }, + { "no-repeat", 42 }, + { "none", 43 }, + { "normal", 44 }, + { "noshade", 45 }, + { "nowrap", 46 }, + { "oblique", 47 }, + { "outset", 48 }, + { "outside", 49 }, + { "overline", 50 }, + { "paragraph", 51 }, + { "pc", 52 }, + { "pre", 53 }, + { "pt", 54 }, + { "px", 55 }, + { "relative", 56 }, + { "repeat", 57 }, + { "repeat-x", 58 }, + { "repeat-y", 59 }, + { "ridge", 60 }, + { "right", 61 }, + { "scroll", 62 }, + { "small", 63 }, + { "small-caps", 64 }, + { "smaller", 65 }, + { "solid", 66 }, + { "square", 67 }, + { "static", 68 }, + { "sub", 69 }, + { "super", 70 }, + { "text-bottom", 71 }, + { "text-top", 72 }, + { "thick", 73 }, + { "thin", 74 }, + { "top", 75 }, + { "transparent", 76 }, + { "underline", 77 }, + { "upper-alpha", 78 }, + { "upper-roman", 79 }, + { "uppercase", 80 }, + { "visible", 81 }, + { "x-large", 82 }, + { "x-small", 83 }, + { "xx-large", 84 }, + { "xx-small", 85 }, +}; diff --git a/mozilla/layout/style/nsCSSKeywords.h b/mozilla/layout/style/nsCSSKeywords.h new file mode 100644 index 00000000000..1db3cbe5ee3 --- /dev/null +++ b/mozilla/layout/style/nsCSSKeywords.h @@ -0,0 +1,40 @@ +/* -*- 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. + */ +#ifndef nsCSSKeywords_h___ +#define nsCSSKeywords_h___ + +#include "nslayout.h" +#include "nsCSSKeywordIDs.h" + +class NS_LAYOUT nsCSSKeywords { +public: + // Given a null terminated string of 7 bit characters, return the + // tag id (see nsHTMLTagIDs.h) for the tag or -1 if the tag is not + // known. The lookup function uses a perfect hash. + static PRInt32 LookupName(const char* str); + + struct NameTableEntry { + const char* name; + PRInt32 id; + }; + + // A table whose index is the tag id (from LookupName) + static const NameTableEntry kNameTable[]; +}; + +#endif /* nsCSSKeywords_h___ */ diff --git a/mozilla/layout/style/nsCSSParser.cpp b/mozilla/layout/style/nsCSSParser.cpp new file mode 100644 index 00000000000..79220097b2c --- /dev/null +++ b/mozilla/layout/style/nsCSSParser.cpp @@ -0,0 +1,2186 @@ +/* -*- 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 "nsICSSParser.h" +#include "nsCSSProps.h" +#include "nsCSSKeywords.h" +#include "nsCSSScanner.h" +#include "nsICSSStyleRule.h" +#include "nsIUnicharInputStream.h" +#include "nsIStyleSet.h" +#include "nsICSSStyleSheet.h" +#include "nsICSSDeclaration.h" +#include "nsStyleConsts.h" +#include "nsIURL.h" +#include "nsString.h" +#include "nsIAtom.h" +#include "nsVoidArray.h" +#include "nsColor.h" + +static NS_DEFINE_IID(kICSSParserIID, NS_ICSS_PARSER_IID); +static NS_DEFINE_IID(kICSSStyleSheetIID, NS_ICSS_STYLE_SHEET_IID); +static NS_DEFINE_IID(kIStyleSheetIID, NS_ISTYLE_SHEET_IID); + +// XXX url's spec'd in a style sheet are relative to the style sheet +// (this includes things like background-image!). +// XXX cell-padding, spacing, etc.??? + +struct Selector { + nsString mTag; // weight 1 + nsString mID; // weight 100 + nsString mClass; // weight 10 + nsString mPseudo; // weight 10 (== class) + PRUint32 mMask; // which fields have values + + Selector(); + ~Selector(); + + PRInt32 Weight() const; +#ifdef NS_DEBUG + void Dump() const; +#endif +}; + +#define SELECTOR_TAG 0x1 +#define SELECTOR_ID 0x2 +#define SELECTOR_CLASS 0x4 +#define SELECTOR_PSEUDO 0x8 + +#define SELECTOR_WEIGHT_BASE 10 + +Selector::Selector() +{ + mMask = 0; +} + +Selector::~Selector() +{ +} + +PRInt32 Selector::Weight() const +{ + return (((0 != (SELECTOR_TAG & mMask)) ? 1 : 0) + + ((0 != (SELECTOR_ID & mMask)) ? (SELECTOR_WEIGHT_BASE * SELECTOR_WEIGHT_BASE) : 0) + + ((0 != ((SELECTOR_CLASS | SELECTOR_PSEUDO) & mMask)) ? SELECTOR_WEIGHT_BASE : 0)); +} + +#ifdef NS_DEBUG +void Selector::Dump() const +{ + PRBool needSpace = PR_FALSE; + if (mTag.Length() > 0) { + fputs(mTag, stdout); + needSpace = PR_TRUE; + } + if (mID.Length() > 0) { + if (needSpace) fputs(" ", stdout); + fputs("#", stdout); + fputs(mID, stdout); + needSpace = PR_TRUE; + } + if (mClass.Length() > 0) { + if (needSpace) fputs(" ", stdout); + fputs(".", stdout); + fputs(mClass, stdout); + needSpace = PR_TRUE; + } + if (mPseudo.Length() > 0) { + if (needSpace) fputs(" ", stdout); + fputs(":", stdout); + fputs(mPseudo, stdout); + needSpace = PR_TRUE; + } +} +#endif + +// e.g. "P B, H1 B { ... }" has a selector list with two elements, +// each of which has two selectors. +struct SelectorList { + SelectorList* mNext; + nsVoidArray mSelectors; + + SelectorList(); + + void Destroy(); + + void AddSelector(Selector* aSelector) { + mSelectors.AppendElement(aSelector); + } + +#ifdef NS_DEBUG + void Dump(); +#endif + +private: + ~SelectorList(); +}; + +SelectorList::SelectorList() +{ + mNext = nsnull; +} + +SelectorList::~SelectorList() +{ + PRInt32 n = mSelectors.Count(); + for (PRInt32 i = 0; i < n; i++) { + Selector* sel = (Selector*) mSelectors.ElementAt(i); + delete sel; + } +} + +void SelectorList::Destroy() +{ + SelectorList* list = this; + while (nsnull != list) { + SelectorList* next = list->mNext; + delete list; + list = next; + } +} + +#ifdef NS_DEBUG +void SelectorList::Dump() +{ + PRInt32 n = mSelectors.Count(); + for (PRInt32 i = 0; i < n; i++) { + Selector* sel = (Selector*) mSelectors.ElementAt(i); + sel->Dump(); + fputs(" ", stdout); + } + if (mNext) { + fputs(", ", stdout); + mNext->Dump(); + } +} +#endif + +//---------------------------------------------------------------------- + +// Your basic top-down recursive descent style parser +class CSSParserImpl : public nsICSSParser { +public: + CSSParserImpl(); + CSSParserImpl(nsICSSStyleSheet* aSheet); + ~CSSParserImpl(); + + NS_DECL_ISUPPORTS + + virtual PRUint32 GetInfoMask(); + + virtual nsresult SetStyleSheet(nsIStyleSheet* aSheet); + + virtual nsIStyleSheet* Parse(PRInt32* aErrorCode, + nsIUnicharInputStream* aInput, + nsIURL* aInputURL); + +protected: + PRBool GetToken(PRInt32* aErrorCode, PRBool aSkipWS); + void UngetToken(); + + PRBool ExpectSymbol(PRInt32* aErrorCode, char aSymbol, PRBool aSkipWS); + nsString* NextIdent(PRInt32* aErrorCode); + void SkipUntil(PRInt32* aErrorCode, PRUnichar aStopSymbol); + void SkipRuleSet(PRInt32* aErrorCode); + void SkipDeclaration(PRInt32* aErrorCode); + + PRBool ParseRuleSet(PRInt32* aErrorCode); + PRBool ParseAtRule(PRInt32* aErrorCode); + PRBool ParseImportRule(PRInt32* aErrorCode); + + PRBool ParseSelectorGroup(PRInt32* aErrorCode, SelectorList* aListHead); + PRBool ParseSelectorList(PRInt32* aErrorCode, SelectorList* aListHead); + PRBool ParseSelector(PRInt32* aErrorCode, Selector* aSelectorResult); + nsICSSDeclaration* ParseDeclarationBlock(PRInt32* aErrorCode); + PRBool ParseDeclaration(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration); + PRBool ParseProperty(PRInt32* aErrorCode, const char* aName, + nsICSSDeclaration* aDeclaration); + PRBool ParseProperty(PRInt32* aErrorCode, const char* aName, + nsICSSDeclaration* aDeclaration, PRInt32 aID); + + // Property specific parsing routines + PRBool ParseBackground(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration); + PRBool ParseBackgroundFilter(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName); + PRBool ParseForegroundFilter(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName); + PRBool ParseBackgroundPosition(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName); + PRBool ParseBorder(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration); + PRBool ParseBorderColor(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration); + PRBool ParseBorderSide(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aNames[], PRInt32 aWhichSide); + PRBool ParseBorderStyle(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration); + PRBool ParseBorderWidth(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration); + PRBool ParseClip(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration); + PRBool ParseFont(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName); + PRBool ParseFontFamily(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName); + PRBool ParseFontWeight(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName); + PRBool ParseListStyle(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration); + PRBool ParseMargin(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration); + PRBool ParsePadding(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration); + PRBool ParseTextDecoration(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName); + + // Reused utility parsing routines + PRBool ParseBoxProperties(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aNames[]); + PRInt32 ParseChoice(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aNames[], PRInt32 aNumNames); + PRBool ParseColor(PRInt32* aErrorCode, nscolor* aColorResult); + PRBool ParseColorComponent(PRInt32* aErrorCode, PRUint8* aComponent, + char aStop); + PRBool ParseEnum(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName, PRInt32* aTable); + PRInt32 SearchKeywordTable(PRInt32 aID, PRInt32 aTable[]); + PRBool ParseVariant(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName, PRInt32 aVariant, + PRInt32* aTable); + PRBool TranslateLength(nsICSSDeclaration* aDeclaration, const char* aName, + float aNumber, const nsString& aDimension); + + void ProcessImport(const nsString& aURLSpec); + + // Current token. The value is valid after calling GetToken + nsCSSToken mToken; + + // After an UngetToken is done this flag is true. The next call to + // GetToken clears the flag. + PRBool mHavePushBack; + + nsCSSScanner* mScanner; + nsIURL* mURL; + nsICSSStyleSheet* mSheet; + + PRBool mInHead; +}; + +NS_HTML nsresult +NS_NewCSSParser(nsICSSParser** aInstancePtrResult) +{ + CSSParserImpl *it = new CSSParserImpl(); + + if (it == nsnull) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(kICSSParserIID, (void **) aInstancePtrResult); +} + +CSSParserImpl::CSSParserImpl() +{ + NS_INIT_REFCNT(); + mScanner = nsnull; + mSheet = nsnull; + mHavePushBack = PR_FALSE; +} + +CSSParserImpl::CSSParserImpl(nsICSSStyleSheet* aSheet) +{ + NS_INIT_REFCNT(); + mScanner = nsnull; + mSheet = aSheet; aSheet->AddRef(); + mHavePushBack = PR_FALSE; +} + +NS_IMPL_ISUPPORTS(CSSParserImpl,kICSSParserIID) + +CSSParserImpl::~CSSParserImpl() +{ + NS_IF_RELEASE(mSheet); +} + +PRUint32 CSSParserImpl::GetInfoMask() +{ + return NS_CSS_GETINFO_CSS1 | NS_CSS_GETINFO_CSSP; +} + +nsresult CSSParserImpl::SetStyleSheet(nsIStyleSheet* aSheet) +{ + NS_PRECONDITION(nsnull != aSheet, "null ptr"); + if (nsnull == aSheet) { + return NS_ERROR_NULL_POINTER; + } + + // Make sure the sheet supports the correct interface! + static NS_DEFINE_IID(kICSSStyleSheetIID, NS_ICSS_STYLE_SHEET_IID); + nsICSSStyleSheet* cssSheet; + nsresult rv = aSheet->QueryInterface(kICSSStyleSheetIID, (void**)&cssSheet); + if (NS_OK != rv) { + return rv; + } + + // Switch to using the new sheet + NS_IF_RELEASE(mSheet); + mSheet = cssSheet; + + return NS_OK; +} + +nsIStyleSheet* CSSParserImpl::Parse(PRInt32* aErrorCode, + nsIUnicharInputStream* aInput, + nsIURL* aInputURL) +{ + if (nsnull == mSheet) { + NS_NewCSSStyleSheet(&mSheet, aInputURL); + } + + mScanner = new nsCSSScanner(); + mScanner->Init(aInput); + mURL = aInputURL; + if (nsnull != aInputURL) { + aInputURL->AddRef(); + } + mInHead = PR_TRUE; + nsCSSToken* tk = &mToken; + for (;;) { + // Get next non-whitespace token + if (!GetToken(aErrorCode, PR_TRUE)) { + break; + } + if (eCSSToken_AtKeyword == tk->mType) { + ParseAtRule(aErrorCode); + continue; + } else if (eCSSToken_Symbol == tk->mType) { + // Discard dangling semicolons. This is not part of the CSS1 + // forward compatible parsing spec, but it makes alot of sense. + if (';' == tk->mSymbol) { + continue; + } + } + mInHead = PR_FALSE; + UngetToken(); + ParseRuleSet(aErrorCode); + } + delete mScanner; + mScanner = nsnull; + NS_IF_RELEASE(mURL); + + nsIStyleSheet* rv = nsnull; + mSheet->QueryInterface(kIStyleSheetIID, (void**)&rv); + return rv; +} + +//---------------------------------------------------------------------- + +PRBool CSSParserImpl::GetToken(PRInt32* aErrorCode, PRBool aSkipWS) +{ + for (;;) { + if (!mHavePushBack) { + if (!mScanner->Next(aErrorCode, &mToken)) { + break; + } + } + mHavePushBack = PR_FALSE; + if (aSkipWS && (eCSSToken_WhiteSpace == mToken.mType)) { + continue; + } + return PR_TRUE; + } + return PR_FALSE; +} + +void CSSParserImpl::UngetToken() +{ + NS_PRECONDITION(mHavePushBack == PR_FALSE, "double pushback"); + mHavePushBack = PR_TRUE; +} + +PRBool CSSParserImpl::ExpectSymbol(PRInt32* aErrorCode, + char aSymbol, + PRBool aSkipWS) +{ + if (!GetToken(aErrorCode, aSkipWS)) { + return PR_FALSE; + } + nsCSSToken* tk = &mToken; + if ((eCSSToken_Symbol == tk->mType) && (aSymbol == tk->mSymbol)) { + return PR_TRUE; + } + UngetToken(); + return PR_FALSE; +} + +nsString* CSSParserImpl::NextIdent(PRInt32* aErrorCode) +{ + if (!GetToken(aErrorCode, PR_TRUE)) { + return nsnull; + } + if (eCSSToken_Ident != mToken.mType) { + UngetToken(); + return nsnull; + } + return &mToken.mIdent; +} + +// XXX @media type {, types } '{' rules '}' +// XXX @font-face +// XXX @page { :left | :right } '{' declarations '}' +PRBool CSSParserImpl::ParseAtRule(PRInt32* aErrorCode) +{ + nsCSSToken* tk = &mToken; + if (mInHead && tk->mIdent.EqualsIgnoreCase("import")) { + ParseImportRule(aErrorCode); + return PR_TRUE; + } + + // Skip over unsupported at rule + for (;;) { + if (!GetToken(aErrorCode, PR_TRUE)) { + return PR_FALSE; + } + if (eCSSToken_Symbol == tk->mType) { + PRUnichar symbol = tk->mSymbol; + if (symbol == ';') { + break; + } + if (symbol == '{') { + SkipUntil(aErrorCode, '}'); + break; + } else if (symbol == '(') { + SkipUntil(aErrorCode, ')'); + } else if (symbol == '[') { + SkipUntil(aErrorCode, ']'); + } + } + } + mInHead = PR_FALSE; + return PR_TRUE; +} + +// Parse a CSS1 import rule: "@import STRING | URL" +PRBool CSSParserImpl::ParseImportRule(PRInt32* aErrorCode) +{ + nsCSSToken* tk = &mToken; + if (!GetToken(aErrorCode, PR_TRUE)) { + return PR_FALSE; + } + if ((eCSSToken_String == tk->mType) || (eCSSToken_URL == tk->mType)) { + if (ExpectSymbol(aErrorCode, ';', PR_TRUE)) { + ProcessImport(tk->mIdent); + return PR_TRUE; + } + if ((eCSSToken_Symbol != tk->mType) || (';' != tk->mSymbol)) { + SkipUntil(aErrorCode, ';'); + } + } + mInHead = PR_FALSE; + return PR_TRUE; +} + +void CSSParserImpl::ProcessImport(const nsString& aURLSpec) +{ + // XXX probably need a way to encode unicode junk for the part of + // the url that follows a "?" + char* cp = aURLSpec.ToNewCString(); + nsIURL* url; + nsresult rv = NS_NewURL(&url, mURL, cp); + delete cp; + if (NS_OK != rv) { + // import url is bad + // XXX log this somewhere for easier web page debugging + return; + } + + if (PR_FALSE == mSheet->ContainsStyleSheet(url)) { // don't allow circular references + + PRInt32 ec; + nsIInputStream* in = url->Open(&ec); + if (nsnull == in) { + // failure to make connection + // XXX log this somewhere for easier web page debugging + } + else { + + nsIUnicharInputStream* uin; + rv = NS_NewConverterStream(&uin, nsnull, in); + if (NS_OK != rv) { + // XXX no iso-latin-1 converter? out of memory? + NS_RELEASE(in); + } + else { + + NS_RELEASE(in); + + // Create a new parse to parse the import. + + if (NS_OK == rv) { + CSSParserImpl *parser = new CSSParserImpl(); + nsIStyleSheet* childSheet = parser->Parse(&ec, uin, url); + NS_RELEASE(parser); + if (nsnull != childSheet) { + nsICSSStyleSheet* cssChild = nsnull; + if (NS_OK == childSheet->QueryInterface(kICSSStyleSheetIID, (void**)&cssChild)) { + mSheet->AppendStyleSheet(cssChild); + NS_RELEASE(cssChild); + } + } + NS_RELEASE(childSheet); + } + NS_RELEASE(uin); + } + } + } + NS_RELEASE(url); +} + +void CSSParserImpl::SkipUntil(PRInt32* aErrorCode, PRUnichar aStopSymbol) +{ + nsCSSToken* tk = &mToken; + for (;;) { + if (!GetToken(aErrorCode, PR_TRUE)) { + break; + } + if (eCSSToken_Symbol == tk->mType) { + PRUnichar symbol = tk->mSymbol; + if (symbol == aStopSymbol) { + break; + } else if ('{' == symbol) { + SkipUntil(aErrorCode, '}'); + } else if ('[' == symbol) { + SkipUntil(aErrorCode, ']'); + } else if ('(' == symbol) { + SkipUntil(aErrorCode, ')'); + } + } + } +} + +void CSSParserImpl::SkipDeclaration(PRInt32* aErrorCode) +{ + nsCSSToken* tk = &mToken; + for (;;) { + if (!GetToken(aErrorCode, PR_TRUE)) { + break; + } + if (eCSSToken_Symbol == tk->mType) { + PRUnichar symbol = tk->mSymbol; + if (';' == symbol) { + break; + } + if ('}' == symbol) { + UngetToken(); + break; + } + if ('{' == symbol) { + SkipUntil(aErrorCode, '}'); + } else if ('(' == symbol) { + SkipUntil(aErrorCode, ')'); + } else if ('[' == symbol) { + SkipUntil(aErrorCode, ']'); + } + } + } +} + +void CSSParserImpl::SkipRuleSet(PRInt32* aErrorCode) +{ + nsCSSToken* tk = &mToken; + for (;;) { + if (!GetToken(aErrorCode, PR_TRUE)) { + break; + } + if (eCSSToken_Symbol == tk->mType) { + PRUnichar symbol = tk->mSymbol; + if ('{' == symbol) { + SkipUntil(aErrorCode, '}'); + break; + } + if ('(' == symbol) { + SkipUntil(aErrorCode, ')'); + } else if ('[' == symbol) { + SkipUntil(aErrorCode, ']'); + } + } + } +} + +PRBool CSSParserImpl::ParseRuleSet(PRInt32* aErrorCode) +{ + nsCSSToken* tk = &mToken; + + // First get the list of selectors for the rule + SelectorList *slist = new SelectorList(); + if (!ParseSelectorList(aErrorCode, slist)) { + SkipRuleSet(aErrorCode); + slist->Destroy(); + return PR_FALSE; + } + + // Next parse the declaration block + nsICSSDeclaration* declaration = ParseDeclarationBlock(aErrorCode); + if (nsnull == declaration) { + // XXX skip something here + slist->Destroy(); + return PR_FALSE; + } + +#if 0 + slist->Dump(); + fputs("{\n", stdout); + declaration->List(); + fputs("}\n", stdout); +#endif + + // Translate the selector list and declaration block into style data + + // XXX PSL working here + + SelectorList* list = slist; + nsCSSSelector selector; + nsICSSStyleRule* rule; + + while (nsnull != list) { + PRInt32 selIndex = list->mSelectors.Count(); + + Selector* sel = (Selector*)list->mSelectors[--selIndex]; + selector.Set(sel->mTag, sel->mID, sel->mClass, sel->mPseudo); + PRInt32 weight = sel->Weight(); + + if (NS_OK == NS_NewCSSStyleRule(&rule, selector)) { + while (--selIndex >= 0) { + Selector* sel = (Selector*)list->mSelectors[selIndex]; + selector.Set(sel->mTag, sel->mID, sel->mClass, sel->mPseudo); + + rule->AddSelector(selector); + weight += sel->Weight(); + } + rule->SetDeclaration(declaration); + rule->SetWeight(weight); +// rule->List(); + mSheet->AppendStyleRule(rule); + NS_RELEASE(rule); + } + + list = list->mNext; + } + + // XXX PSL working here + + // Release temporary storage + slist->Destroy(); + NS_RELEASE(declaration); + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseSelectorList(PRInt32* aErrorCode, + SelectorList* aListHead) +{ + if (!ParseSelectorGroup(aErrorCode, aListHead)) { + // must have at least one selector group + return PR_FALSE; + } + + // After that there must either be a "," or a "{" + nsCSSToken* tk = &mToken; + for (;;) { + if (!GetToken(aErrorCode, PR_TRUE)) { + return PR_FALSE; + } + if (eCSSToken_Symbol != tk->mType) { + UngetToken(); + return PR_FALSE; + } + if (',' == tk->mSymbol) { + // Another selector group must follow + SelectorList* newList = new SelectorList(); + if (!ParseSelectorGroup(aErrorCode, newList)) { + newList->Destroy(); + return PR_FALSE; + } + // add new list to the end of the selector list + aListHead->mNext = newList; + aListHead = newList; + continue; + } else if ('{' == tk->mSymbol) { + UngetToken(); + break; + } else { + UngetToken(); + return PR_FALSE; + } + } + + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseSelectorGroup(PRInt32* aErrorCode, + SelectorList* aList) +{ + for (;;) { + Selector* sel = new Selector(); + if (!ParseSelector(aErrorCode, sel)) { + delete sel; + break; + } + aList->AddSelector(sel); + } + return (PRBool) (aList->mSelectors.Count() > 0); +} + +/** + * These are the 15 possible kinds of CSS1 style selectors: + *

      + *
    • Tag + *
    • Tag#Id + *
    • Tag#Id.Class + *
    • Tag#Id.Class:Pseudo + *
    • Tag#Id:Pseudo + *
    • Tag.Class + *
    • Tag.Class:Pseudo + *
    • Tag:Pseudo + *
    • #Id + *
    • #Id.Class + *
    • #Id.Class:Pseudo + *
    • #Id:Pseudo + *
    • .Class + *
    • .Class:Pseudo + *
    • :Pseudo + *
    + */ +PRBool CSSParserImpl::ParseSelector(PRInt32* aErrorCode, + Selector* aSelectorResult) +{ + PRUint32 mask = 0; + aSelectorResult->mTag.SetLength(0); + aSelectorResult->mClass.SetLength(0); + aSelectorResult->mID.SetLength(0); + aSelectorResult->mPseudo.SetLength(0); + + nsCSSToken* tk = &mToken; + if (!GetToken(aErrorCode, PR_TRUE)) { + return PR_FALSE; + } + if (eCSSToken_Ident == tk->mType) { + // tag + mask |= SELECTOR_TAG; + aSelectorResult->mTag.Append(tk->mIdent); + if (!GetToken(aErrorCode, PR_FALSE)) { + // premature eof is ok (here!) + return PR_TRUE; + } + } + if (eCSSToken_ID == tk->mType) { + // #id + mask |= SELECTOR_ID; + aSelectorResult->mID.Append(tk->mIdent); + if (!GetToken(aErrorCode, PR_FALSE)) { + // premature eof is ok (here!) + return PR_TRUE; + } + } + if ((eCSSToken_Symbol == tk->mType) && ('.' == tk->mSymbol)) { + // .class + mask |= SELECTOR_CLASS; + if (!GetToken(aErrorCode, PR_FALSE)) { + return PR_FALSE; + } + if (eCSSToken_Ident != tk->mType) { + // malformed selector + UngetToken(); + return PR_FALSE; + } + aSelectorResult->mClass.Append(tk->mIdent); + if (!GetToken(aErrorCode, PR_FALSE)) { + // premature eof is ok (here!) + return PR_TRUE; + } + } + if ((eCSSToken_Symbol == tk->mType) && (':' == tk->mSymbol)) { + // :pseudo + mask |= SELECTOR_PSEUDO; + if (!GetToken(aErrorCode, PR_FALSE)) { + // premature eof + return PR_FALSE; + } + if (eCSSToken_Ident != tk->mType) { + // malformed selector + UngetToken(); + return PR_FALSE; + } + aSelectorResult->mPseudo.Append(tk->mIdent); + tk = nsnull; + } + if (nsnull != tk) { + UngetToken(); + } + if (mask == 0) { + return PR_FALSE; + } + aSelectorResult->mMask = mask; + return PR_TRUE; +} + +nsICSSDeclaration* CSSParserImpl::ParseDeclarationBlock(PRInt32* aErrorCode) +{ + if (!ExpectSymbol(aErrorCode, '{', PR_TRUE)) { + return nsnull; + } + nsICSSDeclaration* declaration = nsnull; + if (NS_OK == NS_NewCSSDeclaration(&declaration)) { + for (;;) { + if (!ParseDeclaration(aErrorCode, declaration)) { + SkipDeclaration(aErrorCode); + if (ExpectSymbol(aErrorCode, '}', PR_TRUE)) { + break; + } + // Since the skipped declaration didn't end the block we parse + // the next declaration. + } + } + } + return declaration; +} + +PRBool CSSParserImpl::ParseColor(PRInt32* aErrorCode, nscolor* aColorResult) +{ + char cbuf[50]; + + if (!GetToken(aErrorCode, PR_TRUE)) { + return PR_FALSE; + } + + nsCSSToken* tk = &mToken; + switch (tk->mType) { + case eCSSToken_ID: + // #xxyyzz + tk->mIdent.ToCString(cbuf, sizeof(cbuf)); + if (NS_HexToRGB(cbuf, aColorResult)) { + return PR_TRUE; + } + break; + + case eCSSToken_Ident: + if (!tk->mIdent.EqualsIgnoreCase("rgb")) { + // named color (maybe!) + tk->mIdent.ToCString(cbuf, sizeof(cbuf)); + if (NS_ColorNameToRGB(cbuf, aColorResult)) { + return PR_TRUE; + } + } else { + // rgb ( component , component , component ) + PRUint8 r, g, b; + if (ExpectSymbol(aErrorCode, '(', PR_TRUE) && + ParseColorComponent(aErrorCode, &r, ',') && + ParseColorComponent(aErrorCode, &g, ',') && + ParseColorComponent(aErrorCode, &b, ')')) { + *aColorResult = NS_RGB(r,g,b); + return PR_TRUE; + } + } + break; + + default: + break; + } + + // It's not a color + UngetToken(); + return PR_FALSE; +} + +PRBool CSSParserImpl::ParseColorComponent(PRInt32* aErrorCode, + PRUint8* aComponent, + char aStop) +{ + if (!GetToken(aErrorCode, PR_TRUE)) { + return PR_FALSE; + } + float value; + nsCSSToken* tk = &mToken; + switch (tk->mType) { + case eCSSToken_Number: + value = tk->mNumber; + break; + case eCSSToken_Percentage: + value = tk->mNumber * 255.0f; + break; + default: + UngetToken(); + return PR_FALSE; + } + if (ExpectSymbol(aErrorCode, aStop, PR_TRUE)) { + if (value < 0.0f) value = 0.0f; + if (value > 255.0f) value = 255.0f; + *aComponent = (PRUint8) value; + return PR_TRUE; + } + return PR_FALSE; +} + +//---------------------------------------------------------------------- + +PRBool CSSParserImpl::ParseDeclaration(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + // Get property name + nsCSSToken* tk = &mToken; + for (;;) { + if (!GetToken(aErrorCode, PR_TRUE)) { + return PR_FALSE; + } + if (eCSSToken_Ident == tk->mType) { + if (!ExpectSymbol(aErrorCode, ':', PR_TRUE)) { + return PR_FALSE; + } + break; + } + if ((eCSSToken_Symbol == tk->mType) && (';' == tk->mSymbol)) { + // dangling semicolons are skipped + continue; + } + + // Not a declaration... + UngetToken(); + return PR_FALSE; + } + + // Map property name to it's ID and then parse the property + char propertyName[100]; + tk->mIdent.ToCString(propertyName, sizeof(propertyName)); + if (!ParseProperty(aErrorCode, propertyName, aDeclaration)) { + return PR_FALSE; + } + + // Make sure valid property declaration is terminated with either a + // semicolon or a right-curly-brace. + if (!GetToken(aErrorCode, PR_TRUE)) { + // Premature eof is not ok + return PR_FALSE; + } + if (eCSSToken_Symbol == tk->mType) { + if (';' == tk->mSymbol) { + return PR_TRUE; + } + if ('}' == tk->mSymbol) { + UngetToken(); + return PR_TRUE; + } + } + return PR_FALSE; +} + +// Flags for ParseVariant method +#define VARIANT_KEYWORD 0x01 +#define VARIANT_LENGTH 0x02 +#define VARIANT_PERCENT 0x04 +#define VARIANT_COLOR 0x08 +#define VARIANT_URL 0x10 +#define VARIANT_NUMBER 0x20 +#define VARIANT_INTEGER 0x40 + +// Common combinations of variants +#define VARIANT_KL (VARIANT_KEYWORD | VARIANT_LENGTH) +#define VARIANT_KLP (VARIANT_KEYWORD | VARIANT_LENGTH | VARIANT_PERCENT) +#define VARIANT_KLPN (VARIANT_KLP | VARIANT_NUMBER) +#define VARIANT_KP (VARIANT_KEYWORD | VARIANT_PERCENT) +#define VARIANT_KI (VARIANT_KEYWORD | VARIANT_INTEGER) +#define VARIANT_LP (VARIANT_LENGTH | VARIANT_PERCENT) +#define VARIANT_CK (VARIANT_COLOR | VARIANT_KEYWORD) +#define VARIANT_C VARIANT_COLOR +#define VARIANT_UK (VARIANT_URL | VARIANT_KEYWORD) + +// Keyword id tables for variant/enum parsing +static PRInt32 kBackgroundAttachmentKTable[] = { + KEYWORD_FIXED, NS_STYLE_BG_ATTACHMENT_FIXED, + KEYWORD_SCROLL, NS_STYLE_BG_ATTACHMENT_SCROLL, + -1 +}; + +static PRInt32 kBackgroundColorKTable[] = { + KEYWORD_TRANSPARENT, NS_STYLE_BG_COLOR_TRANSPARENT, + -1 +}; + +static PRInt32 kBackgroundImageKTable[] = { + KEYWORD_NONE, NS_STYLE_BG_IMAGE_NONE, + -1 +}; + +static PRInt32 kBackgroundRepeatKTable[] = { + KEYWORD_NO_REPEAT, NS_STYLE_BG_REPEAT_OFF, + KEYWORD_REPEAT, NS_STYLE_BG_REPEAT_XY, + KEYWORD_REPEAT_X, NS_STYLE_BG_REPEAT_X, + KEYWORD_REPEAT_Y, NS_STYLE_BG_REPEAT_Y, + -1 +}; + +static PRInt32 kBorderStyleKTable[] = { + KEYWORD_NONE, NS_STYLE_BORDER_STYLE_NONE, + KEYWORD_DOTTED, NS_STYLE_BORDER_STYLE_DOTTED, + KEYWORD_DASHED, NS_STYLE_BORDER_STYLE_DASHED, + KEYWORD_SOLID, NS_STYLE_BORDER_STYLE_SOLID, + KEYWORD_DOUBLE, NS_STYLE_BORDER_STYLE_DOUBLE, + KEYWORD_GROOVE, NS_STYLE_BORDER_STYLE_GROOVE, + KEYWORD_RIDGE, NS_STYLE_BORDER_STYLE_RIDGE, + KEYWORD_INSET, NS_STYLE_BORDER_STYLE_INSET, + KEYWORD_OUTSET, NS_STYLE_BORDER_STYLE_OUTSET, + -1 +}; + +static PRInt32 kBorderWidthKTable[] = { + KEYWORD_THIN, NS_STYLE_BORDER_WIDTH_THIN, + KEYWORD_MEDIUM, NS_STYLE_BORDER_WIDTH_MEDIUM, + KEYWORD_THICK, NS_STYLE_BORDER_WIDTH_THICK, + -1 +}; + +static PRInt32 kClearKTable[] = { + KEYWORD_NONE, NS_STYLE_CLEAR_NONE, + KEYWORD_LEFT, NS_STYLE_CLEAR_LEFT, + KEYWORD_RIGHT, NS_STYLE_CLEAR_RIGHT, + KEYWORD_BOTH, NS_STYLE_CLEAR_BOTH, + -1 +}; + +static PRInt32 kClipKTable[] = { + KEYWORD_AUTO, NS_STYLE_CLIP_AUTO, + -1 +}; + +static PRInt32 kDisplayKTable[] = { + KEYWORD_NONE, NS_STYLE_DISPLAY_NONE, + KEYWORD_BLOCK, NS_STYLE_DISPLAY_BLOCK, + KEYWORD_INLINE, NS_STYLE_DISPLAY_INLINE, + KEYWORD_LIST_ITEM, NS_STYLE_DISPLAY_LIST_ITEM, + -1 +}; + +static PRInt32 kFloatKTable[] = { + KEYWORD_NONE, NS_STYLE_FLOAT_NONE, + KEYWORD_LEFT, NS_STYLE_FLOAT_LEFT, + KEYWORD_RIGHT, NS_STYLE_FLOAT_RIGHT, + -1 +}; + +static PRInt32 kFontSizeKTable[] = { + KEYWORD_XX_SMALL, NS_STYLE_FONT_SIZE_XXSMALL, + KEYWORD_X_SMALL, NS_STYLE_FONT_SIZE_XSMALL, + KEYWORD_SMALL, NS_STYLE_FONT_SIZE_SMALL, + KEYWORD_MEDIUM, NS_STYLE_FONT_SIZE_MEDIUM, + KEYWORD_LARGE, NS_STYLE_FONT_SIZE_LARGE, + KEYWORD_X_LARGE, NS_STYLE_FONT_SIZE_XLARGE, + KEYWORD_XX_LARGE, NS_STYLE_FONT_SIZE_XXLARGE, + KEYWORD_LARGER, NS_STYLE_FONT_SIZE_LARGER, + KEYWORD_SMALLER, NS_STYLE_FONT_SIZE_SMALLER, + -1 +}; + +static PRInt32 kFontStyleKTable[] = { + KEYWORD_NORMAL, NS_STYLE_FONT_STYLE_NORMAL, + KEYWORD_ITALIC, NS_STYLE_FONT_STYLE_ITALIC, + KEYWORD_OBLIQUE, NS_STYLE_FONT_STYLE_OBLIQUE, + -1 +}; + +static PRInt32 kFontVariantKTable[] = { + KEYWORD_NORMAL, NS_STYLE_FONT_VARIANT_NORMAL, + KEYWORD_SMALL_CAPS, NS_STYLE_FONT_VARIANT_SMALL_CAPS, + -1 +}; + +static PRInt32 kLeftKTable[] = { + KEYWORD_AUTO, NS_STYLE_LEFT_AUTO, + -1 +}; + +static PRInt32 kHeightKTable[] = { + KEYWORD_AUTO, NS_STYLE_HEIGHT_AUTO, + -1 +}; + +static PRInt32 kLineHeightKTable[] = { + KEYWORD_NORMAL, NS_STYLE_LINE_HEIGHT_NORMAL, + -1 +}; + +static PRInt32 kListStyleImageKTable[] = { + KEYWORD_NONE, NS_STYLE_LIST_STYLE_IMAGE_NONE, + -1 +}; + +static PRInt32 kListStylePositionKTable[] = { + KEYWORD_INSIDE, NS_STYLE_LIST_STYLE_POSITION_INSIDE, + KEYWORD_OUTSIDE, NS_STYLE_LIST_STYLE_POSITION_OUTSIDE, + -1 +}; + +static PRInt32 kListStyleKTable[] = { + KEYWORD_NONE, NS_STYLE_LIST_STYLE_NONE, + KEYWORD_DISC, NS_STYLE_LIST_STYLE_DISC, + KEYWORD_CIRCLE, NS_STYLE_LIST_STYLE_CIRCLE, + KEYWORD_SQUARE, NS_STYLE_LIST_STYLE_SQUARE, + KEYWORD_DECIMAL, NS_STYLE_LIST_STYLE_DECIMAL, + KEYWORD_LOWER_ROMAN, NS_STYLE_LIST_STYLE_LOWER_ROMAN, + KEYWORD_UPPER_ROMAN, NS_STYLE_LIST_STYLE_UPPER_ROMAN, + KEYWORD_LOWER_ALPHA, NS_STYLE_LIST_STYLE_LOWER_ALPHA, + KEYWORD_UPPER_ALPHA, NS_STYLE_LIST_STYLE_UPPER_ALPHA, + -1 +}; + +static PRInt32 kMarginSizeKTable[] = { + KEYWORD_AUTO, NS_STYLE_MARGIN_SIZE_AUTO, + -1 +}; + +static PRInt32 kSpacingKTable[] = { + KEYWORD_NORMAL, NS_STYLE_SPACING_NORMAL, + -1 +}; + +static PRInt32 kOverflowKTable[] = { + KEYWORD_VISIBLE, NS_STYLE_OVERFLOW_VISIBLE, + KEYWORD_HIDDEN, NS_STYLE_OVERFLOW_HIDDEN, + KEYWORD_SCROLL, NS_STYLE_OVERFLOW_SCROLL, + KEYWORD_AUTO, NS_STYLE_OVERFLOW_AUTO, + -1 +}; + +static PRInt32 kPositionKTable[] = { + KEYWORD_STATIC, NS_STYLE_POSITION_STATIC, + KEYWORD_RELATIVE, NS_STYLE_POSITION_RELATIVE, + KEYWORD_ABSOLUTE, NS_STYLE_POSITION_ABSOLUTE, + -1 +}; + +static PRInt32 kTextAlignKTable[] = { + KEYWORD_LEFT, NS_STYLE_TEXT_ALIGN_LEFT, + KEYWORD_RIGHT, NS_STYLE_TEXT_ALIGN_RIGHT, + KEYWORD_CENTER, NS_STYLE_TEXT_ALIGN_CENTER, + KEYWORD_JUSTIFY, NS_STYLE_TEXT_ALIGN_JUSTIFY, + -1 +}; + +static PRInt32 kTextTransformKTable[] = { + KEYWORD_NONE, NS_STYLE_TEXT_TRANSFORM_NONE, + KEYWORD_CAPITALIZE, NS_STYLE_TEXT_TRANSFORM_CAPITALIZE, + KEYWORD_LOWERCASE, NS_STYLE_TEXT_TRANSFORM_LOWERCASE, + KEYWORD_UPPERCASE, NS_STYLE_TEXT_TRANSFORM_UPPERCASE, + -1 +}; + +static PRInt32 kTopKTable[] = { + KEYWORD_AUTO, NS_STYLE_TOP_AUTO, + -1 +}; + +static PRInt32 kVerticalAlignKTable[] = { + KEYWORD_BASELINE, NS_STYLE_VERTICAL_ALIGN_BASELINE, + KEYWORD_SUB, NS_STYLE_VERTICAL_ALIGN_SUB, + KEYWORD_SUPER, NS_STYLE_VERTICAL_ALIGN_SUPER, + KEYWORD_TOP, NS_STYLE_VERTICAL_ALIGN_TOP, + KEYWORD_TEXT_TOP, NS_STYLE_VERTICAL_ALIGN_TEXT_TOP, + KEYWORD_MIDDLE, NS_STYLE_VERTICAL_ALIGN_MIDDLE, + KEYWORD_BOTTOM, NS_STYLE_VERTICAL_ALIGN_BOTTOM, + KEYWORD_TEXT_BOTTOM, NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM, + -1 +}; + +static PRInt32 kVisibilityKTable[] = { + KEYWORD_INHERIT, NS_STYLE_VISIBILITY_INHERIT, + KEYWORD_VISIBLE, NS_STYLE_VISIBILITY_VISIBLE, + KEYWORD_HIDDEN, NS_STYLE_VISIBILITY_HIDDEN, + -1 +}; + +static PRInt32 kWhitespaceKTable[] = { + KEYWORD_NORMAL, NS_STYLE_WHITESPACE_NORMAL, + KEYWORD_PRE, NS_STYLE_WHITESPACE_PRE, + KEYWORD_NOWRAP, NS_STYLE_WHITESPACE_NOWRAP, + -1 +}; + +static PRInt32 kWidthKTable[] = { + KEYWORD_AUTO, NS_STYLE_WIDTH_AUTO, + -1 +}; + +static PRInt32 kZIndexKTable[] = { + KEYWORD_AUTO, NS_STYLE_WIDTH_AUTO, + -1 +}; + +static const char* kBorderTopNames[] = { + "border-top-width", + "border-top-style", + "border-top-color", +}; +static const char* kBorderRightNames[] = { + "border-right-width", + "border-right-style", + "border-right-color", +}; +static const char* kBorderBottomNames[] = { + "border-bottom-width", + "border-bottom-style", + "border-bottom-color", +}; +static const char* kBorderLeftNames[] = { + "border-left-width", + "border-left-style", + "border-left-color", +}; + +PRInt32 CSSParserImpl::SearchKeywordTable(PRInt32 aID, PRInt32 aTable[]) +{ + PRInt32 i = 0; + for (;;) { + if (aTable[i] < 0) { + break; + } + if (aID == aTable[i]) { + return i; + } + i += 2; + } + return -1; +} + +PRBool CSSParserImpl::ParseEnum(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName, PRInt32* aTable) +{ + nsString* ident = NextIdent(aErrorCode); + if (nsnull == ident) { + return PR_FALSE; + } + char cbuf[50]; + ident->ToCString(cbuf, sizeof(cbuf)); + PRInt32 id = nsCSSKeywords::LookupName(cbuf); + if (id >= 0) { + PRInt32 ix = SearchKeywordTable(id, aTable); + if (ix >= 0) { + aDeclaration->AddValue(aName, nsCSSValue(aTable[ix+1], eCSSUnit_Enumerated)); + return PR_TRUE; + } + } + + // Put the unknown identifier back and return + UngetToken(); + return PR_FALSE; +} + +PRBool CSSParserImpl::TranslateLength(nsICSSDeclaration* aDeclaration, + const char* aName, + float aNumber, + const nsString& aDimension) +{ + nsCSSUnit units; + if (0 != aDimension.Length()) { + char cbuf[50]; + aDimension.ToCString(cbuf, sizeof(cbuf)); + PRInt32 id = nsCSSKeywords::LookupName(cbuf); + switch (id) { + case KEYWORD_EM: units = eCSSUnit_EM; break; + case KEYWORD_EX: units = eCSSUnit_XHeight; break; + case KEYWORD_PX: units = eCSSUnit_Pixel; break; + case KEYWORD_IN: units = eCSSUnit_Inch; break; + case KEYWORD_CM: units = eCSSUnit_Centimeter; break; + case KEYWORD_MM: units = eCSSUnit_Millimeter; break; + case KEYWORD_PT: units = eCSSUnit_Point; break; + case KEYWORD_PC: units = eCSSUnit_Pica; break; + default: + // unknown dimension + return PR_FALSE; + } + } else { + // Must be a zero number... + units = eCSSUnit_Point; + } + aDeclaration->AddValue(aName, nsCSSValue(aNumber, units)); + return PR_TRUE; +} + + +PRBool CSSParserImpl::ParseVariant(PRInt32* aErrorCode, + nsICSSDeclaration* aDeclaration, + const char* aName, + PRInt32 aVariants, PRInt32* aTable) +{ + nsCSSToken* tk = &mToken; + if (!GetToken(aErrorCode, PR_TRUE)) { + return PR_FALSE; + } + if (((aVariants & VARIANT_KEYWORD) != 0) && + (eCSSToken_Ident == tk->mType)) { + char cbuf[50]; + tk->mIdent.ToCString(cbuf, sizeof(cbuf)); + PRInt32 sid = nsCSSKeywords::LookupName(cbuf); + if (sid >= 0) { + PRInt32 ix = SearchKeywordTable(sid, aTable); + if (ix >= 0) { + aDeclaration->AddValue(aName, nsCSSValue(aTable[ix+1], eCSSUnit_Enumerated)); + return PR_TRUE; + } + } + } + if (((aVariants & VARIANT_LENGTH) != 0) && tk->isDimension()) { + return TranslateLength(aDeclaration, aName, tk->mNumber, tk->mIdent); + } + if (((aVariants & VARIANT_PERCENT) != 0) && + (eCSSToken_Percentage == tk->mType)) { + aDeclaration->AddValue(aName, nsCSSValue(tk->mNumber, eCSSUnit_Percent)); + return PR_TRUE; + } + if (((aVariants & VARIANT_NUMBER) != 0) && + (eCSSToken_Number == tk->mType)) { + aDeclaration->AddValue(aName, nsCSSValue(tk->mNumber, eCSSUnit_Number)); + return PR_TRUE; + } + if (((aVariants & VARIANT_INTEGER) != 0) && + (eCSSToken_Number == tk->mType) && tk->mIntegerValid) { + aDeclaration->AddValue(aName, nsCSSValue(tk->mInteger, eCSSUnit_Absolute)); + return PR_TRUE; + } + if (((aVariants & VARIANT_URL) != 0) && + (eCSSToken_URL == tk->mType)) { + aDeclaration->AddValue(aName, nsCSSValue(tk->mIdent)); + return PR_TRUE; + } + if ((aVariants & VARIANT_COLOR) != 0) { + if ((eCSSToken_ID == tk->mType) || (eCSSToken_Ident == tk->mType)) { + // Put token back so that parse color can get it + UngetToken(); + nscolor rgba; + // XXX This loses the original input format (e.g. a name which + // should be preserved when editing) + if (ParseColor(aErrorCode, &rgba)) { + aDeclaration->AddValue(aName, nsCSSValue(rgba)); + return PR_TRUE; + } + return PR_FALSE; + } + } + UngetToken(); + return PR_FALSE; +} + +PRInt32 CSSParserImpl::ParseChoice(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aNames[], PRInt32 aNumNames) +{ + PRInt32 found = 0; + for (int i = 0; i < aNumNames; i++) { + // Try each property parser in order + for (int j = 0; j < aNumNames; j++) { + PRInt32 bit = 1 << j; + if ((found & bit) == 0) { + PRInt32 id = nsCSSProps::LookupName(aNames[j]); + if (ParseProperty(aErrorCode, aNames[j], aDeclaration, id)) { + found |= bit; + } + } + } + } + return found; +} + +/** + * Parse a "box" property. Box properties have 1 to 4 values. When less + * than 4 values are provided a standard mapping is used to replicate + * existing values. Note that the replication requires renaming the + * values. + */ +PRBool CSSParserImpl::ParseBoxProperties(PRInt32* aErrorCode, + nsICSSDeclaration* aDeclaration, + const char* aNames[]) +{ + // Get up to four values for the property + PRInt32 count = 0; + for (int i = 0; i < 4; i++) { + PRInt32 id = nsCSSProps::LookupName(aNames[i]); + if (!ParseProperty(aErrorCode, aNames[i], aDeclaration, id)) { + break; + } + count++; + } + if (count == 0) { + return PR_FALSE; + } + + // Provide missing values by replicating some of the values found + nsCSSValue value; + switch (count) { + case 1: // Make right == top + aDeclaration->GetValue(aNames[0], value); + aDeclaration->AddValue(aNames[1], value); + case 2: // Make bottom == top + aDeclaration->GetValue(aNames[0], value); + aDeclaration->AddValue(aNames[2], value); + case 3: // Make left == right + aDeclaration->GetValue(aNames[1], value); + aDeclaration->AddValue(aNames[3], value); + } + + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseProperty(PRInt32* aErrorCode, + const char* aName, + nsICSSDeclaration* aDeclaration) +{ + PRInt32 id = nsCSSProps::LookupName(aName); + if (id < 0) { + return PR_FALSE; + } + + // Strip out properties we use internally. These properties are used + // by compound property parsing routines (e.g. "background-position"). + switch (id) { + case PROP_BACKGROUND_X_POSITION: + case PROP_BACKGROUND_Y_POSITION: + case PROP_BORDER_TOP_COLOR: + case PROP_BORDER_RIGHT_COLOR: + case PROP_BORDER_BOTTOM_COLOR: + case PROP_BORDER_LEFT_COLOR: + case PROP_BORDER_TOP_STYLE: + case PROP_BORDER_RIGHT_STYLE: + case PROP_BORDER_BOTTOM_STYLE: + case PROP_BORDER_LEFT_STYLE: + case PROP_CLIP_BOTTOM: + case PROP_CLIP_LEFT: + case PROP_CLIP_RIGHT: + case PROP_CLIP_TOP: + // The user can't use these + return PR_FALSE; + } + + return ParseProperty(aErrorCode, aName, aDeclaration, id); +} + +PRBool CSSParserImpl::ParseProperty(PRInt32* aErrorCode, + const char* aName, + nsICSSDeclaration* aDeclaration, + PRInt32 aID) +{ + switch (aID) { + case PROP_BACKGROUND: + return ParseBackground(aErrorCode, aDeclaration); + case PROP_BACKGROUND_ATTACHMENT: + return ParseEnum(aErrorCode, aDeclaration, aName, kBackgroundAttachmentKTable); + case PROP_BACKGROUND_COLOR: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_CK, + kBackgroundColorKTable); + case PROP_BACKGROUND_FILTER: + return ParseBackgroundFilter(aErrorCode, aDeclaration, aName); + case PROP_BACKGROUND_IMAGE: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_UK, + kBackgroundImageKTable); + case PROP_BACKGROUND_POSITION: + return ParseBackgroundPosition(aErrorCode, aDeclaration, aName); + case PROP_BACKGROUND_REPEAT: + return ParseEnum(aErrorCode, aDeclaration, aName, kBackgroundRepeatKTable); + case PROP_BORDER: + return ParseBorder(aErrorCode, aDeclaration); + case PROP_BORDER_COLOR: + return ParseBorderColor(aErrorCode, aDeclaration); + case PROP_BORDER_STYLE: + return ParseBorderStyle(aErrorCode, aDeclaration); + case PROP_BORDER_BOTTOM: + return ParseBorderSide(aErrorCode, aDeclaration, kBorderBottomNames, 0); + case PROP_BORDER_LEFT: + return ParseBorderSide(aErrorCode, aDeclaration, kBorderLeftNames, 1); + case PROP_BORDER_RIGHT: + return ParseBorderSide(aErrorCode, aDeclaration, kBorderRightNames, 2); + case PROP_BORDER_TOP: + return ParseBorderSide(aErrorCode, aDeclaration, kBorderTopNames, 3); + case PROP_BORDER_BOTTOM_COLOR: + case PROP_BORDER_LEFT_COLOR: + case PROP_BORDER_RIGHT_COLOR: + case PROP_BORDER_TOP_COLOR: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_C, nsnull); + case PROP_BORDER_BOTTOM_STYLE: + case PROP_BORDER_LEFT_STYLE: + case PROP_BORDER_RIGHT_STYLE: + case PROP_BORDER_TOP_STYLE: + return ParseEnum(aErrorCode, aDeclaration, aName, kBorderStyleKTable); + case PROP_BORDER_BOTTOM_WIDTH: + case PROP_BORDER_LEFT_WIDTH: + case PROP_BORDER_RIGHT_WIDTH: + case PROP_BORDER_TOP_WIDTH: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KL, + kBorderWidthKTable); + case PROP_BORDER_WIDTH: + return ParseBorderWidth(aErrorCode, aDeclaration); + case PROP_CLEAR: + return ParseEnum(aErrorCode, aDeclaration, aName, kClearKTable); + case PROP_CLIP: + return ParseClip(aErrorCode, aDeclaration); + case PROP_COLOR: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_COLOR, nsnull); + case PROP_DISPLAY: + return ParseEnum(aErrorCode, aDeclaration, aName, kDisplayKTable); + case PROP_FILTER: + return ParseForegroundFilter(aErrorCode, aDeclaration, aName); + case PROP_FLOAT: + return ParseEnum(aErrorCode, aDeclaration, aName, kFloatKTable); + case PROP_FONT: + return ParseFont(aErrorCode, aDeclaration, aName); + case PROP_FONT_FAMILY: + return ParseFontFamily(aErrorCode, aDeclaration, aName); + case PROP_FONT_SIZE: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KLP, + kFontSizeKTable); + case PROP_FONT_STYLE: + return ParseEnum(aErrorCode, aDeclaration, aName, kFontStyleKTable); + case PROP_FONT_VARIANT: + return ParseEnum(aErrorCode, aDeclaration, aName, kFontVariantKTable); + case PROP_FONT_WEIGHT: + return ParseFontWeight(aErrorCode, aDeclaration, aName); + case PROP_HEIGHT: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KL, kHeightKTable); + case PROP_LEFT: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KLP, kLeftKTable); + case PROP_LINE_HEIGHT: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KLPN, + kLineHeightKTable); + case PROP_LIST_STYLE: + return ParseListStyle(aErrorCode, aDeclaration); + case PROP_LIST_STYLE_IMAGE: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_UK, + kListStyleImageKTable); + case PROP_LIST_STYLE_POSITION: + return ParseEnum(aErrorCode, aDeclaration, aName, kListStylePositionKTable); + case PROP_LIST_STYLE_TYPE: + return ParseEnum(aErrorCode, aDeclaration, aName, kListStyleKTable); + case PROP_MARGIN: + return ParseMargin(aErrorCode, aDeclaration); + case PROP_MARGIN_BOTTOM: + case PROP_MARGIN_LEFT: + case PROP_MARGIN_RIGHT: + case PROP_MARGIN_TOP: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KLP, + kMarginSizeKTable); + case PROP_PADDING: + return ParsePadding(aErrorCode, aDeclaration); + case PROP_PADDING_BOTTOM: + case PROP_PADDING_LEFT: + case PROP_PADDING_RIGHT: + case PROP_PADDING_TOP: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_LP, nsnull); + case PROP_OVERFLOW: + return ParseEnum(aErrorCode, aDeclaration, aName, kOverflowKTable); + case PROP_POSITION: + return ParseEnum(aErrorCode, aDeclaration, aName, kPositionKTable); + case PROP_TEXT_ALIGN: + return ParseEnum(aErrorCode, aDeclaration, aName, kTextAlignKTable); + case PROP_TEXT_DECORATION: + return ParseTextDecoration(aErrorCode, aDeclaration, aName); + case PROP_TEXT_INDENT: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_LP, nsnull); + case PROP_TEXT_TRANSFORM: + return ParseEnum(aErrorCode, aDeclaration, aName, kTextTransformKTable); + case PROP_TOP: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KLP, kTopKTable); + case PROP_VERTICAL_ALIGN: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KP, + kVerticalAlignKTable); + case PROP_VISIBILITY: + return ParseEnum(aErrorCode, aDeclaration, aName, kVisibilityKTable); + case PROP_WHITE_SPACE: + return ParseEnum(aErrorCode, aDeclaration, aName, kWhitespaceKTable); + case PROP_WIDTH: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KLP, kWidthKTable); + case PROP_LETTER_SPACING: + case PROP_WORD_SPACING: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KL, kSpacingKTable); + case PROP_Z_INDEX: + return ParseVariant(aErrorCode, aDeclaration, aName, VARIANT_KI, kZIndexKTable); + } + return PR_FALSE; +} + +PRBool CSSParserImpl::ParseBackground(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + static const char* kBackgroundNames[] = { + "background-color", + "background-image", + "background-repeat", + "background-attachment", + "background-position", + "background-filter", + }; + + PRInt32 found = ParseChoice(aErrorCode, aDeclaration, kBackgroundNames, 6); + if (0 == found) { + return PR_FALSE; + } + + // Provide missing values + if ((found & 1) == 0) { + aDeclaration->AddValue(kBackgroundNames[0], + nsCSSValue(NS_STYLE_BG_COLOR_TRANSPARENT, + eCSSUnit_Enumerated)); + } + if ((found & 2) == 0) { + aDeclaration->AddValue(kBackgroundNames[1], + nsCSSValue(NS_STYLE_BG_IMAGE_NONE, + eCSSUnit_Enumerated)); + } + if ((found & 4) == 0) { + aDeclaration->AddValue(kBackgroundNames[2], + nsCSSValue(NS_STYLE_BG_REPEAT_XY, + eCSSUnit_Enumerated)); + } + if ((found & 8) == 0) { + aDeclaration->AddValue(kBackgroundNames[3], + nsCSSValue(NS_STYLE_BG_ATTACHMENT_SCROLL, + eCSSUnit_Enumerated)); + } + if ((found & 16) == 0) { + aDeclaration->AddValue("background-x-position", nsCSSValue(0.0f, eCSSUnit_Percent)); + aDeclaration->AddValue("background-y-position", nsCSSValue(0.0f, eCSSUnit_Percent)); + } + + // XXX Note: no default for filter (yet) + return PR_TRUE; +} + +// Bits used in determining which background position info we have +#define BG_CENTER 0 +#define BG_TOP 1 +#define BG_BOTTOM 2 +#define BG_LEFT 4 +#define BG_RIGHT 8 +#define BG_CENTER1 16 +#define BG_CENTER2 32 + +PRBool CSSParserImpl::ParseBackgroundPosition(PRInt32* aErrorCode, + nsICSSDeclaration* aDeclaration, + const char* aName) +{ + static PRInt32 kBackgroundPositionNames[] = { + PROP_BACKGROUND_X_POSITION, + PROP_BACKGROUND_Y_POSITION, + }; + + // Note: Don't change this table unless you update + // parseBackgroundPosition! + + static PRInt32 kBackgroundXYPositionKTable[] = { + KEYWORD_CENTER, BG_CENTER, + KEYWORD_TOP, BG_TOP, + KEYWORD_BOTTOM, BG_BOTTOM, + KEYWORD_LEFT, BG_LEFT, + KEYWORD_RIGHT, BG_RIGHT, + -1, + }; + + const char* bxp = "background-x-position"; + const char* byp = "background-y-position"; + + // First try a number or a length value + if (ParseVariant(aErrorCode, aDeclaration, bxp, VARIANT_LP, nsnull)) { + // We have one number/length. Get the optional second number/length. + if (ParseVariant(aErrorCode, aDeclaration, byp, VARIANT_LP, nsnull)) { + // We have two numbers + return PR_TRUE; + } + + // We have one number which is the x position. Create an value for + // the vertical position which is of value 50% + aDeclaration->AddValue(byp, nsCSSValue(0.5f, eCSSUnit_Percent)); + // XXX shouldn't this be CENTER enum instead? + return PR_TRUE; + } + + // Now try keywords. We do this manually to allow for the first + // appearance of "center" to apply to the either the x or y + // position (it's ambiguous so we have to disambiguate). Each + // allowed keyword value is assigned it's own bit. We don't allow + // any duplicate keywords other than center. We try to get two + // keywords but it's okay if there is only one. + PRInt32 mask = 0; + PRInt32 centerBit = BG_CENTER1; + for (PRInt32 i = 0; i < 2; i++) { + nsString* ident = NextIdent(aErrorCode); + if (nsnull == ident) { + break; + } + char cbuf[50]; + ident->ToCString(cbuf, sizeof(cbuf)); + PRInt32 ix = SearchKeywordTable(nsCSSKeywords::LookupName(cbuf), + kBackgroundXYPositionKTable); + if (ix >= 0) { + PRInt32 bit = kBackgroundXYPositionKTable[ix + 1]; + if (bit == 0) { + // Special hack for center bits: We can have two of them + mask |= centerBit; + centerBit <<= 1; + continue; + } else if ((mask & bit) != 0) { + // no duplicate values allowed (other than center) + return PR_FALSE; + } + mask |= bit; + } else { + UngetToken(); + break; + } + } + + // Check for bad input. Bad input consists of no matching keywords, + // or pairs of x keywords or pairs of y keywords. + if ((mask == 0) || (mask == (BG_TOP | BG_BOTTOM)) || + (mask == (BG_LEFT | BG_RIGHT))) { + return PR_FALSE; + } + + // Map good input + int xValue = 50; + if ((mask & (BG_LEFT | BG_RIGHT)) != 0) { + // We have an x value + xValue = ((mask & BG_LEFT) != 0) ? 0 : 100; + } + int yValue = 50; + if ((mask & (BG_TOP | BG_BOTTOM)) != 0) { + // We have a y value + yValue = ((mask & BG_TOP) != 0) ? 0 : 100; + } + + // Create style values + aDeclaration->AddValue(bxp, nsCSSValue(xValue, eCSSUnit_Enumerated)); + aDeclaration->AddValue(byp, nsCSSValue(yValue, eCSSUnit_Enumerated)); + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseBackgroundFilter(PRInt32* aErrorCode, + nsICSSDeclaration* aDeclaration, + const char* aName) +{ + // XXX not yet supported + return PR_FALSE; +} + +PRBool CSSParserImpl::ParseForegroundFilter(PRInt32* aErrorCode, + nsICSSDeclaration* aDeclaration, + const char* aName) +{ + // XXX not yet supported + return PR_FALSE; +} + +// These must be in alphabetical order for aWhich based indexing to work +static const char* kBorderStyleNames[] = { + "border-bottom-style", + "border-left-style", + "border-right-style", + "border-top-style", +}; +static const char* kBorderWidthNames[] = { + "border-bottom-width", + "border-left-width", + "border-right-width", + "border-top-width", +}; + + +PRBool CSSParserImpl::ParseBorder(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + static const char* kBorderNames[] = { + "border-width", + "border-style", + "border-color" + }; + PRInt32 found = ParseChoice(aErrorCode, aDeclaration, kBorderNames, 3); + if (0 == found) { + return PR_FALSE; + } + if (0 == (found & 1)) { + // provide missing border width's + for (int i = 0; i < 4; i++) { + aDeclaration->AddValue(kBorderWidthNames[i], + nsCSSValue(NS_STYLE_BORDER_WIDTH_MEDIUM, + eCSSUnit_Enumerated)); + } + } + if (0 == (found & 2)) { + // provide missing border style's + for (int i = 0; i < 4; i++) { + aDeclaration->AddValue(kBorderStyleNames[i], + nsCSSValue(NS_STYLE_BORDER_STYLE_NONE, + eCSSUnit_Enumerated)); + } + } + + // Do NOT provide a missing color value as the default is to be + // the color of the element itself which must be determined later. + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseBorderColor(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + static const char* kBoxBorderColorNames[] = { + "border-top-color", + "border-right-color", + "border-bottom-color", + "border-left-color", + }; + return ParseBoxProperties(aErrorCode, aDeclaration, kBoxBorderColorNames); +} + +PRBool CSSParserImpl::ParseBorderSide(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aNames[], PRInt32 aWhich) +{ + PRInt32 found = ParseChoice(aErrorCode, aDeclaration, aNames, 3); + if (found == 0) return PR_FALSE; + if ((found & 1) == 0) { + // Provide default border-width + aDeclaration->AddValue(kBorderWidthNames[aWhich], + nsCSSValue(NS_STYLE_BORDER_WIDTH_MEDIUM, eCSSUnit_Enumerated)); + } + if ((found & 2) == 0) { + // Provide default border-style + aDeclaration->AddValue(kBorderStyleNames[aWhich], + nsCSSValue(NS_STYLE_BORDER_STYLE_NONE, eCSSUnit_Enumerated)); + } + + // Do NOT provide a missing color value as the default is to be + // the color of the element itself which must be determined later. + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseBorderStyle(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + // in top, right, bottom, left order + static const char* kBoxBorderStyleNames[] = { + "border-top-style", + "border-right-style", + "border-bottom-style", + "border-left-style", + }; + return ParseBoxProperties(aErrorCode, aDeclaration, kBoxBorderStyleNames); +} + +PRBool CSSParserImpl::ParseBorderWidth(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + static const char* kBoxBorderWidthNames[] = { + "border-top-width", + "border-right-width", + "border-bottom-width", + "border-left-width", + }; + return ParseBoxProperties(aErrorCode, aDeclaration, kBoxBorderWidthNames); +} + +PRBool CSSParserImpl::ParseClip(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + static const char* kClipNames[] = { + "clip-top", + "clip-right", + "clip-bottom", + "clip-left", + }; + nsString* ident = NextIdent(aErrorCode); + if (nsnull == ident) { + return PR_FALSE; + } + if (ident->EqualsIgnoreCase("auto")) { + for (int i = 0; i < 4; i++) { + aDeclaration->AddValue(kClipNames[i], + nsCSSValue(NS_STYLE_CLIP_AUTO, eCSSUnit_Enumerated)); + } + return PR_TRUE; + } else if (ident->EqualsIgnoreCase("rect")) { + if (!ExpectSymbol(aErrorCode, '(', PR_TRUE)) { + return PR_FALSE; + } + for (int i = 0; i < 4; i++) { + if (!ParseVariant(aErrorCode, aDeclaration, kClipNames[i], VARIANT_KL, + kClipKTable)) { + return PR_FALSE; + } + } + if (!ExpectSymbol(aErrorCode, ')', PR_TRUE)) { + return PR_FALSE; + } + return PR_TRUE; + } else { + UngetToken(); + } + return PR_FALSE; +} + +PRBool CSSParserImpl::ParseFont(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName) +{ + static const char* fontNames[] = { + "font-style", + "font-variant", + "font-weight", + }; + + // Get optional font-style, font-variant and font-weight (in any order) + PRInt32 found = ParseChoice(aErrorCode, aDeclaration, fontNames, 3); + if ((found & 1) == 0) { + // Provide default font-style + aDeclaration->AddValue(fontNames[0], + nsCSSValue(NS_STYLE_FONT_STYLE_NORMAL, eCSSUnit_Enumerated)); + } + if ((found & 2) == 0) { + // Provide default font-variant + aDeclaration->AddValue(fontNames[1], + nsCSSValue(NS_STYLE_FONT_VARIANT_NORMAL, eCSSUnit_Enumerated)); + } + if ((found & 4) == 0) { + // Provide default font-weight + aDeclaration->AddValue(fontNames[2], + nsCSSValue(NS_STYLE_FONT_WEIGHT_NORMAL, eCSSUnit_Enumerated)); + } + + // Get mandatory font-size + if (!ParseVariant(aErrorCode, aDeclaration, "font-size", + VARIANT_KLP, kFontSizeKTable)) { + return PR_FALSE; + } + + // Get optional "/" line-height + if (ExpectSymbol(aErrorCode, '/', PR_TRUE)) { + if (!ParseVariant(aErrorCode, aDeclaration, "line-height", + VARIANT_KLPN, kLineHeightKTable)) { + return PR_FALSE; + } + } + + // Get final mandatory font-family + return ParseFontFamily(aErrorCode, aDeclaration, "font-family"); +} + +PRBool CSSParserImpl::ParseFontFamily(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName) +{ + nsCSSToken* tk = &mToken; + nsAutoString family; + PRBool firstOne = PR_TRUE; + for (;;) { + if (!GetToken(aErrorCode, PR_TRUE)) { + break; + } + if (eCSSToken_Ident == tk->mType) { + if (!firstOne) { + family.Append(PRUnichar(',')); + } + family.Append(PRUnichar('"')); + family.Append(tk->mIdent); + for (;;) { + if (!GetToken(aErrorCode, PR_FALSE)) { + break; + } + if (eCSSToken_Ident == tk->mType) { + family.Append(tk->mIdent); + } else if (eCSSToken_WhiteSpace == tk->mType) { + // Lookahead one token and drop whitespace if we ending the + // font name. + if (!GetToken(aErrorCode, PR_TRUE)) { + break; + } + if (eCSSToken_Ident != tk->mType) { + UngetToken(); + break; + } + UngetToken(); + family.Append(PRUnichar(' ')); + } else { + UngetToken(); + break; + } + } + family.Append(PRUnichar('"')); + firstOne = PR_FALSE; + } else if (eCSSToken_String == tk->mType) { + if (!firstOne) { + family.Append(PRUnichar(',')); + } + family.Append(PRUnichar('"')); + family.Append(tk->mIdent); + family.Append(PRUnichar('"')); + firstOne = PR_FALSE; + } else if (eCSSToken_Symbol == tk->mType) { + if (',' != tk->mSymbol) { + UngetToken(); + break; + } + } else { + UngetToken(); + break; + } + } + if (family.Length() == 0) { + return PR_FALSE; + } + aDeclaration->AddValue(aName, nsCSSValue(family)); + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseFontWeight(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration, + const char* aName) +{ + static PRInt32 kFontWeightKTable[] = { + KEYWORD_NORMAL, NS_STYLE_FONT_WEIGHT_NORMAL, + KEYWORD_BOLD, NS_STYLE_FONT_WEIGHT_BOLD, + KEYWORD_BOLDER, NS_STYLE_FONT_WEIGHT_BOLDER, + KEYWORD_LIGHTER, NS_STYLE_FONT_WEIGHT_LIGHTER, + -1, + }; + nsCSSToken* tk = &mToken; + if (!GetToken(aErrorCode, PR_TRUE)) { + return PR_FALSE; + } + if (eCSSToken_Ident == tk->mType) { + char cbuf[50]; + tk->mIdent.ToCString(cbuf, sizeof(cbuf)); + PRInt32 kid = nsCSSKeywords::LookupName(cbuf); + PRInt32 ix = SearchKeywordTable(kid, kFontWeightKTable); + if (ix < 0) { + UngetToken(); + return PR_FALSE; + } + aDeclaration->AddValue(aName, nsCSSValue(kFontWeightKTable[ix+1], eCSSUnit_Enumerated)); + } else if (eCSSToken_Number == tk->mType) { + PRInt32 v = (PRInt32) tk->mNumber; + if (v < 100) v = 100; + else if (v > 900) v = 900; + v = v - (v % 100); + aDeclaration->AddValue(aName, nsCSSValue(v, eCSSUnit_Absolute)); + } else { + UngetToken(); + return PR_FALSE; + } + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseListStyle(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + const char* lst = "list-style-type"; + const char* lsp = "list-style-position"; + const char* lsi = "list-style-image"; + int found = 0; + for (int i = 0; i < 3; i++) { + if (((found & 1) == 0) && + ParseEnum(aErrorCode, aDeclaration, lst, kListStyleKTable)) { + found |= 1; + continue; + } + if (((found & 2) == 0) && + ParseEnum(aErrorCode, aDeclaration, lsp, kListStylePositionKTable)) { + found |= 2; + continue; + } + if ((found & 4) == 0) { + if (!GetToken(aErrorCode, PR_TRUE)) { + break; + } + if (eCSSToken_URL == mToken.mType) { + aDeclaration->AddValue(lsi, nsCSSValue(mToken.mIdent)); + found |= 4; + continue; + } else { + if (eCSSToken_Symbol == mToken.mType) { + PRUnichar symbol = mToken.mSymbol; + if ((';' == symbol) || ('}' == symbol)) { + UngetToken(); + break; + } + } + + // We got something strange. That's an error. + UngetToken(); + return PR_FALSE; + } + } + } + if (found == 0) { + return PR_FALSE; + } + + // Provide default values + if ((found & 1) == 0) { + aDeclaration->AddValue(lst, nsCSSValue(NS_STYLE_LIST_STYLE_DISC, eCSSUnit_Enumerated)); + } + if ((found & 2) == 0) { + aDeclaration->AddValue(lsp, nsCSSValue(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE, eCSSUnit_Enumerated)); + } + if ((found & 4) == 0) { + aDeclaration->AddValue(lsi, nsCSSValue(NS_STYLE_LIST_STYLE_IMAGE_NONE, eCSSUnit_Enumerated)); + } + return PR_TRUE; +} + +PRBool CSSParserImpl::ParseMargin(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + static const char* kBoxMarginSideNames[] = { + "margin-top", + "margin-right", + "margin-bottom", + "margin-left", + }; + return ParseBoxProperties(aErrorCode, aDeclaration, kBoxMarginSideNames); +} + +PRBool CSSParserImpl::ParsePadding(PRInt32* aErrorCode, nsICSSDeclaration* aDeclaration) +{ + static const char* kBoxPaddingSideNames[] = { + "padding-top", + "padding-right", + "padding-bottom", + "padding-left", + }; + return ParseBoxProperties(aErrorCode, aDeclaration, kBoxPaddingSideNames); +} + +PRBool CSSParserImpl::ParseTextDecoration(PRInt32* aErrorCode, + nsICSSDeclaration* aDeclaration, + const char* aName) +{ + static PRInt32 kTextDecorationNoneKTable[] = { + KEYWORD_NONE, NS_STYLE_TEXT_DECORATION_NONE, + -1 + }; + static PRInt32 kTextDecorationKTable[] = { + KEYWORD_UNDERLINE, NS_STYLE_TEXT_DECORATION_UNDERLINE, + KEYWORD_OVERLINE, NS_STYLE_TEXT_DECORATION_OVERLINE, + KEYWORD_LINE_THROUGH, NS_STYLE_TEXT_DECORATION_LINE_THROUGH, + KEYWORD_BLINK, NS_STYLE_TEXT_DECORATION_BLINK, + -1, + }; + + if (ParseEnum(aErrorCode, aDeclaration, aName, kTextDecorationNoneKTable)) { + return PR_TRUE; + } + + PRInt32 decoration = 0; + for (int i = 0; i < 4; i++) { + nsString* ident = NextIdent(aErrorCode); + if (nsnull == ident) { + break; + } + char cbuf[50]; + ident->ToCString(cbuf, sizeof(cbuf)); + PRInt32 id = nsCSSKeywords::LookupName(cbuf); + PRInt32 ix = SearchKeywordTable(id, kTextDecorationKTable); + if (ix < 0) { + UngetToken(); + break; + } + decoration |= kTextDecorationKTable[ix+1]; + } + if (0 == decoration) { + return PR_FALSE; + } + aDeclaration->AddValue(aName, nsCSSValue(decoration, eCSSUnit_Absolute)); + return PR_TRUE; +} diff --git a/mozilla/layout/style/nsCSSProps.cpp b/mozilla/layout/style/nsCSSProps.cpp new file mode 100644 index 00000000000..d6de955d6a3 --- /dev/null +++ b/mozilla/layout/style/nsCSSProps.cpp @@ -0,0 +1,347 @@ + +/* +** This is a generated file, do not edit it. This file is created by +** genhash.pl +*/ + +#include "plstr.h" +#include "nsCSSProps.h" +#define TOTAL_KEYWORDS 76 +#define MIN_WORD_LENGTH 3 +#define MAX_WORD_LENGTH 21 +#define MIN_HASH_VALUE 6 +#define MAX_HASH_VALUE 212 +/* maximum key range = 207, duplicates = 0 */ + + +struct StaticNameTable { + char* tag; + PRInt32 id; +}; + +static const unsigned char kLowerLookup[256] = { + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, + 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, + 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, + 64, + 97,98,99,100,101,102,103,104,105,106,107,108,109, + 110,111,112,113,114,115,116,117,118,119,120,121,122, + + 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, + + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 +}; + +#define MYLOWER(x) kLowerLookup[((x) & 0x7f)] + +/** + * Map a name to an ID or -1 + */ +PRInt32 nsCSSProps::LookupName(const char* str) +{ + static unsigned char asso_values[] = + { + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 30, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 45, 0, 85, + 45, 25, 5, 20, 80, 0, 213, 213, 25, 75, + 0, 0, 5, 213, 0, 65, 40, 213, 0, 65, + 10, 15, 10, 213, 213, 213, 213, 213, + }; + static unsigned char lengthtable[] = + { + 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 6, 12, 8, + 0, 10, 0, 0, 0, 19, 0, 0, 0, 0, 0, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, + 0, 0, 19, 0, 0, 17, 3, 4, 0, 11, 0, 0, 0, 0, + 0, 0, 18, 0, 0, 0, 12, 0, 0, 0, 11, 17, 0, 19, + 0, 0, 17, 0, 0, 5, 21, 7, 0, 0, 0, 21, 7, 18, + 14, 0, 16, 0, 13, 0, 5, 0, 12, 0, 4, 0, 0, 12, + 8, 19, 10, 16, 17, 0, 9, 10, 16, 0, 0, 0, 0, 0, + 7, 0, 19, 5, 11, 0, 0, 4, 10, 11, 0, 0, 14, 10, + 6, 17, 0, 0, 0, 16, 0, 0, 0, 10, 0, 0, 18, 0, + 0, 0, 12, 0, 0, 0, 16, 0, 0, 0, 5, 21, 0, 0, + 0, 0, 11, 0, 0, 0, 10, 16, 0, 8, 0, 15, 0, 0, + 0, 0, 15, 11, 12, 0, 0, 0, 0, 0, 0, 14, 0, 0, + 12, 13, 9, 0, 0, 0, 0, 0, 0, 6, 0, 0, 14, 0, + 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, + 0, 11, 12, + }; + static struct StaticNameTable wordlist[] = + { + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"border", 9}, + {"",}, {"",}, {"",}, {"",}, + {"filter", 37}, + {"border-color", 14}, + {"position", 64}, + {"",}, + {"border-top", 24}, + {"",}, {"",}, {"",}, + {"border-bottom-color", 11}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"visibility", 71}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, + {"font-family", 40}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"border-bottom-style", 12}, + {"",}, {"",}, + {"border-left-color", 16}, + {"top", 69}, + {"font", 39}, + {"",}, + {"border-left", 15}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"border-right-color", 20}, + {"",}, {"",}, {"",}, + {"border-style", 23}, + {"",}, {"",}, {"",}, + {"padding-top", 63}, + {"background-filter", 3}, + {"",}, + {"background-position", 5}, + {"",}, {"",}, + {"border-left-style", 17}, + {"",}, {"",}, + {"float", 38}, + {"background-x-position", 6}, + {"padding", 59}, + {"",}, {"",}, {"",}, + {"background-y-position", 7}, + {"z-index", 75}, + {"border-right-style", 21}, + {"letter-spacing", 47}, + {"",}, + {"background-image", 4}, + {"",}, + {"border-bottom", 10}, + {"",}, + {"color", 35}, + {"",}, + {"border-right", 19}, + {"",}, + {"left", 46}, + {"",}, {"",}, + {"font-variant", 43}, + {"overflow", 58}, + {"border-bottom-width", 13}, + {"background", 0}, + {"border-top-color", 25}, + {"background-repeat", 8}, + {"",}, + {"font-size", 41}, + {"font-style", 42}, + {"border-top-style", 26}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"display", 36}, + {"",}, + {"list-style-position", 51}, + {"clear", 29}, + {"text-indent", 67}, + {"",}, {"",}, + {"clip", 30}, + {"text-align", 65}, + {"font-weight", 44}, + {"",}, {"",}, + {"vertical-align", 70}, + {"list-style", 49}, + {"margin", 53}, + {"border-left-width", 18}, + {"",}, {"",}, {"",}, + {"list-style-image", 50}, + {"",}, {"",}, {"",}, + {"margin-top", 57}, + {"",}, {"",}, + {"border-right-width", 22}, + {"",}, {"",}, {"",}, + {"padding-left", 61}, + {"",}, {"",}, {"",}, + {"background-color", 2}, + {"",}, {"",}, {"",}, + {"width", 73}, + {"background-attachment", 1}, + {"",}, {"",}, {"",}, {"",}, + {"line-height", 48}, + {"",}, {"",}, {"",}, + {"clip-right", 33}, + {"border-top-width", 27}, + {"",}, + {"clip-top", 34}, + {"",}, + {"text-decoration", 66}, + {"",}, {"",}, {"",}, {"",}, + {"list-style-type", 52}, + {"margin-left", 55}, + {"border-width", 28}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"padding-bottom", 60}, + {"",}, {"",}, + {"word-spacing", 74}, + {"padding-right", 62}, + {"clip-left", 32}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"height", 45}, + {"",}, {"",}, + {"text-transform", 68}, + {"",}, + {"clip-bottom", 31}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, + {"margin-bottom", 54}, + {"",}, {"",}, + {"white-space", 72}, + {"margin-right", 56}, + }; + + if (str != NULL) { + int len = PL_strlen(str); + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) { + register int hval = len; + + switch (hval) + { + default: + case 12: + hval += asso_values[MYLOWER(str[11])]; + case 11: + case 10: + case 9: + case 8: + case 7: + case 6: + hval += asso_values[MYLOWER(str[5])]; + case 5: + case 4: + case 3: + case 2: + hval += asso_values[MYLOWER(str[1])]; + case 1: + hval += asso_values[MYLOWER(str[0])]; + break; + } + hval += asso_values[MYLOWER(str[len - 1])]; + if (hval <= MAX_HASH_VALUE && hval >= MIN_HASH_VALUE) { + if (len == lengthtable[hval]) { + register const char *tag = wordlist[hval].tag; + + /* + ** While not at the end of the string, if they ever differ + ** they are not equal. We know "tag" is already lower case. + */ + while ((*tag != '\0')&&(*str != '\0')) { + if (*tag != (char) MYLOWER(*str)) { + return -1; + } + tag++; + str++; + } + + /* + ** One of the strings has ended, if they are both ended, then they + ** are equal, otherwise not. + */ + if ((*tag == '\0')&&(*str == '\0')) { + return wordlist[hval].id; + } + } + } + } + } + return -1; +} + +const nsCSSProps::NameTableEntry nsCSSProps::kNameTable[] = { + { "background", 0 }, + { "background-attachment", 1 }, + { "background-color", 2 }, + { "background-filter", 3 }, + { "background-image", 4 }, + { "background-position", 5 }, + { "background-x-position", 6 }, + { "background-y-position", 7 }, + { "background-repeat", 8 }, + { "border", 9 }, + { "border-bottom", 10 }, + { "border-bottom-color", 11 }, + { "border-bottom-style", 12 }, + { "border-bottom-width", 13 }, + { "border-color", 14 }, + { "border-left", 15 }, + { "border-left-color", 16 }, + { "border-left-style", 17 }, + { "border-left-width", 18 }, + { "border-right", 19 }, + { "border-right-color", 20 }, + { "border-right-style", 21 }, + { "border-right-width", 22 }, + { "border-style", 23 }, + { "border-top", 24 }, + { "border-top-color", 25 }, + { "border-top-style", 26 }, + { "border-top-width", 27 }, + { "border-width", 28 }, + { "clear", 29 }, + { "clip", 30 }, + { "clip-bottom", 31 }, + { "clip-left", 32 }, + { "clip-right", 33 }, + { "clip-top", 34 }, + { "color", 35 }, + { "display", 36 }, + { "filter", 37 }, + { "float", 38 }, + { "font", 39 }, + { "font-family", 40 }, + { "font-size", 41 }, + { "font-style", 42 }, + { "font-variant", 43 }, + { "font-weight", 44 }, + { "height", 45 }, + { "left", 46 }, + { "letter-spacing", 47 }, + { "line-height", 48 }, + { "list-style", 49 }, + { "list-style-image", 50 }, + { "list-style-position", 51 }, + { "list-style-type", 52 }, + { "margin", 53 }, + { "margin-bottom", 54 }, + { "margin-left", 55 }, + { "margin-right", 56 }, + { "margin-top", 57 }, + { "overflow", 58 }, + { "padding", 59 }, + { "padding-bottom", 60 }, + { "padding-left", 61 }, + { "padding-right", 62 }, + { "padding-top", 63 }, + { "position", 64 }, + { "text-align", 65 }, + { "text-decoration", 66 }, + { "text-indent", 67 }, + { "text-transform", 68 }, + { "top", 69 }, + { "vertical-align", 70 }, + { "visibility", 71 }, + { "white-space", 72 }, + { "width", 73 }, + { "word-spacing", 74 }, + { "z-index", 75 }, +}; diff --git a/mozilla/layout/style/nsCSSProps.h b/mozilla/layout/style/nsCSSProps.h new file mode 100644 index 00000000000..29bd8de6945 --- /dev/null +++ b/mozilla/layout/style/nsCSSProps.h @@ -0,0 +1,40 @@ +/* -*- 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. + */ +#ifndef nsCSSProps_h___ +#define nsCSSProps_h___ + +#include "nslayout.h" +#include "nsCSSPropIDs.h" + +class NS_LAYOUT nsCSSProps { +public: + // Given a null terminated string of 7 bit characters, return the + // tag id (see nsCSSPropIDs.h) for the tag or -1 if the tag is not + // known. The lookup function uses a perfect hash. + static PRInt32 LookupName(const char* str); + + struct NameTableEntry { + const char* name; + PRInt32 id; + }; + + // A table whose index is the tag id (from nsCSSPropIDs) + static const NameTableEntry kNameTable[]; +}; + +#endif /* nsCSSProps_h___ */ diff --git a/mozilla/layout/style/nsCSSScanner.cpp b/mozilla/layout/style/nsCSSScanner.cpp new file mode 100644 index 00000000000..50f64a93f29 --- /dev/null +++ b/mozilla/layout/style/nsCSSScanner.cpp @@ -0,0 +1,585 @@ +/* -*- 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 "nsCSSScanner.h" +#include "nsIInputStream.h" +#include "nsIUnicharInputStream.h" +#include "nsString.h" +#include "nsCRT.h" + +#ifdef NS_DEBUG +static char* kNullPointer = "null pointer"; +#endif + +// Don't bother collecting whitespace characters in token's mIdent buffer +#undef COLLECT_WHITESPACE + +#define BUFFER_SIZE 256 + +static const PRUnichar CSS_ESCAPE = PRUnichar('\\'); + +static const PRUint8 IS_LATIN1 = 0x01; +static const PRUint8 IS_DIGIT = 0x02; +static const PRUint8 IS_HEX_DIGIT = 0x04; +static const PRUint8 IS_ALPHA = 0x08; +static const PRUint8 START_IDENT = 0x10; +static const PRUint8 IS_IDENT = 0x20; +static const PRUint8 IS_WHITESPACE = 0x40; + +static PRUint8* gLexTable; + +static void BuildLexTable() +{ + PRUint8* lt = new PRUint8[256]; + nsCRT::zero(lt, 256); + gLexTable = lt; + + int i; + lt[CSS_ESCAPE] = START_IDENT; + lt['-'] |= IS_IDENT; + // XXX add in other whitespace chars + lt[' '] |= IS_WHITESPACE; + lt['\t'] |= IS_WHITESPACE; + lt['\r'] |= IS_WHITESPACE; + lt['\n'] |= IS_WHITESPACE; + for (i = 161; i <= 255; i++) { + lt[i] |= IS_LATIN1 | IS_IDENT | START_IDENT; + } + for (i = '0'; i <= '9'; i++) { + lt[i] |= IS_DIGIT | IS_HEX_DIGIT | IS_IDENT; + } + for (i = 'A'; i <= 'Z'; i++) { + if ((i >= 'A') && (i <= 'F')) { + lt[i] |= IS_HEX_DIGIT; + lt[i+32] |= IS_HEX_DIGIT; + } + lt[i] |= IS_ALPHA | IS_IDENT | START_IDENT; + lt[i+32] |= IS_ALPHA | IS_IDENT | START_IDENT; + } +} + +nsCSSToken::nsCSSToken() +{ + mType = eCSSToken_Symbol; +} + +nsCSSScanner::nsCSSScanner() +{ + if (nsnull == gLexTable) { + // XXX need a monitor + BuildLexTable(); + } + mInput = nsnull; + mBuffer = new PRUnichar[BUFFER_SIZE]; + mOffset = 0; + mCount = 0; + mLookAhead = -1; +} + +nsCSSScanner::~nsCSSScanner() +{ + Close(); + if (nsnull != mBuffer) { + delete mBuffer; + mBuffer = nsnull; + } +} + +void nsCSSScanner::Init(nsIUnicharInputStream* aInput) +{ + NS_PRECONDITION(nsnull != aInput, kNullPointer); + Close(); + mInput = aInput; + if (nsnull != aInput) { + aInput->AddRef(); + } +} + +void nsCSSScanner::Close() +{ + NS_IF_RELEASE(mInput); +} + +// Returns -1 on error or eof +PRInt32 nsCSSScanner::Read(PRInt32* aErrorCode) +{ + PRInt32 rv; + if (mLookAhead >= 0) { + rv = mLookAhead; + mLookAhead = -1; + } else { + if (mCount < 0) { + return -1; + } + if (mOffset == mCount) { + mOffset = 0; + mCount = mInput->Read(aErrorCode, mBuffer, 0, BUFFER_SIZE); + if (mCount <= 0) { + return -1; + } + } + rv = PRInt32(mBuffer[mOffset++]); + } + mLastRead = rv; +//printf("Read => %x\n", rv); + return rv; +} + +PRInt32 nsCSSScanner::Peek(PRInt32* aErrorCode) +{ + if (mLookAhead < 0) { + mLookAhead = Read(aErrorCode); + if (mLookAhead < 0) { + return -1; + } + } +//printf("Peek => %x\n", mLookAhead); + return mLookAhead; +} + +void nsCSSScanner::Unread() +{ + NS_PRECONDITION((mLastRead >= 0) && (mLookAhead < 0), "double pushback"); + mLookAhead = mLastRead; + mLastRead = -1; +} + +PRBool nsCSSScanner::LookAhead(PRInt32* aErrorCode, PRUnichar aChar) +{ + PRInt32 ch = Read(aErrorCode); + if (ch < 0) { + return PR_FALSE; + } + if (ch == aChar) { + return PR_TRUE; + } + Unread(); + return PR_FALSE; +} + +PRBool nsCSSScanner::EatWhiteSpace(PRInt32* aErrorCode) +{ + PRBool eaten = PR_FALSE; + for (;;) { + PRInt32 ch = Read(aErrorCode); + if (ch < 0) { + break; + } + if ((ch == ' ') || (ch == '\n') || (ch == '\r') || (ch == '\t')) { + eaten = PR_TRUE; + continue; + } + Unread(); + break; + } + return eaten; +} + +PRBool nsCSSScanner::EatNewline(PRInt32* aErrorCode) +{ + PRInt32 ch = Read(aErrorCode); + if (ch < 0) { + return PR_FALSE; + } + PRBool eaten = PR_FALSE; + if (ch == '\r') { + eaten = PR_TRUE; + ch = Peek(aErrorCode); + if (ch == '\n') { + (void) Read(aErrorCode); + } + } else if (ch == '\n') { + eaten = PR_TRUE; + } else { + Unread(); + } + return eaten; +} + +PRBool nsCSSScanner::Next(PRInt32* aErrorCode, nsCSSToken* aToken) +{ + PRInt32 ch = Read(aErrorCode); + if (ch < 0) { + return PR_FALSE; + } + if (ch < 256) { + PRUint8* lexTable = gLexTable; + + // IDENT + if ((lexTable[ch] & START_IDENT) != 0) { + return ParseIdent(aErrorCode, ch, aToken); + } + + // AT_KEYWORD + if (ch == '@') { + PRInt32 nextChar = Peek(aErrorCode); + if ((nextChar >= 0) && (nextChar <= 255)) { + if ((lexTable[nextChar] & START_IDENT) != 0) { + return ParseAtKeyword(aErrorCode, ch, aToken); + } + } + } + + // NUMBER or DIM + if ((ch == '.') || (ch == '+') || (ch == '-')) { + PRInt32 nextChar = Peek(aErrorCode); + if ((nextChar >= 0) && (nextChar <= 255)) { + if ((lexTable[nextChar] & IS_DIGIT) != 0) { + return ParseNumber(aErrorCode, ch, aToken); + } + } + } + if ((lexTable[ch] & IS_DIGIT) != 0) { + return ParseNumber(aErrorCode, ch, aToken); + } + + // ID + if (ch == '#') { + return ParseID(aErrorCode, ch, aToken); + } + + // STRING + if ((ch == '"') || (ch == '\'')) { + return ParseString(aErrorCode, ch, aToken); + } + + // WS + if ((lexTable[ch] & IS_WHITESPACE) != 0) { + aToken->mType = eCSSToken_WhiteSpace; + aToken->mIdent.SetLength(0); + aToken->mIdent.Append(PRUnichar(ch)); + (void) EatWhiteSpace(aErrorCode); + return PR_TRUE; + } + if (ch == '/') { + PRInt32 nextChar = Peek(aErrorCode); + if (nextChar == '/') { + (void) Read(aErrorCode); + aToken->mIdent.SetLength(0); + aToken->mIdent.Append(PRUnichar(ch)); + aToken->mIdent.Append(PRUnichar(ch)); + return ParseEOLComment(aErrorCode, aToken); + } else if (nextChar == '*') { + (void) Read(aErrorCode); + aToken->mIdent.SetLength(0); + aToken->mIdent.Append(PRUnichar(ch)); + aToken->mIdent.Append(PRUnichar(nextChar)); + return ParseCComment(aErrorCode, aToken); + } + } + } + aToken->mType = eCSSToken_Symbol; + aToken->mSymbol = ch; + return PR_TRUE; +} + +PRInt32 nsCSSScanner::ParseEscape(PRInt32* aErrorCode) +{ + PRUint8* lexTable = gLexTable; + PRInt32 ch = Peek(aErrorCode); + if (ch < 0) { + return CSS_ESCAPE; + } + if ((ch <= 255) && ((lexTable[ch] & IS_HEX_DIGIT) != 0)) { + PRInt32 rv = 0; + for (int i = 0; i < 4; i++) { + ch = Read(aErrorCode); + if (ch < 0) { + // Whoops: error or premature eof + break; + } + if ((lexTable[ch] & IS_HEX_DIGIT) != 0) { + if ((lexTable[ch] & IS_DIGIT) != 0) { + rv = rv * 16 + (ch - '0'); + } else { + // Note: c&7 just keeps the low three bits which causes + // upper and lower case alphabetics to both yield their + // "relative to 10" value for computing the hex value. + rv = rv * 16 + (ch & 0x7) + 10; + } + } else { + Unread(); + break; + } + } + return rv; + } else { + // "Any character except a hexidecimal digit can be escaped to + // remove its special meaning by putting a backslash in front" + // -- CSS1 spec section 7.1 + (void) Read(aErrorCode); + return ch; + } +} + +/** + * Gather up the characters in an identifier. The identfier was + * started by "aChar" which will be appended to aIdent. The result + * will be aIdent with all of the identifier characters appended + * until the first non-identifier character is seen. The termination + * character is unread for the future re-reading. + */ +PRBool nsCSSScanner::GatherIdent(PRInt32* aErrorCode, PRInt32 aChar, + nsString& aIdent) +{ + if (aChar == CSS_ESCAPE) { + aChar = ParseEscape(aErrorCode); + } + for (;;) { + aChar = Read(aErrorCode); + if (aChar < 0) break; + if (aChar == CSS_ESCAPE) { + aChar = ParseEscape(aErrorCode); + aIdent.Append(PRUnichar(aChar)); + } else if ((aChar <= 255) && ((gLexTable[aChar] & IS_IDENT) != 0)) { + aIdent.Append(PRUnichar(aChar)); + } else { + Unread(); + break; + } + } + return PR_TRUE; +} + +PRBool nsCSSScanner::ParseID(PRInt32* aErrorCode, + PRInt32 aChar, + nsCSSToken* aToken) +{ + aToken->mIdent.SetLength(0); + aToken->mType = eCSSToken_ID; + return GatherIdent(aErrorCode, aChar, aToken->mIdent); +} + +PRBool nsCSSScanner::ParseIdent(PRInt32* aErrorCode, + PRInt32 aChar, + nsCSSToken* aToken) +{ + nsString& ident = aToken->mIdent; + ident.SetLength(0); + ident.Append(PRUnichar(aChar)); + if (!GatherIdent(aErrorCode, aChar, ident)) { + return PR_FALSE; + } + + // Process a url lexical token. A CSS1 url token can contain + // characters beyond identifier characters (e.g. '/', ':', etc.) + // Because of this the normal rules for tokenizing the input don't + // apply very well. To simplify the parser and relax some of the + // requirements on the scanner we parse url's here. If we find a + // malformed URL then we emit a token of type "InvalidURL" so that + // the CSS1 parser can ignore the invalid input. We attempt to eat + // the right amount of input data when an invalid URL is presented. + nsCSSTokenType tokenType = eCSSToken_Ident; + if (ident.EqualsIgnoreCase("url")) { + tokenType = eCSSToken_InvalidURL; + if (LookAhead(aErrorCode, '(')) { + // Skip leading whitespace + (void) EatWhiteSpace(aErrorCode); + ident.SetLength(0); + + PRInt32 c = Read(aErrorCode); + if (c == ')') { + // empty url spec: this is invalid + } else if ((c == '"') || (c == '\'')) { + // start of a quoted url + if (!GatherString(aErrorCode, c, ident)) { + return PR_FALSE; + } + if (!EatWhiteSpace(aErrorCode)) { + return PR_FALSE; + } + if (LookAhead(aErrorCode, ')')) { + tokenType = eCSSToken_URL; + } + } else { + // start of a non-quoted url + Unread(); + PRBool ok = PR_TRUE; + for (;;) { + c = Read(aErrorCode); + if (c < 0) break; + if (c == CSS_ESCAPE) { + c = ParseEscape(aErrorCode); + ident.Append(PRUnichar(c)); + } else if ((c == '"') || (c == '\'') || (c == '(')) { + // This is an invalid URL spec + ok = PR_FALSE; + } else if ((256 >= c) && ((gLexTable[c] & IS_WHITESPACE) != 0)) { + // Whitespace is allowed at the end of the URL + (void) EatWhiteSpace(aErrorCode); + if (LookAhead(aErrorCode, ')')) { + // done! + break; + } + // Whitespace is followed by something other than a + // ")". This is an invalid url spec. + ok = PR_FALSE; + } else if (c == ')') { + // All done + break; + } else { + // A regular url character. + ident.Append(PRUnichar(c)); + } + } + + // If the result of the above scanning is ok then change the token + // type to a useful one. + if (ok) { + tokenType = eCSSToken_URL; + } + } + } + } + aToken->mType = tokenType; + return PR_TRUE; +} + +PRBool nsCSSScanner::ParseAtKeyword(PRInt32* aErrorCode, PRInt32 aChar, + nsCSSToken* aToken) +{ + aToken->mIdent.SetLength(0); + aToken->mType = eCSSToken_AtKeyword; + return GatherIdent(aErrorCode, aChar, aToken->mIdent); +} + +PRBool nsCSSScanner::ParseNumber(PRInt32* aErrorCode, PRInt32 c, + nsCSSToken* aToken) +{ + nsString& ident = aToken->mIdent; + ident.SetLength(0); + PRBool gotDot = (c == '.') ? PR_TRUE : PR_FALSE; + if (c != '+') { + ident.Append(PRUnichar(c)); + } + + // Gather up characters that make up the number + PRUint8* lexTable = gLexTable; + for (;;) { + c = Read(aErrorCode); + if (c < 0) break; + if (!gotDot && (c == '.')) { + gotDot = PR_TRUE; + } else if ((c > 255) || ((lexTable[c] & IS_DIGIT) == 0)) { + break; + } + ident.Append(PRUnichar(c)); + } + + // Convert number to floating point + nsCSSTokenType type = eCSSToken_Number; + PRInt32 ec; + float value = ident.ToFloat(&ec); + + // Look at character that terminated the number + aToken->mIntegerValid = PR_FALSE; + if (c >= 0) { + if ((c <= 255) && ((lexTable[c] & START_IDENT) != 0)) { + ident.SetLength(0); + ident.Append(PRUnichar(c)); + if (!GatherIdent(aErrorCode, c, ident)) { + return PR_FALSE; + } + type = eCSSToken_Dimension; + } else if ('%' == c) { + type = eCSSToken_Percentage; + value = value / 100.0f; + } else { + // Put back character that stopped numeric scan + Unread(); + if (!gotDot) { + aToken->mInteger = ident.ToInteger(&ec); + aToken->mIntegerValid = PR_TRUE; + } + ident.SetLength(0); + } + } + aToken->mNumber = value; + aToken->mType = type; + return PR_TRUE; +} + +PRBool nsCSSScanner::ParseCComment(PRInt32* aErrorCode, nsCSSToken* aToken) +{ + nsString& ident = aToken->mIdent; + for (;;) { + PRInt32 ch = Read(aErrorCode); + if (ch < 0) break; + if (ch == '*') { + if (LookAhead(aErrorCode, '/')) { + ident.Append(PRUnichar(ch)); + ident.Append('/'); + break; + } + } +#ifdef COLLECT_WHITESPACE + ident.Append(PRUnichar(ch)); +#endif + } + aToken->mType = eCSSToken_WhiteSpace; + return PR_TRUE; +} + +PRBool nsCSSScanner::ParseEOLComment(PRInt32* aErrorCode, nsCSSToken* aToken) +{ + nsString& ident = aToken->mIdent; + ident.SetLength(0); + for (;;) { + if (EatNewline(aErrorCode)) { + break; + } + PRInt32 ch = Read(aErrorCode); + if (ch < 0) { + break; + } +#ifdef COLLECT_WHITESPACE + ident.Append(PRUnichar(ch)); +#endif + } + aToken->mType = eCSSToken_WhiteSpace; + return PR_TRUE; +} + +PRBool nsCSSScanner::GatherString(PRInt32* aErrorCode, PRInt32 aStop, + nsString& aBuffer) +{ + for (;;) { + PRInt32 ch = Read(aErrorCode); + if (ch < 0) { + return PR_FALSE; + } + if (ch == aStop) { + break; + } + if (ch == CSS_ESCAPE) { + ch = ParseEscape(aErrorCode); + if (ch < 0) { + return PR_FALSE; + } + } + aBuffer.Append(PRUnichar(ch)); + } + return PR_TRUE; +} + +PRBool nsCSSScanner::ParseString(PRInt32* aErrorCode, PRInt32 aStop, + nsCSSToken* aToken) +{ + aToken->mIdent.SetLength(0); + aToken->mType = eCSSToken_String; + return GatherString(aErrorCode, aStop, aToken->mIdent); +} diff --git a/mozilla/layout/style/nsCSSScanner.h b/mozilla/layout/style/nsCSSScanner.h new file mode 100644 index 00000000000..afbe1da67fd --- /dev/null +++ b/mozilla/layout/style/nsCSSScanner.h @@ -0,0 +1,118 @@ +/* -*- 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. + */ +#ifndef nsCSSScanner_h___ +#define nsCSSScanner_h___ + +#include "nsString.h" +class nsIUnicharInputStream; + +// Token types +enum nsCSSTokenType { + // A css identifier (e.g. foo) + eCSSToken_Ident = 0, + + // A css at keyword (e.g. @foo) + eCSSToken_AtKeyword = 1, + + // A css number without a percentage or dimension; with percentage; + // without percentage but with a dimension + eCSSToken_Number = 2, + eCSSToken_Percentage = 3, + eCSSToken_Dimension = 4, + + // A css string (e.g. "foo" or 'foo') + eCSSToken_String = 5, + + // Whitespace (e.g. " " or "/* abc */" or "// foo ") + eCSSToken_WhiteSpace = 6, + + // A css symbol (e.g. ':', ';', '+', etc.) + eCSSToken_Symbol = 7, + + eCSSToken_URL = 8, // use getString + eCSSToken_InvalidURL = 9, // doesn't matter + + // A css1 id (e.g. #foo3) + eCSSToken_ID = 10, // use getString() +}; + +struct nsCSSToken { + nsCSSTokenType mType; + nsAutoString mIdent; + float mNumber; + PRInt32 mInteger; + PRUnichar mSymbol; + PRBool mIntegerValid; + + nsCSSToken(); + + PRBool isDimension() { + return (PRBool) + ((eCSSToken_Dimension == mType) || + ((eCSSToken_Number == mType) && (mNumber == 0.0f))); + } +}; + +// CSS Scanner API. Used to tokenize an input stream using the CSS +// forward compatible tokenization rules. This implementation is +// private to this package and is only used internally by the css +// parser. +class nsCSSScanner { + public: + nsCSSScanner(); + ~nsCSSScanner(); + + // Init the scanner. + void Init(nsIUnicharInputStream* aInput); + + // Get the next token. Return nsfalse on EOF or ERROR. aTokenResult + // is filled in with the data for the token. + PRBool Next(PRInt32* aErrorCode, nsCSSToken* aTokenResult); + +protected: + void Close(); + PRInt32 Read(PRInt32* aErrorCode); + PRInt32 Peek(PRInt32* aErrorCode); + void Unread(); + PRBool LookAhead(PRInt32* aErrorCode, PRUnichar aChar); + PRBool EatWhiteSpace(PRInt32* aErrorCode); + PRBool EatNewline(PRInt32* aErrorCode); + + PRInt32 ParseEscape(PRInt32* aErrorCode); + PRBool ParseIdent(PRInt32* aErrorCode, PRInt32 aChar, nsCSSToken* aResult); + PRBool ParseAtKeyword(PRInt32* aErrorCode, PRInt32 aChar, + nsCSSToken* aResult); + PRBool ParseNumber(PRInt32* aErrorCode, PRInt32 aChar, nsCSSToken* aResult); + PRBool ParseID(PRInt32* aErrorCode, PRInt32 aChar, nsCSSToken* aResult); + PRBool ParseString(PRInt32* aErrorCode, PRInt32 aChar, nsCSSToken* aResult); + PRBool ParseEOLComment(PRInt32* aErrorCode, nsCSSToken* aResult); + PRBool ParseCComment(PRInt32* aErrorCode, nsCSSToken* aResult); + + PRBool GatherString(PRInt32* aErrorCode, PRInt32 aStop, + nsString& aString); + PRBool GatherIdent(PRInt32* aErrorCode, PRInt32 aChar, nsString& aIdent); + + nsIUnicharInputStream* mInput; + PRUnichar* mBuffer; + PRInt32 mOffset; + PRInt32 mCount; + PRInt32 mLookAhead; + PRInt32 mLastRead; +}; + +#endif /* nsCSSScanner_h___ */ diff --git a/mozilla/layout/style/nsCSSStruct.cpp b/mozilla/layout/style/nsCSSStruct.cpp new file mode 100644 index 00000000000..2f9d7ac6155 --- /dev/null +++ b/mozilla/layout/style/nsCSSStruct.cpp @@ -0,0 +1,1350 @@ +/* -*- 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 "nsICSSDeclaration.h" +#include "nsString.h" +#include "nsCRT.h" +#include "nsCSSProps.h" +#include "nsCSSPropIDs.h" +#include "nsUnitConversion.h" + +static NS_DEFINE_IID(kCSSFontSID, NS_CSS_FONT_SID); +static NS_DEFINE_IID(kCSSColorSID, NS_CSS_COLOR_SID); +static NS_DEFINE_IID(kCSSTextSID, NS_CSS_TEXT_SID); +static NS_DEFINE_IID(kCSSMarginSID, NS_CSS_MARGIN_SID); +static NS_DEFINE_IID(kCSSPositionSID, NS_CSS_POSITION_SID); +static NS_DEFINE_IID(kCSSListSID, NS_CSS_LIST_SID); +static NS_DEFINE_IID(kICSSDeclarationIID, NS_ICSS_DECLARATION_IID); + + +nsCSSValue::nsCSSValue(void) + : mUnit(eCSSUnit_Null) +{ + mValue.mInt = 0; +} + +nsCSSValue::nsCSSValue(PRInt32 aValue, nsCSSUnit aUnit) + : mUnit(aUnit) +{ + mValue.mInt = aValue; +} + +nsCSSValue::nsCSSValue(float aValue, nsCSSUnit aUnit) + : mUnit(aUnit) +{ + mValue.mFloat = aValue; +} + +nsCSSValue::nsCSSValue(const nsString& aValue) + : mUnit(eCSSUnit_String) +{ + mValue.mString = aValue.ToNewString(); +} + +nsCSSValue::nsCSSValue(nscolor aValue) + : mUnit(eCSSUnit_Color) +{ + mValue.mColor = aValue; +} + +nsCSSValue::nsCSSValue(const nsCSSValue& aCopy) + : mUnit(aCopy.mUnit) +{ + if (eCSSUnit_String == mUnit) { + if (nsnull != aCopy.mValue.mString) { + mValue.mString = (aCopy.mValue.mString)->ToNewString(); + } + else { + mValue.mString = nsnull; + } + } + else if ((eCSSUnit_Absolute <= mUnit) && (mUnit <= eCSSUnit_Enumerated)) { + mValue.mInt = aCopy.mValue.mInt; + } + else if (eCSSUnit_Color == mUnit){ + mValue.mColor = aCopy.mValue.mColor; + } + else { + mValue.mFloat = aCopy.mValue.mFloat; + } +} + +nsCSSValue::~nsCSSValue(void) +{ + Reset(); +} + +nsCSSValue& nsCSSValue::operator=(const nsCSSValue& aCopy) +{ + Reset(); + mUnit = aCopy.mUnit; + if (eCSSUnit_String == mUnit) { + if (nsnull != aCopy.mValue.mString) { + mValue.mString = (aCopy.mValue.mString)->ToNewString(); + } + } + else if ((eCSSUnit_Absolute <= mUnit) && (mUnit <= eCSSUnit_Enumerated)) { + mValue.mInt = aCopy.mValue.mInt; + } + else if (eCSSUnit_Color == mUnit){ + mValue.mColor = aCopy.mValue.mColor; + } + else { + mValue.mFloat = aCopy.mValue.mFloat; + } + return *this; +} + +PRBool nsCSSValue::operator==(const nsCSSValue& aOther) const +{ + if (mUnit == aOther.mUnit) { + if (eCSSUnit_String == mUnit) { + if (nsnull == mValue.mString) { + if (nsnull == aOther.mValue.mString) { + return PR_TRUE; + } + } + else if (nsnull != aOther.mValue.mString) { + return mValue.mString->Equals(*(aOther.mValue.mString)); + } + } + else if ((eCSSUnit_Absolute <= mUnit) && (mUnit < eCSSUnit_Percent)) { + return PRBool(mValue.mInt == aOther.mValue.mInt); + } + else if (eCSSUnit_Color == mUnit){ + return PRBool(mValue.mColor == aOther.mValue.mColor); + } + else { + return PRBool(mValue.mFloat == aOther.mValue.mFloat); + } + } + return PR_FALSE; +} + +nscoord nsCSSValue::GetLengthTwips(void) const +{ + NS_ASSERTION(IsFixedLengthUnit(), "not a fixed length unit"); + + if (IsFixedLengthUnit()) { + switch (mUnit) { + case eCSSUnit_Inch: + return (nscoord)NS_INCHES_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Foot: + return (nscoord)NS_FEET_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Mile: + return (nscoord)NS_MILES_TO_TWIPS(mValue.mFloat); + + case eCSSUnit_Millimeter: + return (nscoord)NS_MILLIMETERS_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Centimeter: + return (nscoord)NS_CENTIMETERS_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Meter: + return (nscoord)NS_METERS_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Kilometer: + return (nscoord)NS_KILOMETERS_TO_TWIPS(mValue.mFloat); + + case eCSSUnit_Point: + return (nscoord)NS_POINTS_TO_TWIPS_FLOAT(mValue.mFloat); + case eCSSUnit_Pica: + return (nscoord)NS_PICAS_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Didot: + return (nscoord)NS_DIDOTS_TO_TWIPS(mValue.mFloat); + case eCSSUnit_Cicero: + return (nscoord)NS_CICEROS_TO_TWIPS(mValue.mFloat); + } + } + return 0; +} + +void nsCSSValue::Reset(void) +{ + if ((eCSSUnit_String == mUnit) && (nsnull != mValue.mString)) { + delete mValue.mString; + } + mUnit = eCSSUnit_Null; + mValue.mInt = 0; +}; + +void nsCSSValue::Set(PRInt32 aValue, nsCSSUnit aUnit) +{ + Reset(); + mUnit = aUnit; + mValue.mInt = aValue; +} + +void nsCSSValue::Set(float aValue, nsCSSUnit aUnit) +{ + Reset(); + mUnit = aUnit; + mValue.mFloat = aValue; +} + +void nsCSSValue::Set(const nsString& aValue) +{ + Reset(); + mUnit = eCSSUnit_String; + mValue.mString = aValue.ToNewString(); +} + +void nsCSSValue::Set(nscolor aValue) +{ + Reset(); + mUnit = eCSSUnit_Color; + mValue.mColor = aValue; +} + +void nsCSSValue::AppendToString(nsString& aBuffer, PRInt32 aPropID) const +{ + if (eCSSUnit_Null == mUnit) { + return; + } + + if (-1 < aPropID) { + aBuffer.Append(nsCSSProps::kNameTable[aPropID].name); + aBuffer.Append(": "); + } + + if (eCSSUnit_String == mUnit) { + if (nsnull != mValue.mString) { + aBuffer.Append('"'); + aBuffer.Append(*(mValue.mString)); + aBuffer.Append('"'); + } + else { + aBuffer.Append("null str"); + } + } + else if ((eCSSUnit_Absolute <= mUnit) && (mUnit <= eCSSUnit_Enumerated)) { + aBuffer.Append(mValue.mInt, 10); + aBuffer.Append("[0x"); + aBuffer.Append(mValue.mInt, 16); + aBuffer.Append(']'); + } + else if (eCSSUnit_Color == mUnit){ + aBuffer.Append("(0x"); + aBuffer.Append(NS_GET_R(mValue.mColor), 16); + aBuffer.Append(" 0x"); + aBuffer.Append(NS_GET_G(mValue.mColor), 16); + aBuffer.Append(" 0x"); + aBuffer.Append(NS_GET_B(mValue.mColor), 16); + aBuffer.Append(" 0x"); + aBuffer.Append(NS_GET_A(mValue.mColor), 16); + aBuffer.Append(')'); + } + else if (eCSSUnit_Percent <= mUnit) { + aBuffer.Append(mValue.mFloat); + } + + switch (mUnit) { + case eCSSUnit_Null: break; + case eCSSUnit_Auto: aBuffer.Append("auto"); break; + case eCSSUnit_String: break; + case eCSSUnit_Absolute: aBuffer.Append("abs"); break; + case eCSSUnit_Enumerated: aBuffer.Append("enum"); break; + case eCSSUnit_Color: aBuffer.Append("rbga"); break; + case eCSSUnit_Percent: aBuffer.Append("%"); break; + case eCSSUnit_Number: aBuffer.Append("#"); break; + case eCSSUnit_Inch: aBuffer.Append("in"); break; + case eCSSUnit_Foot: aBuffer.Append("ft"); break; + case eCSSUnit_Mile: aBuffer.Append("mi"); break; + case eCSSUnit_Millimeter: aBuffer.Append("mm"); break; + case eCSSUnit_Centimeter: aBuffer.Append("cm"); break; + case eCSSUnit_Meter: aBuffer.Append("m"); break; + case eCSSUnit_Kilometer: aBuffer.Append("km"); break; + case eCSSUnit_Point: aBuffer.Append("pt"); break; + case eCSSUnit_Pica: aBuffer.Append("pc"); break; + case eCSSUnit_Didot: aBuffer.Append("dt"); break; + case eCSSUnit_Cicero: aBuffer.Append("cc"); break; + case eCSSUnit_EM: aBuffer.Append("em"); break; + case eCSSUnit_EN: aBuffer.Append("en"); break; + case eCSSUnit_XHeight: aBuffer.Append("ex"); break; + case eCSSUnit_CapHeight: aBuffer.Append("cap"); break; + case eCSSUnit_Pixel: aBuffer.Append("px"); break; + } + aBuffer.Append(' '); +} + +void nsCSSValue::ToString(nsString& aBuffer, PRInt32 aPropID) const +{ + aBuffer.SetLength(0); + AppendToString(aBuffer, aPropID); +} + +const nsID& nsCSSFont::GetID(void) +{ + return kCSSFontSID; +} + +void nsCSSFont::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + nsAutoString buffer; + + mFamily.AppendToString(buffer, PROP_FONT_FAMILY); + mStyle.AppendToString(buffer, PROP_FONT_STYLE); + mVariant.AppendToString(buffer, PROP_FONT_VARIANT); + mWeight.AppendToString(buffer, PROP_FONT_WEIGHT); + mSize.AppendToString(buffer, PROP_FONT_SIZE); + fputs(buffer, out); +} + + +const nsID& nsCSSColor::GetID(void) +{ + return kCSSColorSID; +} + +void nsCSSColor::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + nsAutoString buffer; + + mColor.AppendToString(buffer, PROP_COLOR); + mBackColor.AppendToString(buffer, PROP_BACKGROUND_COLOR); + mBackImage.AppendToString(buffer, PROP_BACKGROUND_IMAGE); + mBackRepeat.AppendToString(buffer, PROP_BACKGROUND_REPEAT); + mBackAttachment.AppendToString(buffer, PROP_BACKGROUND_ATTACHMENT); + mBackPositionX.AppendToString(buffer, PROP_BACKGROUND_X_POSITION); + mBackPositionY.AppendToString(buffer, PROP_BACKGROUND_Y_POSITION); + mBackFilter.AppendToString(buffer, PROP_BACKGROUND_FILTER); + fputs(buffer, out); +} + +const nsID& nsCSSText::GetID(void) +{ + return kCSSTextSID; +} + +void nsCSSText::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + nsAutoString buffer; + + mWordSpacing.AppendToString(buffer, PROP_WORD_SPACING); + mLetterSpacing.AppendToString(buffer, PROP_LETTER_SPACING); + mDecoration.AppendToString(buffer, PROP_TEXT_DECORATION); + mVertAlign.AppendToString(buffer, PROP_VERTICAL_ALIGN); + mTransform.AppendToString(buffer, PROP_TEXT_TRANSFORM); + mHorzAlign.AppendToString(buffer, PROP_TEXT_ALIGN); + mIndent.AppendToString(buffer, PROP_TEXT_INDENT); + mLineHeight.AppendToString(buffer, PROP_LINE_HEIGHT); + mWhiteSpace.AppendToString(buffer, PROP_WHITE_SPACE); + fputs(buffer, out); +} + +void nsCSSRect::List(FILE* out, PRInt32 aPropID, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + nsAutoString buffer; + + if (-1 < aPropID) { + buffer.Append(nsCSSProps::kNameTable[aPropID].name); + buffer.Append(": "); + } + + mTop.AppendToString(buffer); + mRight.AppendToString(buffer); + mBottom.AppendToString(buffer); + mLeft.AppendToString(buffer); + fputs(buffer, out); +} + +nsCSSMargin::nsCSSMargin(void) + : mMargin(nsnull), mPadding(nsnull), mBorder(nsnull), mColor(nsnull), mStyle(nsnull) +{ +} + +nsCSSMargin::~nsCSSMargin(void) +{ + if (nsnull != mMargin) { + delete mMargin; + } + if (nsnull != mPadding) { + delete mPadding; + } + if (nsnull != mBorder) { + delete mBorder; + } + if (nsnull != mColor) { + delete mColor; + } + if (nsnull != mStyle) { + delete mStyle; + } +} + +const nsID& nsCSSMargin::GetID(void) +{ + return kCSSMarginSID; +} + +void nsCSSMargin::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + if (nsnull != mMargin) { + mMargin->List(out, PROP_MARGIN, aIndent); + } + if (nsnull != mPadding) { + mPadding->List(out, PROP_PADDING, aIndent); + } + if (nsnull != mBorder) { + mBorder->List(out, PROP_BORDER_WIDTH, aIndent); + } + if (nsnull != mColor) { + mColor->List(out, PROP_BORDER_COLOR, aIndent); + } + if (nsnull != mStyle) { + mStyle->List(out, PROP_BORDER_STYLE, aIndent); + } +} + +nsCSSPosition::nsCSSPosition(void) + : mClip(nsnull) +{ +} + +nsCSSPosition::~nsCSSPosition(void) +{ + if (nsnull != mClip) { + delete mClip; + } +} + +const nsID& nsCSSPosition::GetID(void) +{ + return kCSSPositionSID; +} + +void nsCSSPosition::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + nsAutoString buffer; + + mPosition.AppendToString(buffer, PROP_POSITION); + mWidth.AppendToString(buffer, PROP_WIDTH); + mHeight.AppendToString(buffer, PROP_HEIGHT); + mLeft.AppendToString(buffer, PROP_LEFT); + mTop.AppendToString(buffer, PROP_TOP); + fputs(buffer, out); + if (nsnull != mClip) { + mClip->List(out, PROP_CLIP); + } + buffer.SetLength(0); + mOverflow.AppendToString(buffer, PROP_OVERFLOW); + mZIndex.AppendToString(buffer, PROP_OVERFLOW); + mVisibility.AppendToString(buffer, PROP_VISIBILITY); + mFloat.AppendToString(buffer, PROP_FLOAT); + mClear.AppendToString(buffer, PROP_CLEAR); + mDisplay.AppendToString(buffer, PROP_DISPLAY); + mFilter.AppendToString(buffer, PROP_FILTER); + fputs(buffer, out); +} + +const nsID& nsCSSList::GetID(void) +{ + return kCSSListSID; +} + +void nsCSSList::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + nsAutoString buffer; + + mType.AppendToString(buffer, PROP_LIST_STYLE_TYPE); + mImage.AppendToString(buffer, PROP_LIST_STYLE_IMAGE); + mPosition.AppendToString(buffer, PROP_LIST_STYLE_POSITION); + fputs(buffer, out); +} + + + +class CSSDeclarationImpl : public nsICSSDeclaration { +public: + void* operator new(size_t size); + + CSSDeclarationImpl(void); + ~CSSDeclarationImpl(void); + + NS_DECL_ISUPPORTS + + nsresult GetData(const nsID& aSID, nsCSSStruct** aData); + nsresult EnsureData(const nsID& aSID, nsCSSStruct** aData); + + nsresult AddValue(const char* aProperty, const nsCSSValue& aValue); + nsresult AddValue(PRInt32 aProperty, const nsCSSValue& aValue); + nsresult GetValue(const char* aProperty, nsCSSValue& aValue); + nsresult GetValue(PRInt32 aProperty, nsCSSValue& aValue); + + void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + +private: + CSSDeclarationImpl(const CSSDeclarationImpl& aCopy); + CSSDeclarationImpl& operator=(const CSSDeclarationImpl& aCopy); + PRBool operator==(const CSSDeclarationImpl& aCopy) const; + +protected: + nsCSSFont* mFont; + nsCSSColor* mColor; + nsCSSText* mText; + nsCSSMargin* mMargin; + nsCSSPosition* mPosition; + nsCSSList* mList; +}; + +void* CSSDeclarationImpl::operator new(size_t size) +{ + void* result = new char[size]; + + nsCRT::zero(result, size); + return result; +} + +CSSDeclarationImpl::CSSDeclarationImpl(void) +{ + NS_INIT_REFCNT(); +} + +CSSDeclarationImpl::~CSSDeclarationImpl(void) +{ + if (nsnull != mFont) { + delete mFont; + } + if (nsnull != mColor) { + delete mColor; + } + if (nsnull != mText) { + delete mText; + } + if (nsnull != mMargin) { + delete mMargin; + } + if (nsnull != mPosition) { + delete mPosition; + } + if (nsnull != mList) { + delete mList; + } +} + +NS_IMPL_ISUPPORTS(CSSDeclarationImpl, kICSSDeclarationIID); + +nsresult CSSDeclarationImpl::GetData(const nsID& aSID, nsCSSStruct** aDataPtr) +{ + if (nsnull == aDataPtr) { + return NS_ERROR_NULL_POINTER; + } + + if (aSID.Equals(kCSSFontSID)) { + *aDataPtr = mFont; + } + else if (aSID.Equals(kCSSColorSID)) { + *aDataPtr = mColor; + } + else if (aSID.Equals(kCSSTextSID)) { + *aDataPtr = mText; + } + else if (aSID.Equals(kCSSMarginSID)) { + *aDataPtr = mMargin; + } + else if (aSID.Equals(kCSSPositionSID)) { + *aDataPtr = mPosition; + } + else if (aSID.Equals(kCSSListSID)) { + *aDataPtr = mList; + } + else { + return NS_NOINTERFACE; + } + return NS_OK; +} + +nsresult CSSDeclarationImpl::EnsureData(const nsID& aSID, nsCSSStruct** aDataPtr) +{ + if (nsnull == aDataPtr) { + return NS_ERROR_NULL_POINTER; + } + + if (aSID.Equals(kCSSFontSID)) { + if (nsnull == mFont) { + mFont = new nsCSSFont(); + } + *aDataPtr = mFont; + } + else if (aSID.Equals(kCSSColorSID)) { + if (nsnull == mColor) { + mColor = new nsCSSColor(); + } + *aDataPtr = mColor; + } + else if (aSID.Equals(kCSSTextSID)) { + if (nsnull == mText) { + mText = new nsCSSText(); + } + *aDataPtr = mText; + } + else if (aSID.Equals(kCSSMarginSID)) { + if (nsnull == mMargin) { + mMargin = new nsCSSMargin(); + } + *aDataPtr = mMargin; + } + else if (aSID.Equals(kCSSPositionSID)) { + if (nsnull == mPosition) { + mPosition = new nsCSSPosition(); + } + *aDataPtr = mPosition; + } + else if (aSID.Equals(kCSSListSID)) { + if (nsnull == mList) { + mList = new nsCSSList(); + } + *aDataPtr = mList; + } + else { + return NS_NOINTERFACE; + } + if (nsnull == *aDataPtr) { + return NS_ERROR_OUT_OF_MEMORY; + } + return NS_OK; +} + +nsresult CSSDeclarationImpl::AddValue(const char* aProperty, const nsCSSValue& aValue) +{ + return AddValue(nsCSSProps::LookupName(aProperty), aValue); +} + +nsresult CSSDeclarationImpl::AddValue(PRInt32 aProperty, const nsCSSValue& aValue) +{ + nsresult result = NS_OK; + + switch (aProperty) { + // nsCSSFont + case PROP_FONT_FAMILY: + case PROP_FONT_STYLE: + case PROP_FONT_VARIANT: + case PROP_FONT_WEIGHT: + case PROP_FONT_SIZE: + if (nsnull == mFont) { + mFont = new nsCSSFont(); + } + if (nsnull != mFont) { + switch (aProperty) { + case PROP_FONT_FAMILY: mFont->mFamily = aValue; break; + case PROP_FONT_STYLE: mFont->mStyle = aValue; break; + case PROP_FONT_VARIANT: mFont->mVariant = aValue; break; + case PROP_FONT_WEIGHT: mFont->mWeight = aValue; break; + case PROP_FONT_SIZE: mFont->mSize = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + // nsCSSColor + case PROP_COLOR: + case PROP_BACKGROUND_COLOR: + case PROP_BACKGROUND_IMAGE: + case PROP_BACKGROUND_REPEAT: + case PROP_BACKGROUND_ATTACHMENT: + case PROP_BACKGROUND_X_POSITION: + case PROP_BACKGROUND_Y_POSITION: + case PROP_BACKGROUND_FILTER: + if (nsnull == mColor) { + mColor = new nsCSSColor(); + } + if (nsnull != mColor) { + switch (aProperty) { + case PROP_COLOR: mColor->mColor = aValue; break; + case PROP_BACKGROUND_COLOR: mColor->mBackColor = aValue; break; + case PROP_BACKGROUND_IMAGE: mColor->mBackImage = aValue; break; + case PROP_BACKGROUND_REPEAT: mColor->mBackRepeat = aValue; break; + case PROP_BACKGROUND_ATTACHMENT: mColor->mBackAttachment = aValue; break; + case PROP_BACKGROUND_X_POSITION: mColor->mBackPositionX = aValue; break; + case PROP_BACKGROUND_Y_POSITION: mColor->mBackPositionY = aValue; break; + case PROP_BACKGROUND_FILTER: mColor->mBackFilter = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + // nsCSSText + case PROP_WORD_SPACING: + case PROP_LETTER_SPACING: + case PROP_TEXT_DECORATION: + case PROP_VERTICAL_ALIGN: + case PROP_TEXT_TRANSFORM: + case PROP_TEXT_ALIGN: + case PROP_TEXT_INDENT: + case PROP_LINE_HEIGHT: + case PROP_WHITE_SPACE: + if (nsnull == mText) { + mText = new nsCSSText(); + } + if (nsnull != mText) { + switch (aProperty) { + case PROP_WORD_SPACING: mText->mWordSpacing = aValue; break; + case PROP_LETTER_SPACING: mText->mLetterSpacing = aValue; break; + case PROP_TEXT_DECORATION: mText->mDecoration = aValue; break; + case PROP_VERTICAL_ALIGN: mText->mVertAlign = aValue; break; + case PROP_TEXT_TRANSFORM: mText->mTransform = aValue; break; + case PROP_TEXT_ALIGN: mText->mHorzAlign = aValue; break; + case PROP_TEXT_INDENT: mText->mIndent = aValue; break; + case PROP_LINE_HEIGHT: mText->mLineHeight = aValue; break; + case PROP_WHITE_SPACE: mText->mWhiteSpace = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + // nsCSSMargin + case PROP_MARGIN_TOP: + case PROP_MARGIN_RIGHT: + case PROP_MARGIN_BOTTOM: + case PROP_MARGIN_LEFT: + if (nsnull == mMargin) { + mMargin = new nsCSSMargin(); + } + if (nsnull != mMargin) { + if (nsnull == mMargin->mMargin) { + mMargin->mMargin = new nsCSSRect(); + } + if (nsnull != mMargin->mMargin) { + switch (aProperty) { + case PROP_MARGIN_TOP: mMargin->mMargin->mTop = aValue; break; + case PROP_MARGIN_RIGHT: mMargin->mMargin->mRight = aValue; break; + case PROP_MARGIN_BOTTOM: mMargin->mMargin->mBottom = aValue; break; + case PROP_MARGIN_LEFT: mMargin->mMargin->mLeft = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + case PROP_PADDING_TOP: + case PROP_PADDING_RIGHT: + case PROP_PADDING_BOTTOM: + case PROP_PADDING_LEFT: + if (nsnull == mMargin) { + mMargin = new nsCSSMargin(); + } + if (nsnull != mMargin) { + if (nsnull == mMargin->mPadding) { + mMargin->mPadding = new nsCSSRect(); + } + if (nsnull != mMargin->mPadding) { + switch (aProperty) { + case PROP_PADDING_TOP: mMargin->mPadding->mTop = aValue; break; + case PROP_PADDING_RIGHT: mMargin->mPadding->mRight = aValue; break; + case PROP_PADDING_BOTTOM: mMargin->mPadding->mBottom = aValue; break; + case PROP_PADDING_LEFT: mMargin->mPadding->mLeft = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + case PROP_BORDER_TOP_WIDTH: + case PROP_BORDER_RIGHT_WIDTH: + case PROP_BORDER_BOTTOM_WIDTH: + case PROP_BORDER_LEFT_WIDTH: + if (nsnull == mMargin) { + mMargin = new nsCSSMargin(); + } + if (nsnull != mMargin) { + if (nsnull == mMargin->mBorder) { + mMargin->mBorder = new nsCSSRect(); + } + if (nsnull != mMargin->mBorder) { + switch (aProperty) { + case PROP_BORDER_TOP_WIDTH: mMargin->mBorder->mTop = aValue; break; + case PROP_BORDER_RIGHT_WIDTH: mMargin->mBorder->mRight = aValue; break; + case PROP_BORDER_BOTTOM_WIDTH: mMargin->mBorder->mBottom = aValue; break; + case PROP_BORDER_LEFT_WIDTH: mMargin->mBorder->mLeft = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + case PROP_BORDER_TOP_COLOR: + case PROP_BORDER_RIGHT_COLOR: + case PROP_BORDER_BOTTOM_COLOR: + case PROP_BORDER_LEFT_COLOR: + if (nsnull == mMargin) { + mMargin = new nsCSSMargin(); + } + if (nsnull != mMargin) { + if (nsnull == mMargin->mColor) { + mMargin->mColor = new nsCSSRect(); + } + if (nsnull != mMargin->mColor) { + switch (aProperty) { + case PROP_BORDER_TOP_COLOR: mMargin->mColor->mTop = aValue; break; + case PROP_BORDER_RIGHT_COLOR: mMargin->mColor->mRight = aValue; break; + case PROP_BORDER_BOTTOM_COLOR: mMargin->mColor->mBottom = aValue; break; + case PROP_BORDER_LEFT_COLOR: mMargin->mColor->mLeft = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + case PROP_BORDER_TOP_STYLE: + case PROP_BORDER_RIGHT_STYLE: + case PROP_BORDER_BOTTOM_STYLE: + case PROP_BORDER_LEFT_STYLE: + if (nsnull == mMargin) { + mMargin = new nsCSSMargin(); + } + if (nsnull != mMargin) { + if (nsnull == mMargin->mStyle) { + mMargin->mStyle = new nsCSSRect(); + } + if (nsnull != mMargin->mStyle) { + switch (aProperty) { + case PROP_BORDER_TOP_STYLE: mMargin->mStyle->mTop = aValue; break; + case PROP_BORDER_RIGHT_STYLE: mMargin->mStyle->mRight = aValue; break; + case PROP_BORDER_BOTTOM_STYLE: mMargin->mStyle->mBottom = aValue; break; + case PROP_BORDER_LEFT_STYLE: mMargin->mStyle->mLeft = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + // nsCSSPosition + case PROP_POSITION: + case PROP_WIDTH: + case PROP_HEIGHT: + case PROP_LEFT: + case PROP_TOP: + case PROP_OVERFLOW: + case PROP_Z_INDEX: + case PROP_VISIBILITY: + case PROP_FLOAT: + case PROP_CLEAR: + case PROP_DISPLAY: + case PROP_FILTER: + if (nsnull == mPosition) { + mPosition = new nsCSSPosition(); + } + if (nsnull != mPosition) { + switch (aProperty) { + case PROP_POSITION: mPosition->mPosition = aValue; break; + case PROP_WIDTH: mPosition->mWidth = aValue; break; + case PROP_HEIGHT: mPosition->mHeight = aValue; break; + case PROP_LEFT: mPosition->mLeft = aValue; break; + case PROP_TOP: mPosition->mTop = aValue; break; + case PROP_OVERFLOW: mPosition->mOverflow = aValue; break; + case PROP_Z_INDEX: mPosition->mZIndex = aValue; break; + case PROP_VISIBILITY: mPosition->mVisibility = aValue; break; + case PROP_FLOAT: mPosition->mFloat = aValue; break; + case PROP_CLEAR: mPosition->mClear = aValue; break; + case PROP_DISPLAY: mPosition->mDisplay = aValue; break; + case PROP_FILTER: mPosition->mFilter = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + case PROP_CLIP_TOP: + case PROP_CLIP_RIGHT: + case PROP_CLIP_BOTTOM: + case PROP_CLIP_LEFT: + if (nsnull == mPosition) { + mPosition = new nsCSSPosition(); + } + if (nsnull != mPosition) { + if (nsnull == mPosition->mClip) { + mPosition->mClip = new nsCSSRect(); + } + if (nsnull != mPosition->mClip) { + switch(aProperty) { + case PROP_CLIP_TOP: mPosition->mClip->mTop = aValue; break; + case PROP_CLIP_RIGHT: mPosition->mClip->mRight = aValue; break; + case PROP_CLIP_BOTTOM: mPosition->mClip->mBottom = aValue; break; + case PROP_CLIP_LEFT: mPosition->mClip->mLeft = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + // nsCSSList + case PROP_LIST_STYLE_TYPE: + case PROP_LIST_STYLE_IMAGE: + case PROP_LIST_STYLE_POSITION: + if (nsnull == mList) { + mList = new nsCSSList(); + } + if (nsnull != mList) { + switch (aProperty) { + case PROP_LIST_STYLE_TYPE: mList->mType = aValue; break; + case PROP_LIST_STYLE_IMAGE: mList->mImage = aValue; break; + case PROP_LIST_STYLE_POSITION: mList->mPosition = aValue; break; + } + } + else { + result = NS_ERROR_OUT_OF_MEMORY; + } + break; + + case PROP_BACKGROUND: + case PROP_BORDER: + case PROP_CLIP: + case PROP_FONT: + case PROP_LIST_STYLE: + case PROP_MARGIN: + case PROP_PADDING: + case PROP_BACKGROUND_POSITION: + case PROP_BORDER_TOP: + case PROP_BORDER_RIGHT: + case PROP_BORDER_BOTTOM: + case PROP_BORDER_LEFT: + case PROP_BORDER_COLOR: + case PROP_BORDER_STYLE: + case PROP_BORDER_WIDTH: + NS_ERROR("can't query for shorthand properties"); + default: + result = NS_ERROR_ILLEGAL_VALUE; + break; + } + return result; +} + +nsresult CSSDeclarationImpl::GetValue(const char* aProperty, nsCSSValue& aValue) +{ + return GetValue(nsCSSProps::LookupName(aProperty), aValue); +} + +nsresult CSSDeclarationImpl::GetValue(PRInt32 aProperty, nsCSSValue& aValue) +{ + nsresult result = NS_OK; + + switch (aProperty) { + // nsCSSFont + case PROP_FONT_FAMILY: + case PROP_FONT_STYLE: + case PROP_FONT_VARIANT: + case PROP_FONT_WEIGHT: + case PROP_FONT_SIZE: + if (nsnull != mFont) { + switch (aProperty) { + case PROP_FONT_FAMILY: aValue = mFont->mFamily; break; + case PROP_FONT_STYLE: aValue = mFont->mStyle; break; + case PROP_FONT_VARIANT: aValue = mFont->mVariant; break; + case PROP_FONT_WEIGHT: aValue = mFont->mWeight; break; + case PROP_FONT_SIZE: aValue = mFont->mSize; break; + } + } + else { + aValue.Reset(); + } + break; + + // nsCSSColor + case PROP_COLOR: + case PROP_BACKGROUND_COLOR: + case PROP_BACKGROUND_IMAGE: + case PROP_BACKGROUND_REPEAT: + case PROP_BACKGROUND_ATTACHMENT: + case PROP_BACKGROUND_X_POSITION: + case PROP_BACKGROUND_Y_POSITION: + case PROP_BACKGROUND_FILTER: + if (nsnull != mColor) { + switch (aProperty) { + case PROP_COLOR: aValue = mColor->mColor; break; + case PROP_BACKGROUND_COLOR: aValue = mColor->mBackColor; break; + case PROP_BACKGROUND_IMAGE: aValue = mColor->mBackImage; break; + case PROP_BACKGROUND_REPEAT: aValue = mColor->mBackRepeat; break; + case PROP_BACKGROUND_ATTACHMENT: aValue = mColor->mBackAttachment; break; + case PROP_BACKGROUND_X_POSITION: aValue = mColor->mBackPositionX; break; + case PROP_BACKGROUND_Y_POSITION: aValue = mColor->mBackPositionY; break; + case PROP_BACKGROUND_FILTER: aValue = mColor->mBackFilter; break; + } + } + else { + aValue.Reset(); + } + break; + + // nsCSSText + case PROP_WORD_SPACING: + case PROP_LETTER_SPACING: + case PROP_TEXT_DECORATION: + case PROP_VERTICAL_ALIGN: + case PROP_TEXT_TRANSFORM: + case PROP_TEXT_ALIGN: + case PROP_TEXT_INDENT: + case PROP_LINE_HEIGHT: + case PROP_WHITE_SPACE: + if (nsnull != mText) { + switch (aProperty) { + case PROP_WORD_SPACING: aValue = mText->mWordSpacing; break; + case PROP_LETTER_SPACING: aValue = mText->mLetterSpacing; break; + case PROP_TEXT_DECORATION: aValue = mText->mDecoration; break; + case PROP_VERTICAL_ALIGN: aValue = mText->mVertAlign; break; + case PROP_TEXT_TRANSFORM: aValue = mText->mTransform; break; + case PROP_TEXT_ALIGN: aValue = mText->mHorzAlign; break; + case PROP_TEXT_INDENT: aValue = mText->mIndent; break; + case PROP_LINE_HEIGHT: aValue = mText->mLineHeight; break; + case PROP_WHITE_SPACE: aValue = mText->mWhiteSpace; break; + } + } + else { + aValue.Reset(); + } + break; + + // nsCSSMargin + case PROP_MARGIN_TOP: + case PROP_MARGIN_RIGHT: + case PROP_MARGIN_BOTTOM: + case PROP_MARGIN_LEFT: + if ((nsnull != mMargin) && (nsnull != mMargin->mMargin)) { + switch (aProperty) { + case PROP_MARGIN_TOP: aValue = mMargin->mMargin->mTop; break; + case PROP_MARGIN_RIGHT: aValue = mMargin->mMargin->mRight; break; + case PROP_MARGIN_BOTTOM: aValue = mMargin->mMargin->mBottom; break; + case PROP_MARGIN_LEFT: aValue = mMargin->mMargin->mLeft; break; + } + } + else { + aValue.Reset(); + } + break; + + case PROP_PADDING_TOP: + case PROP_PADDING_RIGHT: + case PROP_PADDING_BOTTOM: + case PROP_PADDING_LEFT: + if ((nsnull != mMargin) && (nsnull != mMargin->mPadding)) { + switch (aProperty) { + case PROP_PADDING_TOP: aValue = mMargin->mPadding->mTop; break; + case PROP_PADDING_RIGHT: aValue = mMargin->mPadding->mRight; break; + case PROP_PADDING_BOTTOM: aValue = mMargin->mPadding->mBottom; break; + case PROP_PADDING_LEFT: aValue = mMargin->mPadding->mLeft; break; + } + } + else { + aValue.Reset(); + } + break; + + case PROP_BORDER_TOP_WIDTH: + case PROP_BORDER_RIGHT_WIDTH: + case PROP_BORDER_BOTTOM_WIDTH: + case PROP_BORDER_LEFT_WIDTH: + if ((nsnull != mMargin) && (nsnull != mMargin->mBorder)) { + switch (aProperty) { + case PROP_BORDER_TOP_WIDTH: aValue = mMargin->mBorder->mTop; break; + case PROP_BORDER_RIGHT_WIDTH: aValue = mMargin->mBorder->mRight; break; + case PROP_BORDER_BOTTOM_WIDTH: aValue = mMargin->mBorder->mBottom; break; + case PROP_BORDER_LEFT_WIDTH: aValue = mMargin->mBorder->mLeft; break; + } + } + else { + aValue.Reset(); + } + break; + + case PROP_BORDER_TOP_COLOR: + case PROP_BORDER_RIGHT_COLOR: + case PROP_BORDER_BOTTOM_COLOR: + case PROP_BORDER_LEFT_COLOR: + if ((nsnull != mMargin) && (nsnull != mMargin->mColor)) { + switch (aProperty) { + case PROP_BORDER_TOP_COLOR: aValue = mMargin->mColor->mTop; break; + case PROP_BORDER_RIGHT_COLOR: aValue = mMargin->mColor->mRight; break; + case PROP_BORDER_BOTTOM_COLOR: aValue = mMargin->mColor->mBottom; break; + case PROP_BORDER_LEFT_COLOR: aValue = mMargin->mColor->mLeft; break; + } + } + else { + aValue.Reset(); + } + break; + + case PROP_BORDER_TOP_STYLE: + case PROP_BORDER_RIGHT_STYLE: + case PROP_BORDER_BOTTOM_STYLE: + case PROP_BORDER_LEFT_STYLE: + if ((nsnull != mMargin) && (nsnull != mMargin->mStyle)) { + switch (aProperty) { + case PROP_BORDER_TOP_STYLE: aValue = mMargin->mStyle->mTop; break; + case PROP_BORDER_RIGHT_STYLE: aValue = mMargin->mStyle->mRight; break; + case PROP_BORDER_BOTTOM_STYLE: aValue = mMargin->mStyle->mBottom; break; + case PROP_BORDER_LEFT_STYLE: aValue = mMargin->mStyle->mLeft; break; + } + } + else { + aValue.Reset(); + } + break; + + // nsCSSPosition + case PROP_POSITION: + case PROP_WIDTH: + case PROP_HEIGHT: + case PROP_LEFT: + case PROP_TOP: + case PROP_OVERFLOW: + case PROP_Z_INDEX: + case PROP_VISIBILITY: + case PROP_FLOAT: + case PROP_CLEAR: + case PROP_DISPLAY: + case PROP_FILTER: + if (nsnull != mPosition) { + switch (aProperty) { + case PROP_POSITION: aValue = mPosition->mPosition; break; + case PROP_WIDTH: aValue = mPosition->mWidth; break; + case PROP_HEIGHT: aValue = mPosition->mHeight; break; + case PROP_LEFT: aValue = mPosition->mLeft; break; + case PROP_TOP: aValue = mPosition->mTop; break; + case PROP_OVERFLOW: aValue = mPosition->mOverflow; break; + case PROP_Z_INDEX: aValue = mPosition->mZIndex; break; + case PROP_VISIBILITY: aValue = mPosition->mVisibility; break; + case PROP_FLOAT: aValue = mPosition->mFloat; break; + case PROP_CLEAR: aValue = mPosition->mClear; break; + case PROP_DISPLAY: aValue = mPosition->mDisplay; break; + case PROP_FILTER: aValue = mPosition->mFilter; break; + } + } + else { + aValue.Reset(); + } + break; + + case PROP_CLIP_TOP: + case PROP_CLIP_RIGHT: + case PROP_CLIP_BOTTOM: + case PROP_CLIP_LEFT: + if ((nsnull != mPosition) && (nsnull != mPosition->mClip)) { + switch(aProperty) { + case PROP_CLIP_TOP: aValue = mPosition->mClip->mTop; break; + case PROP_CLIP_RIGHT: aValue = mPosition->mClip->mRight; break; + case PROP_CLIP_BOTTOM: aValue = mPosition->mClip->mBottom; break; + case PROP_CLIP_LEFT: aValue = mPosition->mClip->mLeft; break; + } + } + else { + aValue.Reset(); + } + break; + + // nsCSSList + case PROP_LIST_STYLE_TYPE: + case PROP_LIST_STYLE_IMAGE: + case PROP_LIST_STYLE_POSITION: + if (nsnull != mList) { + switch (aProperty) { + case PROP_LIST_STYLE_TYPE: aValue = mList->mType; break; + case PROP_LIST_STYLE_IMAGE: aValue = mList->mImage; break; + case PROP_LIST_STYLE_POSITION: aValue = mList->mPosition; break; + } + } + else { + aValue.Reset(); + } + break; + + case PROP_BACKGROUND: + case PROP_BORDER: + case PROP_CLIP: + case PROP_FONT: + case PROP_LIST_STYLE: + case PROP_MARGIN: + case PROP_PADDING: + case PROP_BACKGROUND_POSITION: + case PROP_BORDER_TOP: + case PROP_BORDER_RIGHT: + case PROP_BORDER_BOTTOM: + case PROP_BORDER_LEFT: + case PROP_BORDER_COLOR: + case PROP_BORDER_STYLE: + case PROP_BORDER_WIDTH: + NS_ERROR("can't query for shorthand properties"); + default: + result = NS_ERROR_ILLEGAL_VALUE; + break; + } + return result; +} + +void CSSDeclarationImpl::List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + fputs("{ ", out); + + if (nsnull != mFont) { + mFont->List(out); + } + if (nsnull != mColor) { + mColor->List(out); + } + if (nsnull != mText) { + mText->List(out); + } + if (nsnull != mMargin) { + mMargin->List(out); + } + if (nsnull != mPosition) { + mPosition->List(out); + } + if (nsnull != mList) { + mList->List(out); + } + + fputs("}", out); +} + +NS_HTML nsresult + NS_NewCSSDeclaration(nsICSSDeclaration** aInstancePtrResult) +{ + if (aInstancePtrResult == nsnull) { + return NS_ERROR_NULL_POINTER; + } + + CSSDeclarationImpl *it = new CSSDeclarationImpl(); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(kICSSDeclarationIID, (void **) aInstancePtrResult); +} + + +/* +font +=========== + +'font-family', string (list) +'font-style', enum +'font-variant' enum (ie: small caps) +'font-weight' enum +'font-size' abs, pct, enum, +-1 + + +color/background +============= + +color: color +background-color: color +background-image: url(string) +background-repeat: enum +background-attachment: enum +background-position-x -y: abs, pct, enum (left/top center right/bottom (pct?)) + + + +text +======= +word-spacing: abs, "normal" +letter-spacing: abs, "normal" +text-decoration: enum +vertical-align: enum, pct +text-transform: enum +text-align: enum +text-indent: abs, pct +line-height: "normal", abs, pct, number-factor +white-space: enum + +margin +======= +margin-top -right -bottom -left: "auto", abs, pct +padding-top -right -bottom -left: abs, pct +border-top -right -bottom -left-width: enum, abs +border-top -right -bottom -left-color: color +border-top -right -bottom -left-style: enum + +size +======= +position: enum +width: abs, pct, "auto" +height: abs, pct, "auto" +left: abs, pct, "auto" +top: abs, pct, "auto" +clip: shape, "auto" (shape: rect - abs, auto) +overflow: enum +z-index: int, auto +visibity: enum + +float: enum +clear: enum + +display: enum + +filter: string + +list +======== +list-style-type: enum +list-style-image: url, "none" +list-style-position: enum (bool? in/out) + +*/ + + + diff --git a/mozilla/layout/style/nsCSSStyleRule.cpp b/mozilla/layout/style/nsCSSStyleRule.cpp new file mode 100644 index 00000000000..c19372058b9 --- /dev/null +++ b/mozilla/layout/style/nsCSSStyleRule.cpp @@ -0,0 +1,683 @@ +/* -*- 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 "nsICSSStyleRule.h" +#include "nsICSSDeclaration.h" +#include "nsIStyleContext.h" +#include "nsIPresContext.h" +#include "nsIArena.h" +#include "nsIAtom.h" +#include "nsCRT.h" +#include "nsString.h" +#include "nsStyleConsts.h" +#include "nsUnitConversion.h" + +static NS_DEFINE_IID(kIStyleRuleIID, NS_ISTYLE_RULE_IID); +static NS_DEFINE_IID(kICSSDeclarationIID, NS_ICSS_DECLARATION_IID); +static NS_DEFINE_IID(kICSSStyleRuleIID, NS_ICSS_STYLE_RULE_IID); + +static NS_DEFINE_IID(kStyleFontSID, NS_STYLEFONT_SID); +static NS_DEFINE_IID(kStyleColorSID, NS_STYLECOLOR_SID); +static NS_DEFINE_IID(kStyleListSID, NS_STYLELIST_SID); + +static NS_DEFINE_IID(kCSSFontSID, NS_CSS_FONT_SID); +static NS_DEFINE_IID(kCSSColorSID, NS_CSS_COLOR_SID); +static NS_DEFINE_IID(kCSSTextSID, NS_CSS_TEXT_SID); +static NS_DEFINE_IID(kCSSMarginSID, NS_CSS_MARGIN_SID); +static NS_DEFINE_IID(kCSSPositionSID, NS_CSS_POSITION_SID); +static NS_DEFINE_IID(kCSSListSID, NS_CSS_LIST_SID); + + +// -- nsCSSSelector ------------------------------- + +nsCSSSelector::nsCSSSelector() + : mTag(nsnull), mID(nsnull), mClass(nsnull), mPseudoClass(nsnull), + mNext(nsnull) +{ +} + +nsCSSSelector::nsCSSSelector(nsIAtom* aTag, nsIAtom* aID, nsIAtom* aClass, nsIAtom* aPseudoClass) + : mTag(aTag), mID(aID), mClass(aClass), mPseudoClass(aPseudoClass), + mNext(nsnull) +{ + NS_IF_ADDREF(mTag); + NS_IF_ADDREF(mID); + NS_IF_ADDREF(mClass); + NS_IF_ADDREF(mPseudoClass); +} + +nsCSSSelector::nsCSSSelector(const nsCSSSelector& aCopy) + : mTag(aCopy.mTag), mID(aCopy.mID), mClass(aCopy.mClass), mPseudoClass(aCopy.mPseudoClass), + mNext(nsnull) +{ // implmented to support extension to CSS2 (when we have to copy the array) + NS_IF_ADDREF(mTag); + NS_IF_ADDREF(mID); + NS_IF_ADDREF(mClass); + NS_IF_ADDREF(mPseudoClass); +} + +nsCSSSelector::~nsCSSSelector() +{ + NS_IF_RELEASE(mTag); + NS_IF_RELEASE(mID); + NS_IF_RELEASE(mClass); + NS_IF_RELEASE(mPseudoClass); +} + +nsCSSSelector& nsCSSSelector::operator=(const nsCSSSelector& aCopy) +{ + NS_IF_RELEASE(mTag); + NS_IF_RELEASE(mID); + NS_IF_RELEASE(mClass); + NS_IF_RELEASE(mPseudoClass); + mTag = aCopy.mTag; + mID = aCopy.mID; + mClass = aCopy.mClass; + mPseudoClass = aCopy.mPseudoClass; + NS_IF_ADDREF(mTag); + NS_IF_ADDREF(mID); + NS_IF_ADDREF(mClass); + NS_IF_ADDREF(mPseudoClass); + return *this; +} + +PRBool nsCSSSelector::Equals(const nsCSSSelector* aOther) const +{ + if (nsnull != aOther) { + return (PRBool)((aOther->mTag == mTag) && (aOther->mID == mID) && + (aOther->mClass == mClass) && (aOther->mPseudoClass == mPseudoClass)); + } + return PR_FALSE; +} + + +void nsCSSSelector::Set(const nsString& aTag, const nsString& aID, + const nsString& aClass, const nsString& aPseudoClass) +{ + NS_IF_RELEASE(mTag); + NS_IF_RELEASE(mID); + NS_IF_RELEASE(mClass); + NS_IF_RELEASE(mPseudoClass); + if (0 < aTag.Length()) { + mTag = NS_NewAtom(aTag); + } + if (0 < aID.Length()) { + mID = NS_NewAtom(aID); + } + if (0 < aClass.Length()) { + mClass = NS_NewAtom(aClass); + } + if (0 < aPseudoClass.Length()) { + mPseudoClass = NS_NewAtom(aPseudoClass); + } +} + +// -- nsCSSStyleRule ------------------------------- + +class CSSStyleRuleImpl : public nsICSSStyleRule { +public: + void* operator new(size_t size); + void* operator new(size_t size, nsIArena* aArena); + void operator delete(void* ptr); + + CSSStyleRuleImpl(const nsCSSSelector& aSelector); + + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + + virtual PRBool Equals(const nsIStyleRule* aRule) const; + virtual PRUint32 HashValue(void) const; + + virtual nsCSSSelector* FirstSelector(void); + virtual void AddSelector(const nsCSSSelector& aSelector); + virtual void DeleteSelector(nsCSSSelector* aSelector); + + virtual nsICSSDeclaration* GetDeclaration(void) const; + virtual void SetDeclaration(nsICSSDeclaration* aDeclaration); + + virtual PRInt32 GetWeight(void) const; + virtual void SetWeight(PRInt32 aWeight); + + virtual nscoord CalcLength(const nsCSSValue& aValue, nsStyleFont* aFont, + nsIPresContext* aPresContext); + virtual void MapStyleInto(nsIStyleContext* aContext, nsIPresContext* aPresContext); + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + +private: + // These are not supported and are not implemented! + CSSStyleRuleImpl(const CSSStyleRuleImpl& aCopy); + CSSStyleRuleImpl& operator=(const CSSStyleRuleImpl& aCopy); + +protected: + virtual ~CSSStyleRuleImpl(); + +protected: + PRUint32 mInHeap : 1; + PRUint32 mRefCnt : 31; + + nsCSSSelector mSelector; + nsICSSDeclaration* mDeclaration; + PRInt32 mWeight; +}; + + +void* CSSStyleRuleImpl::operator new(size_t size) +{ + CSSStyleRuleImpl* rv = (CSSStyleRuleImpl*) ::operator new(size); +#ifdef NS_DEBUG + if (nsnull != rv) { + nsCRT::memset(rv, 0xEE, size); + } +#endif + rv->mInHeap = 1; + return (void*) rv; +} + +void* CSSStyleRuleImpl::operator new(size_t size, nsIArena* aArena) +{ + CSSStyleRuleImpl* rv = (CSSStyleRuleImpl*) aArena->Alloc(PRInt32(size)); +#ifdef NS_DEBUG + if (nsnull != rv) { + nsCRT::memset(rv, 0xEE, size); + } +#endif + rv->mInHeap = 0; + return (void*) rv; +} + +void CSSStyleRuleImpl::operator delete(void* ptr) +{ + CSSStyleRuleImpl* rule = (CSSStyleRuleImpl*) ptr; + if (nsnull != rule) { + if (rule->mInHeap) { + ::delete ptr; + } + } +} + + + +CSSStyleRuleImpl::CSSStyleRuleImpl(const nsCSSSelector& aSelector) + : mSelector(aSelector), mDeclaration(nsnull), mWeight(0) +{ + NS_INIT_REFCNT(); +} + +CSSStyleRuleImpl::~CSSStyleRuleImpl() +{ + nsCSSSelector* next = mSelector.mNext; + + while (nsnull != next) { + nsCSSSelector* selector = next; + next = selector->mNext; + delete selector; + } + NS_IF_RELEASE(mDeclaration); +} + +NS_IMPL_ADDREF(CSSStyleRuleImpl) +NS_IMPL_RELEASE(CSSStyleRuleImpl) + +nsresult CSSStyleRuleImpl::QueryInterface(const nsIID& aIID, + void** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + if (aIID.Equals(kICSSStyleRuleIID)) { + *aInstancePtrResult = (void*) ((nsICSSStyleRule*)this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIStyleRuleIID)) { + *aInstancePtrResult = (void*) ((nsIStyleRule*)this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kISupportsIID)) { + *aInstancePtrResult = (void*) ((nsISupports*)this); + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + + +PRBool CSSStyleRuleImpl::Equals(const nsIStyleRule* aRule) const +{ + nsICSSStyleRule* iCSSRule; + + if (this == aRule) { + return PR_TRUE; + } + + if ((nsnull != aRule) && + (NS_OK == ((nsIStyleRule*)aRule)->QueryInterface(kICSSStyleRuleIID, (void**) &iCSSRule))) { + + CSSStyleRuleImpl* rule = (CSSStyleRuleImpl*)iCSSRule; + const nsCSSSelector* local = &mSelector; + const nsCSSSelector* other = &(rule->mSelector); + PRBool result = PR_TRUE; + + while ((PR_TRUE == result) && (nsnull != local) && (nsnull != other)) { + if (! local->Equals(other)) { + result = PR_FALSE; + } + local = local->mNext; + other = other->mNext; + } + if ((nsnull != local) || (nsnull != other)) { // more were left + result = PR_FALSE; + } + if ((rule->mDeclaration != mDeclaration) || + (rule->mWeight != mWeight)) { + result = PR_FALSE; + } + NS_RELEASE(iCSSRule); + return result; + } + return PR_FALSE; +} + +PRUint32 CSSStyleRuleImpl::HashValue(void) const +{ + return (PRUint32)this; +} + +nsCSSSelector* CSSStyleRuleImpl::FirstSelector(void) +{ + return &mSelector; +} + +void CSSStyleRuleImpl::AddSelector(const nsCSSSelector& aSelector) +{ + nsCSSSelector* selector = new nsCSSSelector(aSelector); + nsCSSSelector* last = &mSelector; + + while (nsnull != last->mNext) { + last = last->mNext; + } + last->mNext = selector; +} + + +void CSSStyleRuleImpl::DeleteSelector(nsCSSSelector* aSelector) +{ + if (nsnull != aSelector) { + if (&mSelector == aSelector) { // handle first selector + mSelector = *aSelector; // assign value + mSelector.mNext = aSelector->mNext; + delete aSelector; + } + else { + nsCSSSelector* selector = &mSelector; + + while (nsnull != selector->mNext) { + if (aSelector == selector->mNext) { + selector->mNext = aSelector->mNext; + delete aSelector; + return; + } + selector = selector->mNext; + } + } + } +} + +nsICSSDeclaration* CSSStyleRuleImpl::GetDeclaration(void) const +{ + NS_IF_ADDREF(mDeclaration); + return mDeclaration; +} + +void CSSStyleRuleImpl::SetDeclaration(nsICSSDeclaration* aDeclaration) +{ + NS_IF_RELEASE(mDeclaration); + mDeclaration = aDeclaration; + NS_IF_ADDREF(mDeclaration); +} + +PRInt32 CSSStyleRuleImpl::GetWeight(void) const +{ + return mWeight; +} + +void CSSStyleRuleImpl::SetWeight(PRInt32 aWeight) +{ + mWeight = aWeight; +} + +nscoord CSSStyleRuleImpl::CalcLength(const nsCSSValue& aValue, nsStyleFont* aFont, + nsIPresContext* aPresContext) +{ + NS_ASSERTION(aValue.IsLengthUnit(), "not a length unit"); + if (aValue.IsFixedLengthUnit()) { + return aValue.GetLengthTwips(); + } + nsCSSUnit unit = aValue.GetUnit(); + switch (unit) { + case eCSSUnit_EM: + return aFont->mFont.size; + case eCSSUnit_EN: + return (aFont->mFont.size / 2); + case eCSSUnit_XHeight: + NS_NOTYETIMPLEMENTED("x height unit"); + return ((aFont->mFont.size / 3) * 2); // XXX HACK! + case eCSSUnit_CapHeight: + NS_NOTYETIMPLEMENTED("cap height unit"); + return ((aFont->mFont.size / 3) * 2); // XXX HACK! + + case eCSSUnit_Pixel: + return (nscoord)(aPresContext->GetPixelsToTwips() * aValue.GetFloatValue()); + } + return 0; +} + +void CSSStyleRuleImpl::MapStyleInto(nsIStyleContext* aContext, nsIPresContext* aPresContext) +{ + if (nsnull != mDeclaration) { + nsStyleFont* font = (nsStyleFont*)aContext->GetData(kStyleFontSID); + + nsCSSFont* ourFont; + if (NS_OK == mDeclaration->GetData(kCSSFontSID, (nsCSSStruct**)&ourFont)) { + if (nsnull != ourFont) { + nsStyleFont* parentFont = font; + nsIStyleContext* parentContext = aContext->GetParent(); + if (nsnull != parentContext) { + parentFont = (nsStyleFont*)parentContext->GetData(kStyleFontSID); + } + + // font-family: string list + if (ourFont->mFamily.GetUnit() == eCSSUnit_String) { + nsAutoString familyList; + ourFont->mFamily.GetStringValue(familyList); + // XXX meeds font support to determine usable fonts + // parse up the CSS string & remove the quotes + // XXX only does first until we can tell what are installed fonts + nsAutoString family; + PRInt32 index = familyList.Find(PRUnichar(',')); + if (-1 < index) { + familyList.Left(family, index); + } + else { + family.Append(familyList); + } + family.StripChars("\""); + family.StripWhitespace(); + + font->mFont.name = family; + } + + // font-style: enum + if (ourFont->mStyle.GetUnit() == eCSSUnit_Enumerated) { + font->mFont.style = ourFont->mStyle.GetIntValue(); + } + + // font-variant: enum + if (ourFont->mVariant.GetUnit() == eCSSUnit_Enumerated) { + font->mFont.variant = ourFont->mVariant.GetIntValue(); + } + + // font-weight: abs, enum + if (ourFont->mWeight.GetUnit() == eCSSUnit_Absolute) { + font->mFont.style = ourFont->mWeight.GetIntValue(); + } + else if (ourFont->mWeight.GetUnit() == eCSSUnit_Enumerated) { + PRInt32 value = ourFont->mWeight.GetIntValue(); + switch (value) { + case NS_STYLE_FONT_WEIGHT_NORMAL: + case NS_STYLE_FONT_WEIGHT_BOLD: + font->mFont.weight = value; + break; + case NS_STYLE_FONT_WEIGHT_BOLDER: + case NS_STYLE_FONT_WEIGHT_LIGHTER: + font->mFont.weight = (parentFont->mFont.weight + value); + break; + } + } + + // font-size: enum, length, percent + if (ourFont->mSize.GetUnit() == eCSSUnit_Enumerated) { + static float kFontScale[7] = { + 0.5f, // xx-small + 0.666667f, // x-small + 0.833333f, // small + 1.0f, // medium + 1.5f, // large + 1.5f * 1.5f, // x-large + 1.5f * 1.5f * 1.5f, // xx-large + }; + PRInt32 value = ourFont->mSize.GetIntValue(); + + const nsFont& normal = aPresContext->GetDefaultFont(); // use normal font or body font?? + if ((NS_STYLE_FONT_SIZE_XXSMALL <= value) && + (value <= NS_STYLE_FONT_SIZE_XXLARGE)) { + font->mFont.size = (nscoord)((float)normal.size * kFontScale[value]); + } + else if (NS_STYLE_FONT_SIZE_LARGER == value) { + PRInt32 index; + for (index = NS_STYLE_FONT_SIZE_XXSMALL; + index < NS_STYLE_FONT_SIZE_XXLARGE; index++) + if (parentFont->mFont.size < (nscoord)((float)normal.size * kFontScale[index])) + break; + font->mFont.size = (nscoord)((float)normal.size * kFontScale[index]); + } + else if (NS_STYLE_FONT_SIZE_SMALLER == value) { + PRInt32 index; + for (index = NS_STYLE_FONT_SIZE_XXLARGE; + index > NS_STYLE_FONT_SIZE_XXSMALL; index--) + if (parentFont->mFont.size > (nscoord)((float)normal.size * kFontScale[index])) + break; + font->mFont.size = (nscoord)((float)normal.size * kFontScale[index]); + } + } + else if (ourFont->mSize.IsLengthUnit()) { + font->mFont.size = CalcLength(ourFont->mSize, parentFont, aPresContext); + } + else if (ourFont->mSize.GetUnit() == eCSSUnit_Percent) { + font->mFont.size = (nscoord)((float)(parentFont->mFont.size) * ourFont->mSize.GetFloatValue()); + } + + NS_IF_RELEASE(parentContext); + } + } + + nsCSSText* ourText; + if (NS_OK == mDeclaration->GetData(kCSSTextSID, (nsCSSStruct**)&ourText)) { + if (nsnull != ourText) { + + // text-decoration: enum, absolute (bit field) + if (ourText->mDecoration.GetUnit() == eCSSUnit_Enumerated) { + font->mFont.decorations = ourText->mDecoration.GetIntValue(); + } + else if (ourText->mDecoration.GetUnit() == eCSSUnit_Absolute) { + font->mFont.decorations = ourText->mDecoration.GetIntValue(); + } + } + } + + + nsCSSColor* ourColor; + if (NS_OK == mDeclaration->GetData(kCSSColorSID, (nsCSSStruct**)&ourColor)) { + if (nsnull != ourColor) { + nsStyleColor* color = (nsStyleColor*)aContext->GetData(kStyleColorSID); + + // color: color + if (ourColor->mColor.GetUnit() == eCSSUnit_Color) { + color->mColor = ourColor->mColor.GetColorValue(); + } + + // background-color: color, enum (flags) + if (ourColor->mBackColor.GetUnit() == eCSSUnit_Color) { + color->mBackgroundColor = ourColor->mBackColor.GetColorValue(); + color->mBackgroundFlags &= ~NS_STYLE_BG_COLOR_TRANSPARENT; + } + else if (ourColor->mBackColor.GetUnit() == eCSSUnit_Enumerated) { + color->mBackgroundFlags |= NS_STYLE_BG_COLOR_TRANSPARENT; + } + + // background-image: string, enum (flags) + if (ourColor->mBackImage.GetUnit() == eCSSUnit_String) { + ourColor->mBackImage.GetStringValue(color->mBackgroundImage); + color->mBackgroundFlags &= ~NS_STYLE_BG_IMAGE_NONE; + } + else if (ourColor->mBackImage.GetUnit() == eCSSUnit_Enumerated) { + color->mBackgroundFlags |= NS_STYLE_BG_IMAGE_NONE; + } + + // background-repeat: enum + if (ourColor->mBackRepeat.GetUnit() == eCSSUnit_Enumerated) { + color->mBackgroundRepeat = ourColor->mBackRepeat.GetIntValue(); + } + + // background-attachment: enum + if (ourColor->mBackAttachment.GetUnit() == eCSSUnit_Enumerated) { + color->mBackgroundAttachment = ourColor->mBackAttachment.GetIntValue(); + } + + // background-position: length, percent (flags) + if (ourColor->mBackPositionX.GetUnit() == eCSSUnit_Percent) { + color->mBackgroundXPosition = (nscoord)(TWIPS_CONST_FLOAT * ourColor->mBackPositionX.GetFloatValue()); + color->mBackgroundFlags |= NS_STYLE_BG_X_POSITION_PCT; + color->mBackgroundFlags &= ~NS_STYLE_BG_X_POSITION_LENGTH; + } + else if (ourColor->mBackPositionX.IsLengthUnit()) { + color->mBackgroundXPosition = CalcLength(ourColor->mBackPositionX, + font, aPresContext); + color->mBackgroundFlags |= NS_STYLE_BG_X_POSITION_LENGTH; + color->mBackgroundFlags &= ~NS_STYLE_BG_X_POSITION_PCT; + } + if (ourColor->mBackPositionY.GetUnit() == eCSSUnit_Percent) { + color->mBackgroundYPosition = (nscoord)(TWIPS_CONST_FLOAT * ourColor->mBackPositionY.GetFloatValue()); + color->mBackgroundFlags |= NS_STYLE_BG_Y_POSITION_PCT; + color->mBackgroundFlags &= ~NS_STYLE_BG_Y_POSITION_LENGTH; + } + else if (ourColor->mBackPositionY.IsLengthUnit()) { + color->mBackgroundYPosition = CalcLength(ourColor->mBackPositionY, + font, aPresContext); + color->mBackgroundFlags |= NS_STYLE_BG_Y_POSITION_LENGTH; + color->mBackgroundFlags &= ~NS_STYLE_BG_Y_POSITION_PCT; + } + + // XXX: NYI nsCSSValue mBackFilter; + } + } + + + nsCSSList* ourList; + if (NS_OK == mDeclaration->GetData(kCSSListSID, (nsCSSStruct**)&ourList)) { + if (nsnull != ourList) { + nsStyleList* list = (nsStyleList*)aContext->GetData(kStyleListSID); + + // list-style-type: enum + if (ourList->mType.GetUnit() == eCSSUnit_Enumerated) { + list->mListStyleType = ourList->mType.GetIntValue(); + } + + // list-style-image: string + if (ourList->mImage.GetUnit() == eCSSUnit_String) { + ourList->mImage.GetStringValue(list->mListStyleImage); + } + else if (ourList->mImage.GetUnit() == eCSSUnit_Enumerated) { // handle "none" + list->mListStyleImage = ""; + } + + // list-style-position: enum + if (ourList->mPosition.GetUnit() == eCSSUnit_Enumerated) { + list->mListStyleType = ourList->mPosition.GetIntValue(); + } + } + } + + } + +} + + + +static void ListSelector(FILE* out, const nsCSSSelector* aSelector) +{ + nsAutoString buffer; + + if (nsnull != aSelector->mTag) { + aSelector->mTag->ToString(buffer); + fputs(buffer, out); + } + if (nsnull != aSelector->mID) { + aSelector->mID->ToString(buffer); + fputs("#", out); + fputs(buffer, out); + } + if (nsnull != aSelector->mClass) { + aSelector->mClass->ToString(buffer); + fputs(".", out); + fputs(buffer, out); + } + if (nsnull != aSelector->mPseudoClass) { + aSelector->mPseudoClass->ToString(buffer); + fputs(":", out); + fputs(buffer, out); + } +} + +void CSSStyleRuleImpl::List(FILE* out, PRInt32 aIndent) const +{ + // Indent + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + const nsCSSSelector* selector = &mSelector; + + while (nsnull != selector) { + ListSelector(out, selector); + fputs(" ", out); + selector = selector->mNext; + } + + nsAutoString buffer; + + buffer.Append("weight: "); + buffer.Append(mWeight, 10); + buffer.Append(" "); + fputs(buffer, out); + if (nsnull != mDeclaration) { + mDeclaration->List(out); + } + else { + fputs("{ null declaration }", out); + } + fputs("\n", out); +} + +NS_HTML nsresult + NS_NewCSSStyleRule(nsICSSStyleRule** aInstancePtrResult, const nsCSSSelector& aSelector) +{ + if (aInstancePtrResult == nsnull) { + return NS_ERROR_NULL_POINTER; + } + + CSSStyleRuleImpl *it = new CSSStyleRuleImpl(aSelector); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(kICSSStyleRuleIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/layout/style/nsCSSStyleSheet.cpp b/mozilla/layout/style/nsCSSStyleSheet.cpp new file mode 100644 index 00000000000..14d80e149fe --- /dev/null +++ b/mozilla/layout/style/nsCSSStyleSheet.cpp @@ -0,0 +1,364 @@ +/* -*- 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 "nsICSSStyleSheet.h" +#include "nsIArena.h" +#include "nsCRT.h" +#include "nsIAtom.h" +#include "nsIURL.h" +#include "nsISupportsArray.h" +#include "nsICSSStyleRule.h" +#include "nsIHTMLContent.h" +#include "nsIFrame.h" +#include "nsString.h" + +static NS_DEFINE_IID(kICSSStyleSheetIID, NS_ICSS_STYLE_SHEET_IID); +static NS_DEFINE_IID(kIStyleSheetIID, NS_ISTYLE_SHEET_IID); +static NS_DEFINE_IID(kIStyleRuleIID, NS_ISTYLE_RULE_IID); +static NS_DEFINE_IID(kIHTMLContentIID, NS_IHTMLCONTENT_IID); + + +class CSSStyleSheetImpl : public nsICSSStyleSheet { +public: + void* operator new(size_t size); + void* operator new(size_t size, nsIArena* aArena); + void operator delete(void* ptr); + + CSSStyleSheetImpl(nsIURL* aURL); + + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + + virtual PRBool SelectorMatches(nsCSSSelector* aSelector, + nsIContent* aContent); + virtual PRInt32 RulesMatching(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsISupportsArray* aResults); + + virtual nsIURL* GetURL(void); + + virtual PRBool ContainsStyleSheet(nsIURL* aURL); + + virtual void AppendStyleSheet(nsICSSStyleSheet* aSheet); + + // XXX do these belong here or are they generic? + virtual void PrependStyleRule(nsICSSStyleRule* aRule); + virtual void AppendStyleRule(nsICSSStyleRule* aRule); + + // XXX style rule enumerations + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + +private: + // These are not supported and are not implemented! + CSSStyleSheetImpl(const CSSStyleSheetImpl& aCopy); + CSSStyleSheetImpl& operator=(const CSSStyleSheetImpl& aCopy); + +protected: + virtual ~CSSStyleSheetImpl(); + +protected: + PRUint32 mInHeap : 1; + PRUint32 mRefCnt : 31; + + nsIURL* mURL; + CSSStyleSheetImpl* mFirstChild; + nsISupportsArray* mRules; + CSSStyleSheetImpl* mNext; +}; + + +void* CSSStyleSheetImpl::operator new(size_t size) +{ + CSSStyleSheetImpl* rv = (CSSStyleSheetImpl*) ::operator new(size); +#ifdef NS_DEBUG + if (nsnull != rv) { + nsCRT::memset(rv, 0xEE, size); + } +#endif + rv->mInHeap = 1; + return (void*) rv; +} + +void* CSSStyleSheetImpl::operator new(size_t size, nsIArena* aArena) +{ + CSSStyleSheetImpl* rv = (CSSStyleSheetImpl*) aArena->Alloc(PRInt32(size)); +#ifdef NS_DEBUG + if (nsnull != rv) { + nsCRT::memset(rv, 0xEE, size); + } +#endif + rv->mInHeap = 0; + return (void*) rv; +} + +void CSSStyleSheetImpl::operator delete(void* ptr) +{ + CSSStyleSheetImpl* sheet = (CSSStyleSheetImpl*) ptr; + if (nsnull != sheet) { + if (sheet->mInHeap) { + ::delete ptr; + } + } +} + + + +CSSStyleSheetImpl::CSSStyleSheetImpl(nsIURL* aURL) + : nsICSSStyleSheet(), + mURL(aURL), mFirstChild(nsnull), mRules(nsnull), mNext(nsnull) +{ + NS_INIT_REFCNT(); + NS_ADDREF(mURL); +} + +CSSStyleSheetImpl::~CSSStyleSheetImpl() +{ + NS_RELEASE(mURL); + NS_IF_RELEASE(mFirstChild); + NS_IF_RELEASE(mRules); + NS_IF_RELEASE(mNext); +} + +NS_IMPL_ADDREF(CSSStyleSheetImpl) +NS_IMPL_RELEASE(CSSStyleSheetImpl) + +nsresult CSSStyleSheetImpl::QueryInterface(const nsIID& aIID, + void** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + if (aIID.Equals(kICSSStyleSheetIID)) { + *aInstancePtrResult = (void*) ((nsICSSStyleSheet*)this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIStyleSheetIID)) { + *aInstancePtrResult = (void*) ((nsIStyleSheet*)this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kISupportsIID)) { + *aInstancePtrResult = (void*) ((nsISupports*)this); + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +PRBool CSSStyleSheetImpl::SelectorMatches(nsCSSSelector* aSelector, nsIContent* aContent) +{ + PRBool result = PR_FALSE; + + if ((nsnull == aSelector->mTag) || (aSelector->mTag == aContent->GetTag())) { + if ((nsnull != aSelector->mClass) || (nsnull != aSelector->mTag)) { + nsIHTMLContent* htmlContent; + if (NS_OK == aContent->QueryInterface(kIHTMLContentIID, (void**)&htmlContent)) { + if ((nsnull == aSelector->mClass) || (aSelector->mClass == htmlContent->GetClass())) { + if ((nsnull == aSelector->mID) || (aSelector->mID == htmlContent->GetID())) { + result = PR_TRUE; + } + } + NS_RELEASE(htmlContent); + } + } + else { + result = PR_TRUE; + } + } + return result; +} + +PRInt32 CSSStyleSheetImpl::RulesMatching(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsISupportsArray* aResults) +{ + NS_PRECONDITION(nsnull != aPresContext, "null arg"); + NS_PRECONDITION(nsnull != aContent, "null arg"); +// NS_PRECONDITION(nsnull != aParentFrame, "null arg"); + NS_PRECONDITION(nsnull != aResults, "null arg"); + + PRInt32 matchCount = 0; + CSSStyleSheetImpl* child = mFirstChild; + while (nsnull != child) { + matchCount += child->RulesMatching(aPresContext, aContent, aParentFrame, aResults); + child = child->mNext; + } + + PRInt32 count = ((nsnull != mRules) ? mRules->Count() : 0); + + for (PRInt32 index = 0; index < count; index++) { + nsICSSStyleRule* rule = (nsICSSStyleRule*)mRules->ElementAt(index); + + nsCSSSelector* selector = rule->FirstSelector(); + if (SelectorMatches(selector, aContent)) { + selector = selector->mNext; + nsIFrame* frame = aParentFrame; + while ((nsnull != selector) && (nsnull != frame)) { // check compound selectors + nsIContent* content = frame->GetContent(); + if (SelectorMatches(selector, content)) { + selector = selector->mNext; + } + frame = frame->GetGeometricParent(); + NS_RELEASE(content); + } + if (nsnull == selector) { // ran out, it matched + nsIStyleRule* iRule; + if (NS_OK == rule->QueryInterface(kIStyleRuleIID, (void**)&iRule)) { + aResults->AppendElement(iRule); + NS_RELEASE(iRule); + matchCount++; + } + } + } + NS_RELEASE(rule); + } + return matchCount; +} + +nsIURL* CSSStyleSheetImpl::GetURL(void) +{ + NS_ADDREF(mURL); + return mURL; +} + +PRBool CSSStyleSheetImpl::ContainsStyleSheet(nsIURL* aURL) +{ + NS_PRECONDITION(nsnull != aURL, "null arg"); + + PRBool result = (*mURL == *aURL); + + CSSStyleSheetImpl* child = mFirstChild; + while ((PR_FALSE == result) && (nsnull != child)) { + result = child->ContainsStyleSheet(aURL); + child = child->mNext; + } + return result; +} + +void CSSStyleSheetImpl::AppendStyleSheet(nsICSSStyleSheet* aSheet) +{ + NS_PRECONDITION(nsnull != aSheet, "null arg"); + + if (nsnull == mFirstChild) { + mFirstChild = (CSSStyleSheetImpl*)aSheet; + } + else { + CSSStyleSheetImpl* child = mFirstChild; + while (nsnull != child->mNext) { + child = child->mNext; + } + child->mNext = (CSSStyleSheetImpl*)aSheet; + } + NS_ADDREF(aSheet); +} + +void CSSStyleSheetImpl::PrependStyleRule(nsICSSStyleRule* aRule) +{ + NS_PRECONDITION(nsnull != aRule, "null arg"); + NS_ADDREF(aRule); + //XXX replace this with a binary search? + PRInt32 weight = aRule->GetWeight(); + if (nsnull == mRules) { + if (NS_OK != NS_NewISupportsArray(&mRules)) + return; + } + PRInt32 index = mRules->Count(); + while (0 <= --index) { + nsICSSStyleRule* rule = (nsICSSStyleRule*)mRules->ElementAt(index); + if (rule->GetWeight() > weight) { // insert before rules with equal or lesser weight + NS_RELEASE(rule); + break; + } + NS_RELEASE(rule); + } + mRules->InsertElementAt(aRule, index + 1); +} + +void CSSStyleSheetImpl::AppendStyleRule(nsICSSStyleRule* aRule) +{ + NS_PRECONDITION(nsnull != aRule, "null arg"); + NS_ADDREF(aRule); + + //XXX replace this with a binary search? + PRInt32 weight = aRule->GetWeight(); + if (nsnull == mRules) { + if (NS_OK != NS_NewISupportsArray(&mRules)) + return; + } + PRInt32 count = mRules->Count(); + PRInt32 index = -1; + while (++index < count) { + nsICSSStyleRule* rule = (nsICSSStyleRule*)mRules->ElementAt(index); + if (rule->GetWeight() < weight) { // insert after rules with equal or greater weight (before lower weight) + NS_RELEASE(rule); + break; + } + NS_RELEASE(rule); + } + mRules->InsertElementAt(aRule, index); +} + +void CSSStyleSheetImpl::List(FILE* out, PRInt32 aIndent) const +{ + nsAutoString buffer; + PRInt32 index; + + // Indent + for (index = aIndent; --index >= 0; ) fputs(" ", out); + + fputs("CSS Style Sheet: ", out); + mURL->ToString(buffer); + fputs(buffer, out); + fputs("\n", out); + + CSSStyleSheetImpl* child = mFirstChild; + while (nsnull != child) { + child->List(out, aIndent + 1); + child = child->mNext; + } + + PRInt32 count = ((nsnull != mRules) ? mRules->Count() : 0); + + for (index = 0; index < count; index++) { + nsICSSStyleRule* rule = (nsICSSStyleRule*)mRules->ElementAt(index); + rule->List(out, aIndent); + NS_RELEASE(rule); + } +} + +NS_HTML nsresult + NS_NewCSSStyleSheet(nsICSSStyleSheet** aInstancePtrResult, nsIURL* aURL) +{ + if (aInstancePtrResult == nsnull) { + return NS_ERROR_NULL_POINTER; + } + + CSSStyleSheetImpl *it = new CSSStyleSheetImpl(aURL); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(kICSSStyleSheetIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/layout/style/nsHTMLStyleSheet.cpp b/mozilla/layout/style/nsHTMLStyleSheet.cpp new file mode 100644 index 00000000000..687a1030ee4 --- /dev/null +++ b/mozilla/layout/style/nsHTMLStyleSheet.cpp @@ -0,0 +1,214 @@ +/* -*- 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 "nsIHTMLStyleSheet.h" +#include "nsIArena.h" +#include "nsCRT.h" +#include "nsIAtom.h" +#include "nsIURL.h" +#include "nsISupportsArray.h" +#include "nsIHTMLContent.h" +#include "nsIStyleRule.h" + +static NS_DEFINE_IID(kIHTMLStyleSheetIID, NS_IHTML_STYLE_SHEET_IID); +static NS_DEFINE_IID(kIStyleSheetIID, NS_ISTYLE_SHEET_IID); +static NS_DEFINE_IID(kIHTMLContentIID, NS_IHTMLCONTENT_IID); + + +class HTMLStyleSheetImpl : public nsIHTMLStyleSheet { +public: + void* operator new(size_t size); + void* operator new(size_t size, nsIArena* aArena); + void operator delete(void* ptr); + + HTMLStyleSheetImpl(nsIURL* aURL); + + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + + virtual PRInt32 RulesMatching(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsISupportsArray* aResults); + + virtual nsIURL* GetURL(void); + + // XXX style rule enumerations + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + +private: + // These are not supported and are not implemented! + HTMLStyleSheetImpl(const HTMLStyleSheetImpl& aCopy); + HTMLStyleSheetImpl& operator=(const HTMLStyleSheetImpl& aCopy); + +protected: + virtual ~HTMLStyleSheetImpl(); + +protected: + PRUint32 mInHeap : 1; + PRUint32 mRefCnt : 31; + + nsIURL* mURL; +}; + + +void* HTMLStyleSheetImpl::operator new(size_t size) +{ + HTMLStyleSheetImpl* rv = (HTMLStyleSheetImpl*) ::operator new(size); +#ifdef NS_DEBUG + if (nsnull != rv) { + nsCRT::memset(rv, 0xEE, size); + } +#endif + rv->mInHeap = 1; + return (void*) rv; +} + +void* HTMLStyleSheetImpl::operator new(size_t size, nsIArena* aArena) +{ + HTMLStyleSheetImpl* rv = (HTMLStyleSheetImpl*) aArena->Alloc(PRInt32(size)); +#ifdef NS_DEBUG + if (nsnull != rv) { + nsCRT::memset(rv, 0xEE, size); + } +#endif + rv->mInHeap = 0; + return (void*) rv; +} + +void HTMLStyleSheetImpl::operator delete(void* ptr) +{ + HTMLStyleSheetImpl* sheet = (HTMLStyleSheetImpl*) ptr; + if (nsnull != sheet) { + if (sheet->mInHeap) { + ::delete ptr; + } + } +} + + + +HTMLStyleSheetImpl::HTMLStyleSheetImpl(nsIURL* aURL) + : nsIHTMLStyleSheet(), + mURL(aURL) +{ + NS_INIT_REFCNT(); + NS_ADDREF(mURL); +} + +HTMLStyleSheetImpl::~HTMLStyleSheetImpl() +{ + NS_RELEASE(mURL); +} + +NS_IMPL_ADDREF(HTMLStyleSheetImpl) +NS_IMPL_RELEASE(HTMLStyleSheetImpl) + +nsresult HTMLStyleSheetImpl::QueryInterface(const nsIID& aIID, + void** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + if (aIID.Equals(kIHTMLStyleSheetIID)) { + *aInstancePtrResult = (void*) ((nsIHTMLStyleSheet*)this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIStyleSheetIID)) { + *aInstancePtrResult = (void*) ((nsIStyleSheet*)this); + AddRef(); + return NS_OK; + } + if (aIID.Equals(kISupportsIID)) { + *aInstancePtrResult = (void*) ((nsISupports*)this); + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +PRInt32 HTMLStyleSheetImpl::RulesMatching(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsISupportsArray* aResults) +{ + NS_PRECONDITION(nsnull != aPresContext, "null arg"); + NS_PRECONDITION(nsnull != aContent, "null arg"); +// NS_PRECONDITION(nsnull != aParentFrame, "null arg"); + NS_PRECONDITION(nsnull != aResults, "null arg"); + + PRInt32 matchCount = 0; + + nsIHTMLContent* htmlContent; + + // for now, just get the one and only style rule from the content + // this may need some special handling for pseudo-frames + if (NS_OK == aContent->QueryInterface(kIHTMLContentIID, (void**)&htmlContent)) { + nsIStyleRule* rule = htmlContent->GetStyleRule(); + + if (nsnull != rule) { + aResults->AppendElement(rule); + NS_RELEASE(rule); + matchCount++; + } + + NS_RELEASE(htmlContent); + } + + return matchCount; +} + +nsIURL* HTMLStyleSheetImpl::GetURL(void) +{ + NS_ADDREF(mURL); + return mURL; +} + +void HTMLStyleSheetImpl::List(FILE* out, PRInt32 aIndent) const +{ + nsAutoString buffer; + + // Indent + for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out); + + fputs("HTML Style Sheet: ", out); + mURL->ToString(buffer); + fputs(buffer, out); + fputs("\n", out); + +} + +NS_HTML nsresult + NS_NewHTMLStyleSheet(nsIHTMLStyleSheet** aInstancePtrResult, nsIURL* aURL) +{ + if (aInstancePtrResult == nsnull) { + return NS_ERROR_NULL_POINTER; + } + + HTMLStyleSheetImpl *it = new HTMLStyleSheetImpl(aURL); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(kIHTMLStyleSheetIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/layout/style/nsICSSParser.h b/mozilla/layout/style/nsICSSParser.h new file mode 100644 index 00000000000..e9b21f10215 --- /dev/null +++ b/mozilla/layout/style/nsICSSParser.h @@ -0,0 +1,56 @@ +/* -*- 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. + */ +#ifndef nsCSS1Parser_h___ +#define nsCSS1Parser_h___ + +#include "nslayout.h" +#include "nsISupports.h" +class nsIStyleSheet; +class nsIUnicharInputStream; +class nsIURL; + +#define NS_ICSS_PARSER_IID \ +{ 0xcc9c0610, 0x968c, 0x11d1, \ + {0x93, 0x23, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +// Interface to the css parser. +class nsICSSParser : public nsISupports { +public: + // Return a mask of the various css standards that this parser + // supports. + virtual PRUint32 GetInfoMask() = 0; + + // Set a style sheet for the parser to fill in. The style sheet must + // implement the nsICSSStyleSheet interface + virtual nsresult SetStyleSheet(nsIStyleSheet* aSheet) = 0; + + virtual nsIStyleSheet* Parse(PRInt32* aErrorCode, + nsIUnicharInputStream* aInput, + nsIURL* aInputURL) = 0; +}; + +// Values or'd in the GetInfoMask; other bits are reserved +#define NS_CSS_GETINFO_CSS1 ((PRUint32) 0x00000001L) +#define NS_CSS_GETINFO_CSSP ((PRUint32) 0x00000002L) +#define NS_CSS_GETINFO_CSS2 ((PRUint32) 0x00000004L) +#define NS_CSS_GETINFO_CSS_FROSTING ((PRUint32) 0x00000008L) + +extern NS_HTML nsresult + NS_NewCSSParser(nsICSSParser** aInstancePtrResult); + +#endif /* nsCSS1Parser_h___ */ diff --git a/mozilla/layout/style/nsICSSStyleRule.h b/mozilla/layout/style/nsICSSStyleRule.h new file mode 100644 index 00000000000..153397fe876 --- /dev/null +++ b/mozilla/layout/style/nsICSSStyleRule.h @@ -0,0 +1,76 @@ +/* -*- 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. + */ +#ifndef nsICSSStyleRule_h___ +#define nsICSSStyleRule_h___ + +#include +#include "nslayout.h" +#include "nsIStyleRule.h" +class nsIAtom; +class nsIArena; +class nsString; +class nsICSSDeclaration; + + +struct nsCSSSelector { +public: + nsCSSSelector(); + nsCSSSelector(nsIAtom* aTag, nsIAtom* aID, nsIAtom* aClass, nsIAtom* aPseudoClass); + nsCSSSelector(const nsCSSSelector& aCopy); + ~nsCSSSelector(); + + nsCSSSelector& operator=(const nsCSSSelector& aCopy); + PRBool Equals(const nsCSSSelector* aOther) const; + + void Set(const nsString& aTag, const nsString& aID, const nsString& aClass, const nsString& aPseudoClass); + +public: + nsIAtom* mTag; + nsIAtom* mID; + nsIAtom* mClass; // this'll have to be an array for CSS2 + nsIAtom* mPseudoClass; + + nsCSSSelector* mNext; +}; + +// IID for the nsICSSStyleRule interface {7c277af0-af19-11d1-8031-006008159b5a} +#define NS_ICSS_STYLE_RULE_IID \ +{0x7c277af0, 0xaf19, 0x11d1, {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}} + +class nsICSSStyleRule : public nsIStyleRule { +public: + virtual PRBool Equals(const nsIStyleRule* aRule) const = 0; + virtual PRUint32 HashValue(void) const = 0; + + virtual nsCSSSelector* FirstSelector(void) = 0; + virtual void AddSelector(const nsCSSSelector& aSelector) = 0; + virtual void DeleteSelector(nsCSSSelector* aSelector) = 0; + + virtual nsICSSDeclaration* GetDeclaration(void) const = 0; + virtual void SetDeclaration(nsICSSDeclaration* aDeclaration) = 0; + + virtual PRInt32 GetWeight(void) const = 0; + virtual void SetWeight(PRInt32 aWeight) = 0; + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const = 0; +}; + +extern NS_HTML nsresult + NS_NewCSSStyleRule(nsICSSStyleRule** aInstancePtrResult, const nsCSSSelector& aSelector); + +#endif /* nsICSSStyleRule_h___ */ diff --git a/mozilla/layout/style/nsIStyleRule.h b/mozilla/layout/style/nsIStyleRule.h new file mode 100644 index 00000000000..e79eff7dae8 --- /dev/null +++ b/mozilla/layout/style/nsIStyleRule.h @@ -0,0 +1,43 @@ +/* -*- 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. + */ +#ifndef nsIStyleRule_h___ +#define nsIStyleRule_h___ + +#include + +#include "nslayout.h" +#include "nsISupports.h" + +class nsIStyleContext; +class nsIPresContext; + +// IID for the nsIStyleRule interface {40ae5c90-ad6a-11d1-8031-006008159b5a} +#define NS_ISTYLE_RULE_IID \ +{0x40ae5c90, 0xad6a, 0x11d1, {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}} + +class nsIStyleRule : public nsISupports { +public: + virtual PRBool Equals(const nsIStyleRule* aRule) const = 0; + virtual PRUint32 HashValue(void) const = 0; + + virtual void MapStyleInto(nsIStyleContext* aContext, nsIPresContext* aPresContext) = 0; + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const = 0; +}; + +#endif /* nsIStyleRule_h___ */ diff --git a/mozilla/layout/style/nsIStyleSheet.h b/mozilla/layout/style/nsIStyleSheet.h new file mode 100644 index 00000000000..bac20159aa0 --- /dev/null +++ b/mozilla/layout/style/nsIStyleSheet.h @@ -0,0 +1,50 @@ +/* -*- 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. + */ +#ifndef nsIStyleSheet_h___ +#define nsIStyleSheet_h___ + +#include +#include "nsISupports.h" +class nsIAtom; +class nsIURL; +class nsIStyleRule; +class nsISupportsArray; +class nsIPresContext; +class nsIContent; +class nsIFrame; + +// IID for the nsIStyleSheet interface {8c4a80a0-ad6a-11d1-8031-006008159b5a} +#define NS_ISTYLE_SHEET_IID \ +{0x8c4a80a0, 0xad6a, 0x11d1, {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}} + +class nsIStyleSheet : public nsISupports { +public: + virtual nsIURL* GetURL(void) = 0; + + // populate void array with nsIStyleRule* + virtual PRInt32 RulesMatching(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsISupportsArray* aResults) = 0; + + // XXX style rule enumerations + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const = 0; +}; + +#endif /* nsIStyleSheet_h___ */ diff --git a/mozilla/layout/style/nsStyleContext.cpp b/mozilla/layout/style/nsStyleContext.cpp new file mode 100644 index 00000000000..bf44521a48e --- /dev/null +++ b/mozilla/layout/style/nsStyleContext.cpp @@ -0,0 +1,613 @@ +/* -*- 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 "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsString.h" +#include "nsUnitConversion.h" +#include "nsIContent.h" +#include "nsIPresContext.h" +#include "nsIStyleRule.h" +#include "nsISupportsArray.h" +#include "nsCRT.h" + +#include "nsIFrame.h" + + +#ifdef NS_DEBUG +static PRBool gsDebug = PR_FALSE; +#else +static const PRBool gsDebug = PR_FALSE; +#endif + + +static NS_DEFINE_IID(kStyleFontSID, NS_STYLEFONT_SID); +static NS_DEFINE_IID(kStyleColorSID, NS_STYLECOLOR_SID); +static NS_DEFINE_IID(kStyleListSID, NS_STYLELIST_SID); +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID); + +static NS_DEFINE_IID(kIStyleContextIID, NS_ISTYLECONTEXT_IID); + +nsStyleFont::nsStyleFont(const nsFont& aFont) + : mFont(aFont) +{ +} + +nsStyleFont::~nsStyleFont(void) +{ +} + +struct StyleFontImpl : public nsStyleFont { + StyleFontImpl(const nsFont& aFont) + : nsStyleFont(aFont) + {} + ~StyleFontImpl() + {} + + virtual const nsID& GetID(void) + { return kStyleFontSID; } + + virtual void InheritFrom(const nsStyleFont& aCopy); + +private: // These are not allowed + StyleFontImpl(const StyleFontImpl& aOther); + StyleFontImpl& operator=(const StyleFontImpl& aOther); +}; + +void StyleFontImpl::InheritFrom(const nsStyleFont& aCopy) +{ + mFont = aCopy.mFont; + mThreeD = aCopy.mThreeD; +} + +struct StyleColorImpl: public nsStyleColor { + StyleColorImpl(void) + { + mBackgroundAttachment = NS_STYLE_BG_ATTACHMENT_SCROLL; + mBackgroundFlags = NS_STYLE_BG_COLOR_TRANSPARENT; + mBackgroundRepeat = NS_STYLE_BG_REPEAT_OFF; + + mBackgroundColor = NS_RGB(192,192,192); + } + + ~StyleColorImpl(void) + {} + + virtual const nsID& GetID(void) + { return kStyleColorSID; } + + virtual void InheritFrom(const nsStyleColor& aCopy); + +private: // These are not allowed + StyleColorImpl(const StyleColorImpl& aOther); + StyleColorImpl& operator=(const StyleColorImpl& aOther); +}; + +void StyleColorImpl::InheritFrom(const nsStyleColor& aCopy) +{ + mColor = aCopy.mColor; + + mBackgroundFlags = NS_STYLE_BG_COLOR_TRANSPARENT; +} + + +struct StyleListImpl: public nsStyleList { + StyleListImpl(void) + { + mListStyleType = NS_STYLE_LIST_STYLE_BASIC; + mListStylePosition = NS_STYLE_LIST_STYLE_POSITION_OUTSIDE; + } + + ~StyleListImpl(void) + { + } + + virtual const nsID& GetID(void) + { return kStyleListSID; } + + virtual void InheritFrom(const nsStyleList& aCopy); +}; + +void StyleListImpl::InheritFrom(const nsStyleList& aCopy) +{ + mListStyleType = aCopy.mListStyleType; + mListStyleImage = aCopy.mListStyleImage; + mListStylePosition = aCopy.mListStylePosition; +} + +nsStyleMolecule::nsStyleMolecule() +{ +} + +nsStyleMolecule::~nsStyleMolecule() +{ +} + +struct StyleMoleculeImpl : public nsStyleMolecule { + StyleMoleculeImpl(void) + {} + ~StyleMoleculeImpl(void) + {} + + virtual const nsID& GetID(void) + { return kStyleMoleculeSID; } + + virtual void InheritFrom(const nsStyleMolecule& aCopy); + +private: // These are not allowed + StyleMoleculeImpl(const StyleMoleculeImpl& aOther); + StyleMoleculeImpl& operator=(const StyleMoleculeImpl& aOther); +}; + +void StyleMoleculeImpl::InheritFrom(const nsStyleMolecule& aCopy) +{ + cursor = aCopy.cursor; + direction = aCopy.direction; + + textDecoration = aCopy.textDecoration; + + textAlign = aCopy.textAlign; + whiteSpace = aCopy.whiteSpace; + +// lineHeight = aCopy.lineHeight; +} + + +//---------------------------------------------------------------------- + +class StyleContextImpl : public nsIStyleContext { +public: + StyleContextImpl(nsIStyleContext* aParent, nsISupportsArray* aRules, nsIPresContext* aPresContext); + ~StyleContextImpl(); + + void* operator new(size_t sz) { + void* rv = new char[sz]; + nsCRT::zero(rv, sz); + return rv; + } + + NS_DECL_ISUPPORTS + + virtual nsIStyleContext* GetParent(void) const; + virtual nsISupportsArray* GetStyleRules(void) const; + + virtual PRBool Equals(const nsIStyleContext* aOther) const; + virtual PRUint32 HashValue(void) const; + + virtual nsStyleStruct* GetData(const nsIID& aSID); + + virtual void InheritFrom(const StyleContextImpl& aParent); + + virtual void HackStyleFor(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aFrame); + + nsIStyleContext* mParent; + PRUint32 mHashValid: 1; + PRUint32 mHashValue: 31; + nsISupportsArray* mRules; + + // the style data... + StyleFontImpl mFont; + StyleColorImpl mColor; + StyleListImpl mList; +// xxx backward support hack + StyleMoleculeImpl mMolecule; +}; + +StyleContextImpl::StyleContextImpl(nsIStyleContext* aParent, nsISupportsArray* aRules, + nsIPresContext* aPresContext) + : mParent(aParent), // weak ref + mRules(aRules), + mFont(aPresContext->GetDefaultFont()), + mColor(), + mList(), + mMolecule() +{ + NS_INIT_REFCNT(); + NS_IF_ADDREF(mRules); + + if (nsnull != aParent) { + InheritFrom((StyleContextImpl&)*aParent); + } + + if (nsnull != mRules) { + PRInt32 index = mRules->Count(); + while (0 < index) { + nsIStyleRule* rule = (nsIStyleRule*)mRules->ElementAt(--index); + rule->MapStyleInto(this, aPresContext); + NS_RELEASE(rule); + } + } +} + +StyleContextImpl::~StyleContextImpl() +{ + mParent = nsnull; // weak ref + NS_IF_RELEASE(mRules); +} + +NS_IMPL_ISUPPORTS(StyleContextImpl, kIStyleContextIID) + +nsIStyleContext* StyleContextImpl::GetParent(void) const +{ + NS_IF_ADDREF(mParent); + return mParent; +} + +nsISupportsArray* StyleContextImpl::GetStyleRules(void) const +{ + NS_IF_ADDREF(mRules); + return mRules; +} + + +PRBool StyleContextImpl::Equals(const nsIStyleContext* aOther) const +{ + PRBool result = PR_TRUE; + const StyleContextImpl* other = (StyleContextImpl*)aOther; + + if (other != this) { + if (mParent != other->mParent) { + result = PR_FALSE; + } + else { + if ((nsnull != mRules) && (nsnull != other->mRules)) { + result = mRules->Equals(other->mRules); + } + else { + result = PRBool((nsnull == mRules) && (nsnull == other->mRules)); + } + } + } + return result; +} + +PRUint32 StyleContextImpl::HashValue(void) const +{ + if (0 == mHashValid) { + ((StyleContextImpl*)this)->mHashValue = ((nsnull != mParent) ? mParent->HashValue() : 0); + if (nsnull != mRules) { + PRInt32 index = mRules->Count(); + while (0 <= --index) { + nsIStyleRule* rule = (nsIStyleRule*)mRules->ElementAt(index); + PRUint32 hash = rule->HashValue(); + ((StyleContextImpl*)this)->mHashValue ^= (hash & 0x7FFFFFFF); + NS_RELEASE(rule); + } + } + ((StyleContextImpl*)this)->mHashValid = 1; + } + return mHashValue; +} + + +nsStyleStruct* StyleContextImpl::GetData(const nsIID& aSID) +{ + if (aSID.Equals(kStyleFontSID)) { + return &mFont; + } + if (aSID.Equals(kStyleColorSID)) { + return &mColor; + } + if (aSID.Equals(kStyleListSID)) { + return &mList; + } + if (aSID.Equals(kStyleMoleculeSID)) { + return &mMolecule; + } + return nsnull; +} + +void StyleContextImpl::InheritFrom(const StyleContextImpl& aParent) +{ + mFont.InheritFrom(aParent.mFont); + mColor.InheritFrom(aParent.mColor); + mList.InheritFrom(aParent.mList); + mMolecule.InheritFrom(aParent.mMolecule); +} + +void StyleContextImpl::HackStyleFor(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame) +{ +/* + mColor.mColor = NS_RGB(0, 0, 0); +*/ + + mMolecule.display = NS_STYLE_DISPLAY_BLOCK; + mMolecule.whiteSpace = NS_STYLE_WHITESPACE_NORMAL; + mMolecule.verticalAlign = NS_STYLE_VERTICAL_ALIGN_BASELINE; + mMolecule.textAlign = NS_STYLE_TEXT_ALIGN_LEFT; + + mMolecule.positionFlags = NS_STYLE_POSITION_STATIC; + mMolecule.floats = 0; + + // XXX If it's a B guy then make it inline + nsIAtom* tag = aContent->GetTag(); + nsAutoString buf; + if (tag != nsnull) { + tag->ToString(buf); + NS_RELEASE(tag); + if (buf.EqualsIgnoreCase("B")) { +// float p2t = aPresContext->GetPixelsToTwips(); + mMolecule.display = NS_STYLE_DISPLAY_INLINE; +// mColor.mBackgroundColor = NS_RGB(128, 128, 255); +// mColor.mBackgroundFlags = 0; +// mMolecule.border.top = nscoord(5 * p2t); +// mMolecule.border.right = nscoord(5 * p2t); +// mMolecule.border.bottom = nscoord(5 * p2t); +// mMolecule.border.left = nscoord(5 * p2t); +// for (int i = 0; i < 4; i++) { +// mMolecule.borderStyle[i] = NS_STYLE_BORDER_STYLE_INSET; +// mMolecule.borderColor[i] = NS_RGB(128, 128, 128); +// } + } else if (buf.EqualsIgnoreCase("A")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + mMolecule.cursor = NS_STYLE_CURSOR_HAND; + } else if (buf.EqualsIgnoreCase("BR")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + nsString align("CLEAR"); + nsString value; + if (eContentAttr_HasValue == aContent->GetAttribute(align, value)) { + if (0 == value.Compare("left", PR_TRUE)) { + mMolecule.clear = NS_STYLE_CLEAR_LEFT; + } else if (0 == value.Compare("right", PR_TRUE)) { + mMolecule.clear = NS_STYLE_CLEAR_RIGHT; + } else if (0 == value.Compare("all", PR_TRUE)) { + mMolecule.clear = NS_STYLE_CLEAR_BOTH; + } + } + } else if (buf.EqualsIgnoreCase("SPACER")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + } else if (buf.EqualsIgnoreCase("WBR")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + } else if (buf.EqualsIgnoreCase("INPUT")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + } else if (buf.EqualsIgnoreCase("I")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + } else if (buf.EqualsIgnoreCase("S")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + } else if (buf.EqualsIgnoreCase("PRE")) { + mMolecule.whiteSpace = NS_STYLE_WHITESPACE_PRE; + mMolecule.margin.top = NS_POINTS_TO_TWIPS_INT(3); + mMolecule.margin.bottom = NS_POINTS_TO_TWIPS_INT(3); +// mColor.mBackgroundImage = "resource:/res/gear1.gif"; +// mColor.mBackgroundRepeat = NS_STYLE_BG_REPEAT_XY; + } else if (buf.EqualsIgnoreCase("U")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + } else if (buf.EqualsIgnoreCase("FONT")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + } else if (buf.EqualsIgnoreCase("THREED")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + mFont.mThreeD = 1; + } else if (buf.EqualsIgnoreCase("TT")) { + mMolecule.display = NS_STYLE_DISPLAY_INLINE; +// mFont.mFont.name.SetLength(0); +// mFont.mFont.name.Append("Courier"); +// mMolecule.positionFlags = NS_STYLE_POSITION_RELATIVE; +// mMolecule.left = -50; +// mMolecule.top = -50; + } else if (buf.EqualsIgnoreCase("IMG")) { + float p2t = aPresContext->GetPixelsToTwips(); + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + mMolecule.padding.top = nscoord(2 * p2t); + mMolecule.padding.right = nscoord(2 * p2t); + mMolecule.padding.bottom = nscoord(2 * p2t); + mMolecule.padding.left = nscoord(2 * p2t); + nsString align("ALIGN"); + nsString value; + if (eContentAttr_HasValue == aContent->GetAttribute(align, value)) { + if (0 == value.Compare("left", PR_TRUE)) { + mMolecule.floats = NS_STYLE_FLOAT_LEFT; + } else if (0 == value.Compare("right", PR_TRUE)) { + mMolecule.floats = NS_STYLE_FLOAT_RIGHT; + } + } + } else if (buf.EqualsIgnoreCase("P")) { + // mMolecule.textAlign = NS_STYLE_TEXT_ALIGN_CENTER; + mMolecule.margin.top = NS_POINTS_TO_TWIPS_INT(2); + mMolecule.margin.bottom = NS_POINTS_TO_TWIPS_INT(2); + } else if (buf.EqualsIgnoreCase("BODY")) { + float p2t = aPresContext->GetPixelsToTwips(); +// mColor.mBackgroundColor = NS_RGB(255, 255, 255); +// mColor.mBackgroundFlags = 0; + //mColor.mBackgroundFlags = 0; + //mColor.mBackgroundImage = "resource:/res/rock_gra.gif"; + //mColor.mBackgroundRepeat = NS_STYLE_BG_REPEAT_XY; + mMolecule.padding.top = nscoord(5 * p2t); + mMolecule.padding.right = nscoord(5 * p2t); + mMolecule.padding.bottom = nscoord(5 * p2t); + mMolecule.padding.left = nscoord(5 * p2t); + mMolecule.border.top = nscoord(1 * p2t); + mMolecule.border.right = nscoord(1 * p2t); + mMolecule.border.bottom = nscoord(1 * p2t); + mMolecule.border.left = nscoord(1 * p2t); + for (int i = 0; i < 4; i++) { + mMolecule.borderStyle[i] = NS_STYLE_BORDER_STYLE_SOLID; + mMolecule.borderColor[i] = NS_RGB(0, 255, 0); + } + } else if (buf.EqualsIgnoreCase("LI")) { + mMolecule.display = NS_STYLE_DISPLAY_LIST_ITEM; + } else if (buf.EqualsIgnoreCase("UL") || buf.EqualsIgnoreCase("OL")) { + float p2t = aPresContext->GetPixelsToTwips(); + mMolecule.padding.left = nscoord(40 * p2t); + mMolecule.margin.top = NS_POINTS_TO_TWIPS_INT(5); + mMolecule.margin.bottom = NS_POINTS_TO_TWIPS_INT(5); + } else if (buf.EqualsIgnoreCase("TABLE")) { // TABLE + mMolecule.border.top = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.border.bottom = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.border.right = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.border.left = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.borderStyle[0] = mMolecule.borderStyle[1] = + mMolecule.borderStyle[2] = mMolecule.borderStyle[3] = NS_STYLE_BORDER_STYLE_SOLID; + mMolecule.fixedWidth = -1; + mMolecule.proportionalWidth = 100; + nsString align("ALIGN"); + nsString value; + if (eContentAttr_HasValue == aContent->GetAttribute(align, value)) { + if (0 == value.Compare("left", PR_TRUE)) { + mMolecule.floats = NS_STYLE_FLOAT_LEFT; + } else if (0 == value.Compare("right", PR_TRUE)) { + mMolecule.floats = NS_STYLE_FLOAT_RIGHT; + } + } + } else if (buf.EqualsIgnoreCase("CAPTION")) { // CAPTION + mMolecule.verticalAlign = NS_STYLE_VERTICAL_ALIGN_TOP; + } else if (buf.EqualsIgnoreCase("TBODY")) { // TBODY + mMolecule.padding.top = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.padding.bottom = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.padding.right = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.padding.left = NS_POINTS_TO_TWIPS_INT(1); + } else if (buf.EqualsIgnoreCase("TR")) { // TROW + mMolecule.padding.top = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.padding.bottom = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.padding.right = NS_POINTS_TO_TWIPS_INT(1); + mMolecule.padding.left = NS_POINTS_TO_TWIPS_INT(1); + } else if (buf.EqualsIgnoreCase("TD")) { // TD + float p2t = aPresContext->GetPixelsToTwips(); + + + // Set padding to twenty for testing purposes + int cellPadding = 1; + if (gsDebug==PR_TRUE) + cellPadding = 20; + mMolecule.verticalAlign = NS_STYLE_VERTICAL_ALIGN_MIDDLE; + + mMolecule.padding.top = NS_POINTS_TO_TWIPS_INT(cellPadding); + mMolecule.padding.bottom = NS_POINTS_TO_TWIPS_INT(cellPadding); + mMolecule.padding.right = NS_POINTS_TO_TWIPS_INT(cellPadding); + mMolecule.padding.left = NS_POINTS_TO_TWIPS_INT(cellPadding); +// mColor.mBackgroundColor = NS_RGB(255, 255, 0); +// mColor.mBackgroundFlags = 0; + mMolecule.border.top = nscoord(1 * p2t); + mMolecule.border.right = nscoord(1 * p2t); + mMolecule.border.bottom = nscoord(1 * p2t); + mMolecule.border.left = nscoord(1 * p2t); + for (int i = 0; i < 4; i++) { + mMolecule.borderStyle[i] = NS_STYLE_BORDER_STYLE_SOLID; + mMolecule.borderColor[i] = NS_RGB(128, 128, 128); + } + mMolecule.fixedWidth = -1; + mMolecule.proportionalWidth = -1; + mMolecule.fixedHeight = -1; + mMolecule.proportionalHeight = -1; + + } else if (buf.EqualsIgnoreCase("COL")) { + mMolecule.fixedWidth = -1; + mMolecule.proportionalWidth = -1; + mMolecule.fixedHeight = -1; + mMolecule.proportionalHeight = -1; + } + } else { + // It's text (!) + mMolecule.display = NS_STYLE_DISPLAY_INLINE; + mMolecule.cursor = NS_STYLE_CURSOR_IBEAM; + nsIContent* content = aParentFrame->GetContent(); + nsIAtom* parentTag = content->GetTag(); + parentTag->ToString(buf); + NS_RELEASE(content); + NS_RELEASE(parentTag); + if (buf.EqualsIgnoreCase("B")) { +// mFont.mFont.size = NS_POINTS_TO_TWIPS_INT(18); +// mFont.mFont.weight = NS_FONT_WEIGHT_BOLD; + } else if (buf.EqualsIgnoreCase("A")) { +// mColor.mColor = NS_RGB(0,0,255); +// mFont.mFont.decorations = NS_FONT_DECORATION_UNDERLINE; + // This simulates a
    text inheritance rule
    +      // Check the parent of the A
    +      nsIFrame* parentParentFrame = aParentFrame->GetGeometricParent();
    +      if (nsnull != parentParentFrame) {
    +        nsIContent* parentParentContent = parentParentFrame->GetContent();
    +        nsIAtom* parentParentTag = parentParentContent->GetTag();
    +        parentParentTag->ToString(buf);
    +        NS_RELEASE(parentParentTag);
    +        NS_RELEASE(parentParentContent);
    +        if (buf.EqualsIgnoreCase("PRE")) {
    +          mMolecule.whiteSpace = NS_STYLE_WHITESPACE_PRE;
    +//          mFont.mFont.name.SetLength(0);
    +//          mFont.mFont.name.Append("Courier");
    +        }
    +      }
    +    } else if (buf.EqualsIgnoreCase("THREED")) {
    +//      mFont.mFont.size = NS_POINTS_TO_TWIPS_INT(18);
    +//      mFont.mFont.weight = NS_FONT_WEIGHT_BOLD;
    +      mFont.mThreeD = 1;
    +    } else if (buf.EqualsIgnoreCase("I")) {
    +//      mFont.mFont.style = NS_FONT_STYLE_ITALIC;
    +    } else if (buf.EqualsIgnoreCase("BLINK")) {
    +//      mFont.mFont.decorations |= NS_STYLE_TEXT_DECORATION_BLINK;
    +    } else if (buf.EqualsIgnoreCase("TT")) {
    +//      mFont.mFont.name.SetLength(0);
    +//      mFont.mFont.name.Append("Courier");
    +    } else if (buf.EqualsIgnoreCase("S")) {
    +//      mFont.mFont.decorations = NS_FONT_DECORATION_LINE_THROUGH;
    +    } else if (buf.EqualsIgnoreCase("U")) {
    +//      mFont.mFont.decorations = NS_FONT_DECORATION_UNDERLINE;
    +    } else if (buf.EqualsIgnoreCase("PRE")) {
    +      mMolecule.whiteSpace = NS_STYLE_WHITESPACE_PRE;
    +//      mFont.mFont.name.SetLength(0);
    +//      mFont.mFont.name.Append("Courier");
    +    }
    +  }
    +
    +#if 0
    +  if ((NS_STYLE_DISPLAY_BLOCK == mMolecule.display) ||
    +      (NS_STYLE_DISPLAY_LIST_ITEM == mMolecule.display)) {
    +    // Always justify text (take that ie)
    +    mMolecule.textAlign = NS_STYLE_TEXT_ALIGN_JUSTIFY;
    +  }
    +#endif
    +
    +  mMolecule.borderPadding.top =
    +    mMolecule.border.top + mMolecule.padding.top;
    +  mMolecule.borderPadding.right =
    +    mMolecule.border.right + mMolecule.padding.right;
    +  mMolecule.borderPadding.bottom =
    +    mMolecule.border.bottom + mMolecule.padding.bottom;
    +  mMolecule.borderPadding.left =
    +    mMolecule.border.left + mMolecule.padding.left;
    +
    +}
    +
    +NS_LAYOUT nsresult
    +NS_NewStyleContext(nsIStyleContext** aInstancePtrResult,
    +                   nsISupportsArray* aRules,
    +                   nsIPresContext* aPresContext,
    +                   nsIContent* aContent,
    +                   nsIFrame* aParentFrame)
    +{
    +  NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr");
    +  if (nsnull == aInstancePtrResult) {
    +    return NS_ERROR_NULL_POINTER;
    +  }
    +
    +  nsIStyleContext* parent = nsnull;
    +  if (nsnull != aParentFrame) {
    +    parent = aParentFrame->GetStyleContext(aPresContext);
    +    NS_ASSERTION(nsnull != parent, "parent frame must have style context");
    +  }
    +
    +  StyleContextImpl* context = new StyleContextImpl(parent, aRules, aPresContext);
    +  NS_IF_RELEASE(parent);
    +  if (nsnull == context) {
    +    return NS_ERROR_OUT_OF_MEMORY;
    +  }
    +  context->HackStyleFor(aPresContext, aContent, aParentFrame);
    +
    +  return context->QueryInterface(kIStyleContextIID, (void **) aInstancePtrResult);
    +}
    diff --git a/mozilla/layout/style/nsStyleSet.cpp b/mozilla/layout/style/nsStyleSet.cpp
    new file mode 100644
    index 00000000000..156e68bea3c
    --- /dev/null
    +++ b/mozilla/layout/style/nsStyleSet.cpp
    @@ -0,0 +1,530 @@
    +/* -*- 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 "nsIStyleSet.h"
    +#include "nsIStyleSheet.h"
    +#include "nsIStyleRule.h"
    +#include "nsIStyleContext.h"
    +#include "nsISupportsArray.h"
    +#include "nsIFrame.h"
    +#include "nsHashtable.h"
    +
    +
    +static NS_DEFINE_IID(kIStyleSetIID, NS_ISTYLE_SET_IID);
    +
    +class ContextKey : public nsHashKey {
    +public:
    +  ContextKey(nsIStyleContext* aContext);
    +  ContextKey(nsIStyleContext* aParent, nsISupportsArray* aRules);
    +  ~ContextKey(void);
    +
    +  void        SetContext(nsIStyleContext* aContext);
    +
    +  PRBool      Equals(const nsHashKey* aOther) const;
    +  PRUint32    HashValue(void) const;
    +  nsHashKey*  Clone(void) const;
    +
    +private:
    +  ContextKey(void);
    +  ContextKey(const ContextKey& aCopy);
    +  ContextKey& operator=(const ContextKey& aCopy) const;
    +
    +protected:
    +  nsIStyleContext* mContext;
    +  nsIStyleContext* mParent;
    +  nsISupportsArray* mRules;
    +};
    +
    +ContextKey::ContextKey(nsIStyleContext* aContext)
    +  : mContext(aContext),
    +    mParent(nsnull),
    +    mRules(nsnull)
    +{
    +  NS_IF_ADDREF(mContext);
    +}
    +
    +ContextKey::ContextKey(nsIStyleContext* aParent, nsISupportsArray* aRules)
    +  : mContext(nsnull),
    +    mParent(aParent),
    +    mRules(aRules)
    +{
    +  NS_IF_ADDREF(mParent);
    +  NS_IF_ADDREF(mRules);
    +}
    +
    +ContextKey::ContextKey(const ContextKey& aCopy)
    +  : mContext(aCopy.mContext),
    +    mParent(aCopy.mParent),
    +    mRules(aCopy.mRules)
    +{
    +  NS_IF_ADDREF(mContext);
    +  NS_IF_ADDREF(mParent);
    +  NS_IF_ADDREF(mRules);
    +}
    +
    +ContextKey::~ContextKey(void)
    +{
    +  NS_IF_RELEASE(mContext);
    +  NS_IF_RELEASE(mParent);
    +  NS_IF_RELEASE(mRules);
    +}
    +
    +void ContextKey::SetContext(nsIStyleContext* aContext)
    +{
    +  if (aContext != mContext) {
    +    NS_IF_RELEASE(mContext);
    +    mContext = aContext;
    +    NS_IF_ADDREF(mContext);
    +  }
    +  NS_IF_RELEASE(mParent);
    +  NS_IF_RELEASE(mRules);
    +}
    +
    +PRBool ContextKey::Equals(const nsHashKey* aOther) const
    +{
    +  PRBool result = PR_TRUE;
    +  const ContextKey* other = (const ContextKey*)aOther;
    +
    +  if (other != this) {
    +    if ((nsnull == mContext) || (nsnull == other->mContext) || (mContext != other->mContext)) {
    +      nsIStyleContext* otherParent = other->mParent;
    +      if ((nsnull == otherParent) && (nsnull != other->mContext)) {
    +        otherParent = other->mContext->GetParent();
    +      }
    +      else {
    +        NS_IF_ADDREF(otherParent);  // simulate the above addref
    +      }
    +
    +      if (mParent == otherParent) {
    +        nsISupportsArray* otherRules = other->mRules;
    +        if ((nsnull == otherRules) && (nsnull != other->mContext)) {
    +          otherRules = other->mContext->GetStyleRules();
    +        }
    +        else {
    +          NS_IF_ADDREF(otherRules); // simulate the above addref
    +        }
    +        if ((nsnull != mRules) && (nsnull != otherRules)) {
    +          result = mRules->Equals(otherRules);
    +        }
    +        else {
    +          result = PRBool((nsnull == mRules) && (nsnull == otherRules));
    +        }
    +        NS_IF_RELEASE(otherRules);
    +      }
    +      else {
    +        result = PR_FALSE;
    +      }
    +      NS_IF_RELEASE(otherParent);
    +    }
    +  }
    +  return result;
    +}
    +
    +PRUint32 ContextKey::HashValue(void) const
    +{
    +  if (nsnull != mContext) {
    +    return mContext->HashValue();
    +  }
    +  // we don't have a context yet, compute it like it would
    +  PRUint32 hashValue = ((nsnull != mParent) ? mParent->HashValue() : 0);
    +  if (nsnull != mRules) {
    +    PRInt32 index = mRules->Count();
    +    while (0 <= --index) {
    +      nsIStyleRule* rule = (nsIStyleRule*)mRules->ElementAt(index);
    +      PRUint32 hash = rule->HashValue();
    +      hashValue ^= (hash & 0x7FFFFFFF);
    +      NS_RELEASE(rule);
    +    }
    +  }
    +  return hashValue;
    +}
    +
    +nsHashKey* ContextKey::Clone(void) const
    +{
    +  return new ContextKey(*this);
    +}
    +
    +
    +class StyleSetImpl : public nsIStyleSet {
    +public:
    +  StyleSetImpl();
    +
    +  NS_DECL_ISUPPORTS
    +
    +  virtual void AppendOverrideStyleSheet(nsIStyleSheet* aSheet);
    +  virtual void InsertOverrideStyleSheetAfter(nsIStyleSheet* aSheet,
    +                                             nsIStyleSheet* aAfterSheet);
    +  virtual void InsertOverrideStyleSheetBefore(nsIStyleSheet* aSheet,
    +                                              nsIStyleSheet* aBeforeSheet);
    +  virtual void RemoveOverrideStyleSheet(nsIStyleSheet* aSheet);
    +  virtual PRInt32 GetNumberOfOverrideStyleSheets();
    +  virtual nsIStyleSheet* GetOverrideStyleSheetAt(PRInt32 aIndex);
    +
    +  virtual void AppendDocStyleSheet(nsIStyleSheet* aSheet);
    +  virtual void InsertDocStyleSheetAfter(nsIStyleSheet* aSheet,
    +                                        nsIStyleSheet* aAfterSheet);
    +  virtual void InsertDocStyleSheetBefore(nsIStyleSheet* aSheet,
    +                                         nsIStyleSheet* aBeforeSheet);
    +  virtual void RemoveDocStyleSheet(nsIStyleSheet* aSheet);
    +  virtual PRInt32 GetNumberOfDocStyleSheets();
    +  virtual nsIStyleSheet* GetDocStyleSheetAt(PRInt32 aIndex);
    +
    +  virtual void AppendBackstopStyleSheet(nsIStyleSheet* aSheet);
    +  virtual void InsertBackstopStyleSheetAfter(nsIStyleSheet* aSheet,
    +                                             nsIStyleSheet* aAfterSheet);
    +  virtual void InsertBackstopStyleSheetBefore(nsIStyleSheet* aSheet,
    +                                              nsIStyleSheet* aBeforeSheet);
    +  virtual void RemoveBackstopStyleSheet(nsIStyleSheet* aSheet);
    +  virtual PRInt32 GetNumberOfBackstopStyleSheets();
    +  virtual nsIStyleSheet* GetBackstopStyleSheetAt(PRInt32 aIndex);
    +
    +  virtual nsIStyleContext* ResolveStyleFor(nsIPresContext* aPresContext,
    +                                           nsIContent* aContent,
    +                                           nsIFrame* aParentFrame);
    +
    +  // xxx style rules enumeration
    +
    +  virtual void List(FILE* out = stdout, PRInt32 aIndent = 0);
    +
    +private:
    +  // These are not supported and are not implemented!
    +  StyleSetImpl(const StyleSetImpl& aCopy);
    +  StyleSetImpl& operator=(const StyleSetImpl& aCopy);
    +
    +protected:
    +  virtual ~StyleSetImpl();
    +  PRBool EnsureArray(nsISupportsArray** aArray);
    +  PRInt32 RulesMatching(nsISupportsArray* aSheets,
    +                        nsIPresContext* aPresContext,
    +                        nsIContent* aContent,
    +                        nsIFrame* aParentFrame,
    +                        nsISupportsArray* aResults);
    +  void  List(FILE* out, PRInt32 aIndent, nsISupportsArray* aSheets);
    +
    +  nsISupportsArray* mOverrideSheets;
    +  nsISupportsArray* mDocSheets;
    +  nsISupportsArray* mBackstopSheets;
    +  nsHashtable mStyleContexts;
    +};
    +
    +
    +StyleSetImpl::StyleSetImpl()
    +  : mOverrideSheets(nsnull),
    +    mDocSheets(nsnull),
    +    mBackstopSheets(nsnull)
    +{
    +  NS_INIT_REFCNT();
    +}
    +
    +PRBool ReleaseContext(nsHashKey *aKey, void *aData)
    +{
    +  ((nsIStyleContext*)aData)->Release();
    +  return PR_TRUE;
    +}
    +
    +StyleSetImpl::~StyleSetImpl()
    +{
    +  NS_IF_RELEASE(mOverrideSheets);
    +  NS_IF_RELEASE(mDocSheets);
    +  NS_IF_RELEASE(mBackstopSheets);
    +  mStyleContexts.Enumerate(ReleaseContext);
    +}
    +
    +NS_IMPL_ISUPPORTS(StyleSetImpl, kIStyleSetIID)
    +
    +PRBool StyleSetImpl::EnsureArray(nsISupportsArray** aArray)
    +{
    +  if (nsnull == *aArray) {
    +    if (NS_OK != NS_NewISupportsArray(aArray)) {
    +      return PR_FALSE;
    +    }
    +  }
    +  return PR_TRUE;
    +}
    +
    +// ----- Override sheets
    +
    +void StyleSetImpl::AppendOverrideStyleSheet(nsIStyleSheet* aSheet)
    +{
    +  NS_PRECONDITION(nsnull != aSheet, "null arg");
    +  if (EnsureArray(&mOverrideSheets)) {
    +    mOverrideSheets->AppendElement(aSheet);
    +  }
    +}
    +
    +void StyleSetImpl::InsertOverrideStyleSheetAfter(nsIStyleSheet* aSheet,
    +                                                 nsIStyleSheet* aAfterSheet)
    +{
    +  NS_PRECONDITION(nsnull != aSheet, "null arg");
    +  if (EnsureArray(&mOverrideSheets)) {
    +    PRInt32 index = mOverrideSheets->IndexOf(aAfterSheet);
    +    mOverrideSheets->InsertElementAt(aSheet, ++index);
    +  }
    +}
    +
    +void StyleSetImpl::InsertOverrideStyleSheetBefore(nsIStyleSheet* aSheet,
    +                                                  nsIStyleSheet* aBeforeSheet)
    +{
    +  NS_PRECONDITION(nsnull != aSheet, "null arg");
    +  if (EnsureArray(&mOverrideSheets)) {
    +    PRInt32 index = mOverrideSheets->IndexOf(aBeforeSheet);
    +    mOverrideSheets->InsertElementAt(aSheet, ((-1 < index) ? index : 0));
    +  }
    +}
    +
    +void StyleSetImpl::RemoveOverrideStyleSheet(nsIStyleSheet* aSheet)
    +{
    +  NS_PRECONDITION(nsnull != aSheet, "null arg");
    +
    +  if (nsnull != mOverrideSheets) {
    +    mOverrideSheets->RemoveElement(aSheet);
    +  }
    +}
    +
    +PRInt32 StyleSetImpl::GetNumberOfOverrideStyleSheets()
    +{
    +  if (nsnull != mOverrideSheets) {
    +    return mOverrideSheets->Count();
    +  }
    +  return 0;
    +}
    +
    +nsIStyleSheet* StyleSetImpl::GetOverrideStyleSheetAt(PRInt32 aIndex)
    +{
    +  nsIStyleSheet* sheet = nsnull;
    +  if (nsnull == mOverrideSheets) {
    +    sheet = (nsIStyleSheet*)mOverrideSheets->ElementAt(aIndex);
    +  }
    +  return sheet;
    +}
    +
    +// -------- Doc Sheets
    +
    +void StyleSetImpl::AppendDocStyleSheet(nsIStyleSheet* aSheet)
    +{
    +  NS_PRECONDITION(nsnull != aSheet, "null arg");
    +  if (EnsureArray(&mDocSheets)) {
    +    mDocSheets->AppendElement(aSheet);
    +  }
    +}
    +
    +void StyleSetImpl::InsertDocStyleSheetAfter(nsIStyleSheet* aSheet,
    +                                         nsIStyleSheet* aAfterSheet)
    +{
    +  NS_PRECONDITION(nsnull != aSheet, "null arg");
    +  if (EnsureArray(&mDocSheets)) {
    +    PRInt32 index = mDocSheets->IndexOf(aAfterSheet);
    +    mDocSheets->InsertElementAt(aSheet, ++index);
    +  }
    +}
    +
    +void StyleSetImpl::InsertDocStyleSheetBefore(nsIStyleSheet* aSheet,
    +                                          nsIStyleSheet* aBeforeSheet)
    +{
    +  NS_PRECONDITION(nsnull != aSheet, "null arg");
    +  if (EnsureArray(&mDocSheets)) {
    +    PRInt32 index = mDocSheets->IndexOf(aBeforeSheet);
    +    mDocSheets->InsertElementAt(aSheet, ((-1 < index) ? index : 0));
    +  }
    +}
    +
    +void StyleSetImpl::RemoveDocStyleSheet(nsIStyleSheet* aSheet)
    +{
    +  NS_PRECONDITION(nsnull != aSheet, "null arg");
    +
    +  if (nsnull != mDocSheets) {
    +    mDocSheets->RemoveElement(aSheet);
    +  }
    +}
    +
    +PRInt32 StyleSetImpl::GetNumberOfDocStyleSheets()
    +{
    +  if (nsnull != mDocSheets) {
    +    return mDocSheets->Count();
    +  }
    +  return 0;
    +}
    +
    +nsIStyleSheet* StyleSetImpl::GetDocStyleSheetAt(PRInt32 aIndex)
    +{
    +  nsIStyleSheet* sheet = nsnull;
    +  if (nsnull == mDocSheets) {
    +    sheet = (nsIStyleSheet*)mDocSheets->ElementAt(aIndex);
    +  }
    +  return sheet;
    +}
    +
    +// ------ backstop sheets
    +
    +void StyleSetImpl::AppendBackstopStyleSheet(nsIStyleSheet* aSheet)
    +{
    +  NS_PRECONDITION(nsnull != aSheet, "null arg");
    +  if (EnsureArray(&mBackstopSheets)) {
    +    mBackstopSheets->AppendElement(aSheet);
    +  }
    +}
    +
    +void StyleSetImpl::InsertBackstopStyleSheetAfter(nsIStyleSheet* aSheet,
    +                                                 nsIStyleSheet* aAfterSheet)
    +{
    +  NS_PRECONDITION(nsnull != aSheet, "null arg");
    +  if (EnsureArray(&mBackstopSheets)) {
    +    PRInt32 index = mBackstopSheets->IndexOf(aAfterSheet);
    +    mBackstopSheets->InsertElementAt(aSheet, ++index);
    +  }
    +}
    +
    +void StyleSetImpl::InsertBackstopStyleSheetBefore(nsIStyleSheet* aSheet,
    +                                                  nsIStyleSheet* aBeforeSheet)
    +{
    +  NS_PRECONDITION(nsnull != aSheet, "null arg");
    +  if (EnsureArray(&mBackstopSheets)) {
    +    PRInt32 index = mBackstopSheets->IndexOf(aBeforeSheet);
    +    mBackstopSheets->InsertElementAt(aSheet, ((-1 < index) ? index : 0));
    +  }
    +}
    +
    +void StyleSetImpl::RemoveBackstopStyleSheet(nsIStyleSheet* aSheet)
    +{
    +  NS_PRECONDITION(nsnull != aSheet, "null arg");
    +
    +  if (nsnull != mBackstopSheets) {
    +    mBackstopSheets->RemoveElement(aSheet);
    +  }
    +}
    +
    +PRInt32 StyleSetImpl::GetNumberOfBackstopStyleSheets()
    +{
    +  if (nsnull != mBackstopSheets) {
    +    return mBackstopSheets->Count();
    +  }
    +  return 0;
    +}
    +
    +nsIStyleSheet* StyleSetImpl::GetBackstopStyleSheetAt(PRInt32 aIndex)
    +{
    +  nsIStyleSheet* sheet = nsnull;
    +  if (nsnull == mBackstopSheets) {
    +    sheet = (nsIStyleSheet*)mBackstopSheets->ElementAt(aIndex);
    +  }
    +  return sheet;
    +}
    +
    +PRInt32 StyleSetImpl::RulesMatching(nsISupportsArray* aSheets,
    +                                    nsIPresContext* aPresContext,
    +                                    nsIContent* aContent,
    +                                    nsIFrame* aParentFrame,
    +                                    nsISupportsArray* aResults)
    +{
    +  PRInt32 ruleCount = 0;
    +
    +  if (nsnull != aSheets) {
    +    PRInt32 sheetCount = aSheets->Count();
    +    PRInt32 index;
    +    for (index = 0; index < sheetCount; index++) {
    +      nsIStyleSheet* sheet = (nsIStyleSheet*)aSheets->ElementAt(index);
    +      ruleCount += sheet->RulesMatching(aPresContext, aContent, aParentFrame,
    +                                        aResults);
    +      NS_RELEASE(sheet);
    +    }
    +  }
    +  return ruleCount;
    +}
    +
    +nsIStyleContext* StyleSetImpl::ResolveStyleFor(nsIPresContext* aPresContext,
    +                                               nsIContent* aContent,
    +                                               nsIFrame* aParentFrame)
    +{
    +  nsIStyleContext*  result = nsnull;
    +
    +  nsIStyleContext* parentContext = nsnull;
    +  
    +  if (nsnull != aParentFrame) {
    +    parentContext = aParentFrame->GetStyleContext(aPresContext);
    +    NS_ASSERTION(nsnull != parentContext, "parent must have style context");
    +  }
    +
    +  // want to check parent frame's context for cached child context first
    +
    +  // then do a brute force rule search
    +
    +  nsISupportsArray*  rules = nsnull;
    +  if (NS_OK == NS_NewISupportsArray(&rules)) {
    +    PRInt32 ruleCount = RulesMatching(mOverrideSheets, aPresContext, aContent, aParentFrame, rules);
    +    ruleCount += RulesMatching(mDocSheets, aPresContext, aContent, aParentFrame, rules);
    +    ruleCount += RulesMatching(mBackstopSheets, aPresContext, aContent, aParentFrame, rules);
    +
    +    // then check for cached ruleSet to context or create
    +    ContextKey tempKey(parentContext, rules);
    +    result = (nsIStyleContext*)mStyleContexts.Get(&tempKey);
    +    if (nsnull == result) {
    +      if (NS_OK == NS_NewStyleContext(&result, rules, aPresContext, aContent, aParentFrame)) {
    +        tempKey.SetContext(result);
    +        mStyleContexts.Put(&tempKey, result);  // hashtable clones key, so this is OK (table gets first ref)
    +        NS_ADDREF(result);  // add ref for the caller
    +//fprintf(stdout, "+");
    +      }
    +    }
    +    else {
    +      NS_ADDREF(result);
    +//fprintf(stdout, "-");
    +    }
    +    NS_RELEASE(rules);
    +  }
    +
    +  NS_IF_RELEASE(parentContext);
    +
    +  return result;
    +}
    +
    +// xxx style rules enumeration
    +
    +void StyleSetImpl::List(FILE* out, PRInt32 aIndent, nsISupportsArray* aSheets)
    +{
    +  PRInt32 count = ((nsnull != aSheets) ? aSheets->Count() : 0);
    +
    +  for (PRInt32 index = 0; index < count; index++) {
    +    nsIStyleSheet* sheet = (nsIStyleSheet*)aSheets->ElementAt(index);
    +    sheet->List(out, aIndent);
    +    fputs("\n", out);
    +    NS_RELEASE(sheet);
    +  }
    +}
    +
    +void StyleSetImpl::List(FILE* out, PRInt32 aIndent)
    +{
    +  List(out, aIndent, mOverrideSheets);
    +  List(out, aIndent, mDocSheets);
    +  List(out, aIndent, mBackstopSheets);
    +}
    +
    +
    +NS_LAYOUT nsresult
    +NS_NewStyleSet(nsIStyleSet** aInstancePtrResult)
    +{
    +  if (aInstancePtrResult == nsnull) {
    +    return NS_ERROR_NULL_POINTER;
    +  }
    +
    +  StyleSetImpl  *it = new StyleSetImpl();
    +
    +  if (nsnull == it) {
    +    return NS_ERROR_OUT_OF_MEMORY;
    +  }
    +
    +  return it->QueryInterface(kIStyleSetIID, (void **) aInstancePtrResult);
    +}
    diff --git a/mozilla/layout/style/ua.css b/mozilla/layout/style/ua.css
    new file mode 100644
    index 00000000000..2f44c42e563
    --- /dev/null
    +++ b/mozilla/layout/style/ua.css
    @@ -0,0 +1,286 @@
    +/*
    + * 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.
    + */
    +
    +// It's probably cheaper to have a single rule per tag than to have to
    +// merge rules
    +
    +// XXX I'm starting to believe that this portion of the style sheet
    +// comes from the PresentationContext.
    +
    +// XXX temporary hack
    +IMPLICITP {
    +  display: block;
    +  margin-top: 0pt;
    +  margin-bottom: 2pt;
    +}
    +
    +BODY {
    +  font-family: "Times Roman", serif;
    +  font-style: normal;
    +  font-variant: normal;
    +  font-weight: normal;
    +  font-size: 10pt;
    +  line-height: 1.1;
    +  background: rgb(255,255,255);
    +//  background: rgb(192,192,192);
    +  color: black;
    +  margin: 10px;
    +  display: block;
    +}
    +
    +// XXX Use this!
    +FRAMESET {
    +  font-family: "Times Roman", serif;
    +  font-style: normal;
    +  font-variant: normal;
    +  font-weight: normal;
    +  font-size: medium;
    +  background: rgb(192,192,192);
    +  color: black;
    +  margin: 0px;
    +  display: block;
    +}
    +
    +// XXX Used when PagePreview'ing
    +PAGE {
    +  margin: 10px;
    +  background: white;
    +  border: black solid 1px;
    +  display: block;
    +}
    +
    +//----------------------------------------------------------------------
    +
    +// This part of the ua.css is junk taken from the css1 spec and used as
    +// a temporary style sheet.
    +
    +UL, OL, DL { display: block; }
    +DT, DD { display: block; }
    +LI { display: list-item; }
    +IMG { display: inline; }
    +SPACER { display: inline; }
    +WBR { display: inline; }
    +
    +// Default list-style-type styles.
    +// The Navigator 3.0 rule is:
    +// Zeroth-level: small disc. (Needs to be handled by parser.)
    +// First level: disc
    +// second level: circle
    +// third and higher levels: square.
    +//
    +// These style rules assume that MENU and DIR have been mapped to UL.
    +
    +UL {
    +  list-style-type: disc;
    +}
    +
    +OL UL, UL UL  {
    +  list-style-type: circle;
    +}
    +
    +UL UL UL,  UL OL UL, OL UL UL,  OL OL UL {
    +  list-style-type: square;
    +}
    +
    +OL {
    +  list-style-type: decimal;
    +}
    +
    +UL, OL {
    +  padding-left: 40px;		/* nav4's value */
    +}
    +
    +DT { margin-bottom: 0 }
    +DD { margin-top: 0; margin-left: .25in; }
    +
    +A:link { color: blue; text-decoration: underline }
    +A:visited { color: purple; text-decoration: underline }
    +A:active { color: lime; text-decoration: underline }
    +A:out-of-date { color: red; text-decoration: underline }
    +
    +A:link IMG { border: 2px solid blue; text-decoration: underline }
    +A:visited IMG { border: 2px solid purple; text-decoration: underline }
    +A:active IMG { border: 2px solid lime; text-decoration: underline }
    +A:out-of-date IMG { border: 2px solid red; text-decoration: underline }
    +
    +IMG { border-style: solid; border-color: blue; }
    +//INPUT { border-style: solid; border-color: blue; }
    +
    +//----------------------------------------------------------------------
    +// The real stuff
    +
    +HR {
    +  display: block;
    +  height: 3px;
    +  margin-top: 5px;
    +  margin-bottom: 5px;
    +}
    +
    +BR {
    +  display: block;
    +}
    +
    +// Block tags
    +ADDRESS {
    +  display: block;
    +  font-style: italic;
    +}
    +BLOCKQUOTE {
    +  display: block;
    +  margin-left: .25in;
    +  margin-right: .25in;
    +}
    +CENTER {
    +  display: block;
    +  text-align: center;
    +}
    +DIV {
    +  display: block;
    +}
    +H1 {
    +  display: block;
    +  font-size: 22pt;
    +  font-weight: bold;
    +  margin-top: 2pt;
    +  margin-bottom: 2pt;
    +}
    +H2 {
    +  display: block;
    +  font-size: 16pt;
    +  font-weight: bold;
    +  margin-top: 2pt;
    +  margin-bottom: 2pt;
    +}
    +H3 {
    +  display: block;
    +  font-size: 13pt;
    +  font-weight: bold;
    +  margin-top: 2pt;
    +  margin-bottom: 2pt;
    +}
    +H4 {
    +  display: block;
    +  font-size: 12pt;
    +  font-weight: bold;
    +  margin-top: 2pt;
    +  margin-bottom: 2pt;
    +}
    +H5 {
    +  display: block;
    +  font-size: 9pt;
    +  font-weight: bold;
    +  margin-top: 2pt;
    +  margin-bottom: 2pt;
    +}
    +H6 {
    +  display: block;
    +  font-size: 8pt;
    +  font-weight: bold;
    +  margin-top: 2pt;
    +  margin-bottom: 2pt;
    +}
    +LISTING {
    +  display: block;
    +  font-family: monospace;
    +  font-size: small;
    +  white-space: pre;
    +}
    +NOBR {
    +  display: inline;
    +  white-space: pre; // XXX approximation?
    +}
    +P {
    +  display: block;
    +  margin-top: 2pt;
    +  margin-bottom: 2pt;
    +}
    +PLAINTEXT, XMP, PRE {
    +  display: block; // Note: need before and after breaks
    +  font-family: monospace;
    +  white-space: pre;
    +}
    +
    +// Table tags
    +TABLE {
    +  border-style: outset;
    +  border-color: #C0C0C0;
    +  cell-spacing: 4px;
    +}
    +TD {
    +  vertical-align: middle;
    +  border-style: inset;
    +  border-color: #C0C0C0;
    +}
    +TH {
    +  vertical-align: middle;
    +  text-align: center;
    +  font-weight: bold;
    +  border-style: inset;
    +  border-color: #C0C0C0;
    +}
    +// XXX Special rule to eliminate margin around for nav4 compatability
    +// XXX This isn't good enough because we only want the margin eliminated
    +// around the first paragraph!
    +/*TD P, TH P {
    +  margin-top: 0;
    +  margin-bottom: 0;
    +}*/
    +
    +// Span tags
    +B, STRONG {
    +  display: inline;
    +  font-weight: bolder;
    +}
    +I, CITE, EM, VAR {
    +  display: inline;
    +  font-style: italic;
    +}
    +TT, CODE, KBD, SAMP {
    +  display: inline;
    +  font-family: monospace;
    +}
    +U {
    +  display: inline;
    +  text-decoration: underline;
    +}
    +S, STRIKE {
    +  display: inline;
    +  text-decoration: line-through;
    +}
    +BLINK {
    +  display: inline;
    +  text-decoration: blink;
    +}
    +BIG {
    +  display: inline;
    +  font-size: larger;
    +}
    +SMALL {
    +  display: inline;
    +  font-size: smaller;
    +}
    +DFN, SPAN {
    +  display: inline;
    +}
    +SUB {
    +  display: inline;
    +  vertical-align: sub;
    +}
    +SUP {
    +  display: inline;
    +  vertical-align: super;
    +}
    diff --git a/mozilla/layout/tables/nsCellMap.cpp b/mozilla/layout/tables/nsCellMap.cpp
    new file mode 100644
    index 00000000000..25fd456989d
    --- /dev/null
    +++ b/mozilla/layout/tables/nsCellMap.cpp
    @@ -0,0 +1,136 @@
    +/* -*- 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 "nsCRT.h"
    +#include "nsCellMap.h"
    +#include "nsTablePart.h"
    +#include /* XXX */ // for printf
    +
    +#ifdef NS_DEBUG
    +static PRBool gsDebug1 = PR_FALSE;
    +#else
    +static const PRBool gsDebug1 = PR_FALSE;
    +#endif
    +
    +static PRInt32 gBytesPerPointer = sizeof(PRInt32);
    +
    +nsCellMap::nsCellMap(int aRows, int aColumns)
    +  : mRowCount(aRows),
    +    mColCount(aColumns)
    +{
    +  mCells = nsnull;
    +  Reset(aRows, aColumns);
    +}
    +
    +nsCellMap::~nsCellMap()
    +{
    +  for (int i=0;iGetData(kStyleColorSID);
    +  nsStyleMolecule* myMol =
    +    (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID);
    +  NS_ASSERTION(nsnull!=myColor, "bad style color");
    +  NS_ASSERTION(nsnull!=myMol, "bad style molecule");
    +
    +  nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this,
    +                                  aDirtyRect, mRect, *myColor);
    +  nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this,
    +                              aDirtyRect, mRect, *myMol, 0);
    +
    +
    +  // for debug...
    +  if (nsIFrame::GetShowFrameBorders()) {
    +    aRenderingContext.SetColor(NS_RGB(0,128,128));
    +    aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height);
    +  }
    +
    +  PaintChildren(aPresContext, aRenderingContext, aDirtyRect);
    +}
    +
    +/**
    +*
    +* Align the cell's child frame within the cell
    +*
    +**/
    +
    +void  nsTableCellFrame::VerticallyAlignChild(nsIPresContext* aPresContext)
    +  {
    +  
    +  nsStyleMolecule* mol =
    +      (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID);
    +  NS_ASSERTION(nsnull!=mol, "bad style molecule");
    +  nscoord topInset=0, bottomInset=0;
    +  PRInt32 verticalAlign = NS_STYLE_VERTICAL_ALIGN_MIDDLE;
    +  
    +  if (nsnull!=mol)
    +  {
    +    topInset = mol->borderPadding.top;
    +    bottomInset =mol->borderPadding.bottom;
    +    verticalAlign = mol->verticalAlign;
    +  }
    +  nscoord       height = GetHeight();
    +
    +  nsRect        kidRect;  
    +  mFirstChild->GetRect(kidRect);
    +  nscoord       childHeight = kidRect.height;
    +  
    +
    +  // Vertically align the child
    +  nscoord kidYTop = 0;
    +  switch (verticalAlign) 
    +  {
    +    case NS_STYLE_VERTICAL_ALIGN_BASELINE:
    +    // Align the child's baseline at the max baseline
    +    //kidYTop = aMaxAscent - kidAscent;
    +    break;
    +
    +    case NS_STYLE_VERTICAL_ALIGN_TOP:
    +    // Align the top of the child frame with the top of the box, 
    +    // minus the top padding
    +      kidYTop = topInset;
    +    break;
    +
    +    case NS_STYLE_VERTICAL_ALIGN_BOTTOM:
    +      kidYTop = height - childHeight - bottomInset;
    +    break;
    +
    +    default:
    +    case NS_STYLE_VERTICAL_ALIGN_MIDDLE:
    +      kidYTop = height/2 - childHeight/2;
    +  }
    +  mFirstChild->MoveTo(kidRect.x, kidYTop);
    +}
    +
    +/** helper method to get the row span of this frame's content (which must be a cell) */
    +PRInt32 nsTableCellFrame::GetRowSpan()
    +{
    +  PRInt32 result = 0;
    +  nsTableCell *cellContent = (nsTableCell *)GetContent();        // cellContent:  REFCNT++
    +  if (nsnull!=cellContent)
    +  {
    +    result = cellContent->GetRowSpan();
    +    NS_RELEASE(cellContent);                                     // cellContent:  REFCNT--
    +  }
    +  return result;
    +}
    +
    +void nsTableCellFrame::CreatePsuedoFrame(nsIPresContext* aPresContext)
    +{
    +  // Do we have a prev-in-flow?
    +  if (nsnull == mPrevInFlow) {
    +    // No, create a column pseudo frame
    +    nsBodyFrame::NewFrame(&mFirstChild, mContent, mIndexInParent, this);
    +    mChildCount = 1;
    +
    +    // Resolve style and set the style context
    +    nsIStyleContext* styleContext =
    +      aPresContext->ResolveStyleContextFor(mContent, this);             // styleContext: ADDREF++
    +    mFirstChild->SetStyleContext(styleContext);
    +    NS_RELEASE(styleContext);                                           // styleContext: ADDREF--
    +  } else {
    +    nsTableCellFrame* prevFrame = (nsTableCellFrame *)mPrevInFlow;
    +
    +    nsIFrame* prevPseudoFrame = prevFrame->mFirstChild;
    +    NS_ASSERTION(prevFrame->ChildIsPseudoFrame(prevPseudoFrame), "bad previous pseudo-frame");
    +
    +    // Create a continuing column
    +    mFirstChild = prevPseudoFrame->CreateContinuingFrame(aPresContext, this);
    +    mChildCount = 1;
    +  }
    +}
    +
    +/**
    +  */
    +nsIFrame::ReflowStatus
    +nsTableCellFrame::ResizeReflow(nsIPresContext* aPresContext,
    +                               nsReflowMetrics& aDesiredSize,
    +                               const nsSize&   aMaxSize,
    +                               nsSize*         aMaxElementSize)
    +{
    +  NS_PRECONDITION(nsnull!=aPresContext, "bad arg");
    +
    +#ifdef NS_DEBUG
    +  //PreReflowCheck();
    +#endif
    +
    +  ReflowStatus result = frComplete;
    +  if (gsDebug==PR_TRUE)
    +    printf("nsTableCellFrame::ResizeReflow: maxSize=%d,%d\n",
    +           aMaxSize.width, aMaxSize.height);
    +
    +  mFirstContentOffset = mLastContentOffset = 0;
    +
    +  nsSize availSize(aMaxSize);
    +  nsSize maxElementSize;
    +  nsSize *pMaxElementSize = aMaxElementSize;
    +  if (NS_UNCONSTRAINEDSIZE==aMaxSize.width)
    +    pMaxElementSize = &maxElementSize;
    +  nsReflowMetrics kidSize;
    +  nscoord x = 0;
    +  // SEC: what about ascent and decent???
    +
    +  // Compute the insets (sum of border and padding)
    +  nsStyleMolecule* myMol =
    +      (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID);
    +  NS_ASSERTION(nsnull!=myMol, "bad style molecule");
    +  nscoord topInset=0,rightInset=0, bottomInset=0, leftInset=0;
    +  if (nsnull!=myMol)
    +  {
    +    topInset = myMol->borderPadding.top;
    +    rightInset = myMol->borderPadding.right;
    +    bottomInset =myMol->borderPadding.bottom;
    +    leftInset = myMol->borderPadding.left;
    +  }
    +
    +  // reduce available space by insets
    +  if (NS_UNCONSTRAINEDSIZE!=availSize.width)
    +    availSize.width -= leftInset+rightInset;
    +  if (NS_UNCONSTRAINEDSIZE!=availSize.height)
    +    availSize.height -= topInset+bottomInset;
    +  //was: availSize.SizeBy(-(leftInset+rightInset), -(topInset+bottomInset));
    +
    +  mLastContentIsComplete = PR_TRUE;
    +
    +  // get frame, creating one if needed
    +  if (nsnull==mFirstChild)
    +  {
    +    CreatePsuedoFrame(aPresContext);
    +  }
    +
    +  // Try to reflow the child into the available space. It might not
    +  // fit or might need continuing.
    +  nsSize maxKidElementSize;
    +  if (gsDebug==PR_TRUE)
    +    printf("  nsTableCellFrame::ResizeReflow calling ReflowChild with availSize=%d,%d\n",
    +           availSize.width, availSize.height);
    +  result = ReflowChild(mFirstChild, aPresContext, kidSize, availSize, pMaxElementSize);
    +
    +  if (gsDebug==PR_TRUE)
    +  {
    +    if (nsnull!=pMaxElementSize)
    +      printf("  nsTableCellFrame::ResizeReflow: child returned desiredSize=%d,%d,\
    +             and maxElementSize=%d,%d\n",
    +             kidSize.width, kidSize.height,
    +             pMaxElementSize->width, pMaxElementSize->height);
    +    else
    +      printf("  nsTableCellFrame::ResizeReflow: child returned desiredSize=%d,%d,\
    +             and maxElementSize=nsnull\n",
    +             kidSize.width, kidSize.height);
    +  }
    +
    +  SetFirstContentOffset(mFirstChild);
    +  if (gsDebug) printf("CELL: set first content offset to %d\n", GetFirstContentOffset()); //@@@
    +  SetLastContentOffset(mFirstChild);
    +  if (gsDebug) printf("CELL: set last content offset to %d\n", GetLastContentOffset()); //@@@
    +
    +  // Place the child since some of it's content fit in us.
    +  mFirstChild->SetRect(nsRect(leftInset + x, topInset,
    +                           kidSize.width, kidSize.height));
    +  
    +    
    +  if (frNotComplete == result) {
    +    // If the child didn't finish layout then it means that it used
    +    // up all of our available space (or needs us to split).
    +    mLastContentIsComplete = PR_FALSE;
    +  }
    +
    +  // Return our size and our result
    +  PRInt32 kidWidth = kidSize.width;
    +  if (NS_UNCONSTRAINEDSIZE!=kidSize.width) //&& NS_UNCONSTRAINEDSIZE!=aMaxSize.width)
    +    kidWidth += leftInset + rightInset;
    +  PRInt32 kidHeight = kidSize.height;
    +
    +  // height can be set w/o being restricted by aMaxSize.height
    +  if (NS_UNCONSTRAINEDSIZE!=kidSize.height)
    +    kidHeight += topInset + bottomInset;
    +  aDesiredSize.width = kidWidth;
    +  aDesiredSize.height = kidHeight;
    +  aDesiredSize.ascent = topInset;
    +  aDesiredSize.descent = bottomInset;
    +
    +  if (nsnull!=aMaxElementSize)
    +    *aMaxElementSize = *pMaxElementSize;
    +  
    +  if (gsDebug==PR_TRUE)
    +    printf("  nsTableCellFrame::ResizeReflow returning aDesiredSize=%d,%d\n",
    +           aDesiredSize.width, aDesiredSize.height);
    +
    +#ifdef NS_DEBUG
    +  //PostReflowCheck(result);
    +#endif
    +
    +  return result;
    +}
    +
    +nsIFrame::ReflowStatus
    +nsTableCellFrame::IncrementalReflow(nsIPresContext*  aPresContext,
    +                                    nsReflowMetrics& aDesiredSize,
    +                                    const nsSize&    aMaxSize,
    +                                    nsReflowCommand& aReflowCommand)
    +{
    +  if (gsDebug == PR_TRUE) printf("nsTableCellFrame::IncrementalReflow\n");
    +  // total hack for now, just some hard-coded values
    +  ResizeReflow(aPresContext, aDesiredSize, aMaxSize, nsnull);
    +
    +  return frComplete;
    +}
    +
    +nsIFrame* nsTableCellFrame::CreateContinuingFrame(nsIPresContext* aPresContext,
    +                                                  nsIFrame*       aParent)
    +{
    +  nsTableCellFrame* cf = new nsTableCellFrame(mContent, mIndexInParent, aParent);
    +  PrepareContinuingFrame(aPresContext, aParent, cf);
    +  return cf;
    +}
    +
    +
    +/* ----- static methods ----- */
    +
    +nsresult nsTableCellFrame::NewFrame(nsIFrame** aInstancePtrResult,
    +                                    nsIContent* aContent,
    +                                    PRInt32     aIndexInParent,
    +                                    nsIFrame*   aParent)
    +{
    +  NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr");
    +  if (nsnull == aInstancePtrResult) {
    +    return NS_ERROR_NULL_POINTER;
    +  }
    +  nsIFrame* it = new nsTableCellFrame(aContent, aIndexInParent, aParent);
    +  if (nsnull == it) {
    +    return NS_ERROR_OUT_OF_MEMORY;
    +  }
    +  *aInstancePtrResult = it;
    +  return NS_OK;
    +}
    diff --git a/mozilla/layout/tables/nsTableCellFrame.h b/mozilla/layout/tables/nsTableCellFrame.h
    new file mode 100644
    index 00000000000..c71974a1894
    --- /dev/null
    +++ b/mozilla/layout/tables/nsTableCellFrame.h
    @@ -0,0 +1,84 @@
    +/* -*- 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.
    + */
    +#ifndef nsTableCellFrame_h__
    +#define nsTableCellFrame_h__
    +
    +#include "nscore.h"
    +#include "nsContainerFrame.h"
    +#include "nsTableCell.h"
    +
    +struct nsStyleMolecule;
    +
    +/**
    + * nsTableCellFrame
    + * data structure to maintain information about a single table cell's frame
    + *
    + * @author  sclark
    + */
    +class nsTableCellFrame : public nsContainerFrame
    +{
    +public:
    +  static nsresult NewFrame(nsIFrame** aInstancePtrResult,
    +                           nsIContent* aContent,
    +                           PRInt32     aIndexInParent,
    +                           nsIFrame*   aParent);
    +
    +  virtual void  Paint(nsIPresContext& aPresContext,
    +                      nsIRenderingContext& aRenderingContext,
    +                      const nsRect& aDirtyRect);
    +
    +  ReflowStatus  ResizeReflow(nsIPresContext* aPresContext,
    +                             nsReflowMetrics& aDesiredSize,
    +                             const nsSize&   aMaxSize,
    +                             nsSize*         aMaxElementSize);
    +
    +  ReflowStatus  IncrementalReflow(nsIPresContext*  aPresContext,
    +                                  nsReflowMetrics& aDesiredSize,
    +                                  const nsSize&    aMaxSize,
    +                                  nsReflowCommand& aReflowCommand);
    +
    +  /**
    +   * @see nsContainerFrame
    +   */
    +  virtual nsIFrame* CreateContinuingFrame(nsIPresContext* aPresContext,
    +                                          nsIFrame*       aParent);
    +
    +  void          VerticallyAlignChild(nsIPresContext* aPresContext);
    +
    +  virtual PRInt32 GetRowSpan();
    +
    +  virtual ~nsTableCellFrame();
    +
    +protected:
    +
    +  /** protected constructor.
    +    * @see NewFrame
    +    */
    +  nsTableCellFrame(nsIContent* aContent,
    +                   PRInt32 aIndexInParent,
    +					         nsIFrame* aParentFrame);
    +
    +  /** Create a psuedo-frame for this caption.  Handles continuing frames as needed.
    +    */
    +  virtual void CreatePsuedoFrame(nsIPresContext* aPresContext);
    +
    +
    +};
    +
    +
    +#endif
    diff --git a/mozilla/layout/tables/nsTableColGroupFrame.cpp b/mozilla/layout/tables/nsTableColGroupFrame.cpp
    new file mode 100644
    index 00000000000..d2741f097ca
    --- /dev/null
    +++ b/mozilla/layout/tables/nsTableColGroupFrame.cpp
    @@ -0,0 +1,94 @@
    +/* -*- 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 "nsTableColGroupFrame.h"
    +#include "nsReflowCommand.h"
    +#include "nsIStyleContext.h"
    +#include "nsStyleConsts.h"
    +#include "nsIPresContext.h"
    +
    +static PRBool gsDebug = PR_FALSE;
    +
    +
    +nsTableColGroupFrame::nsTableColGroupFrame(nsIContent* aContent,
    +                     PRInt32     aIndexInParent,
    +                     nsIFrame*   aParentFrame)
    +  : nsContainerFrame(aContent, aIndexInParent, aParentFrame)
    +{
    +}
    +
    +nsTableColGroupFrame::~nsTableColGroupFrame()
    +{
    +}
    +
    +void nsTableColGroupFrame::Paint(nsIPresContext& aPresContext,
    +                                 nsIRenderingContext& aRenderingContext,
    +                                 const nsRect&        aDirtyRect)
    +{
    +  if (gsDebug==PR_TRUE) printf("nsTableColGroupFrame::Paint\n");
    +  PaintChildren(aPresContext, aRenderingContext, aDirtyRect);
    +}
    +
    +
    +nsIFrame::ReflowStatus
    +nsTableColGroupFrame::ResizeReflow(nsIPresContext* aPresContext,
    +                        nsReflowMetrics& aDesiredSize,
    +                        const nsSize&   aMaxSize,
    +                        nsSize*         aMaxElementSize)
    +{
    +  NS_ASSERTION(nsnull!=aPresContext, "bad arg");
    +  if (gsDebug==PR_TRUE) printf("nsTableColGroupFrame::ResizeReflow\n");
    +  aDesiredSize.width=0;
    +  aDesiredSize.height=0;
    +  if (nsnull!=aMaxElementSize)
    +  {
    +    aMaxElementSize->width=0;
    +    aMaxElementSize->height=0;
    +  }
    +  return nsIFrame::frComplete;
    +}
    +
    +nsIFrame::ReflowStatus
    +nsTableColGroupFrame::IncrementalReflow(nsIPresContext*  aPresContext,
    +                                        nsReflowMetrics& aDesiredSize,
    +                                        const nsSize&    aMaxSize,
    +                                        nsReflowCommand& aReflowCommand)
    +{
    +  NS_ASSERTION(nsnull!=aPresContext, "bad arg");
    +  ReflowStatus  status;
    +
    +  if (gsDebug==PR_TRUE) printf("nsTableColGroupFrame::IncrementalReflow\n");
    +
    +  return status;
    +}
    +
    +nsresult nsTableColGroupFrame::NewFrame(nsIFrame** aInstancePtrResult,
    +                                        nsIContent* aContent,
    +                                        PRInt32     aIndexInParent,
    +                                        nsIFrame*   aParent)
    +{
    +  NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr");
    +  if (nsnull == aInstancePtrResult) {
    +    return NS_ERROR_NULL_POINTER;
    +  }
    +  nsIFrame* it = new nsTableColGroupFrame(aContent, aIndexInParent, aParent);
    +  if (nsnull == it) {
    +    return NS_ERROR_OUT_OF_MEMORY;
    +  }
    +  *aInstancePtrResult = it;
    +  return NS_OK;
    +}
    diff --git a/mozilla/layout/tables/nsTableColGroupFrame.h b/mozilla/layout/tables/nsTableColGroupFrame.h
    new file mode 100644
    index 00000000000..260c77c8745
    --- /dev/null
    +++ b/mozilla/layout/tables/nsTableColGroupFrame.h
    @@ -0,0 +1,63 @@
    +/* -*- 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.
    + */
    +#ifndef nsTableColGroupFrame_h__
    +#define nsTableColGroupFrame_h__
    +
    +#include "nscore.h"
    +#include "nsContainerFrame.h"
    +
    +
    +/**
    + * nsTableColGroupFrame
    + * data structure to maintain information about a single table cell's frame
    + *
    + * @author  sclark
    + */
    +class nsTableColGroupFrame : public nsContainerFrame
    +{
    +public:
    +  static nsresult NewFrame(nsIFrame** aInstancePtrResult,
    +                           nsIContent* aContent,
    +                           PRInt32     aIndexInParent,
    +                           nsIFrame*   aParent);
    +
    +  virtual void  Paint(nsIPresContext& aPresContext,
    +                      nsIRenderingContext& aRenderingContext,
    +                      const nsRect& aDirtyRect);
    +
    +  ReflowStatus  ResizeReflow(nsIPresContext* aPresContext,
    +                             nsReflowMetrics& aDesiredSize,
    +                             const nsSize&   aMaxSize,
    +                             nsSize*         aMaxElementSize);
    +
    +  ReflowStatus  IncrementalReflow(nsIPresContext*  aPresContext,
    +                                  nsReflowMetrics& aDesiredSize,
    +                                  const nsSize&    aMaxSize,
    +                                  nsReflowCommand& aReflowCommand);
    +
    +protected:
    +
    +  nsTableColGroupFrame(nsIContent* aContent,
    +                       PRInt32 aIndexInParent,
    +          					   nsIFrame* aParentFrame);
    +
    +  ~nsTableColGroupFrame();
    +
    +};
    +
    +#endif
    diff --git a/mozilla/layout/tables/nsTableFrame.cpp b/mozilla/layout/tables/nsTableFrame.cpp
    new file mode 100644
    index 00000000000..d3656cc91a1
    --- /dev/null
    +++ b/mozilla/layout/tables/nsTableFrame.cpp
    @@ -0,0 +1,2541 @@
    +/* -*- 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 "nsTableFrame.h"
    +#include "nsTablePart.h"
    +#include "nsIRenderingContext.h"
    +#include "nsIStyleContext.h"
    +#include "nsIContent.h"
    +#include "nsIContentDelegate.h"
    +#include "nsCellMap.h"
    +#include "nsTableContent.h"
    +#include "nsTableCell.h"
    +#include "nsTableCellFrame.h"
    +#include "nsTableCol.h"
    +#include "nsTableRowFrame.h"
    +#include "nsTableRowGroupFrame.h"
    +#include "nsColLayoutData.h"
    +#include "nsIPresContext.h"
    +#include "nsCSSRendering.h"
    +#include "nsStyleConsts.h"
    +#include "nsCellLayoutData.h"
    +#include "nsVoidArray.h"
    +#include "prinrval.h"
    +
    +
    +#ifdef NS_DEBUG
    +static PRBool gsDebug = PR_FALSE;
    +static PRBool gsDebugCLD = PR_FALSE;
    +static PRBool gsTiming = PR_FALSE;
    +static PRBool gsDebugMBP = PR_FALSE;
    +//#define NOISY
    +//#define NOISY_FLOW
    +#else
    +static const PRBool gsDebug = PR_FALSE;
    +static const PRBool gsDebugCLD = PR_FALSE;
    +static const PRBool gsTiming = PR_FALSE;
    +static const PRBool gsDebugMBP = PR_FALSE;
    +#endif
    +
    +#ifndef max
    +#define max(x, y) ((x) > (y) ? (x) : (y))
    +#endif
    +
    +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID);
    +static NS_DEFINE_IID(kStyleColorSID, NS_STYLECOLOR_SID);
    +
    +/* ----------- InnerTableReflowState ---------- */
    +
    +struct InnerTableReflowState {
    +
    +  // The body's style molecule
    +  nsStyleMolecule* mol;
    +
    +  // The body's available size (computed from the body's parent)
    +  nsSize availSize;
    +
    +  // Margin tracking information
    +  nscoord prevMaxPosBottomMargin;
    +  nscoord prevMaxNegBottomMargin;
    +
    +  // Flags for whether the max size is unconstrained
    +  PRBool  unconstrainedWidth;
    +  PRBool  unconstrainedHeight;
    +
    +  // Running y-offset
    +  nscoord y;
    +
    +  // Flag for whether we're dealing with the first interior row group
    +  PRBool firstRowGroup;
    +
    +  InnerTableReflowState(nsIPresContext*  aPresContext,
    +                        const nsSize&    aMaxSize,
    +                        nsStyleMolecule* aMol)
    +  {
    +    mol = aMol;
    +    availSize.width = aMaxSize.width;
    +    availSize.height = aMaxSize.height;
    +    prevMaxPosBottomMargin = 0;
    +    prevMaxNegBottomMargin = 0;
    +    y=0;  // border/padding/margin???
    +    unconstrainedWidth = PRBool(aMaxSize.width == NS_UNCONSTRAINEDSIZE);
    +    unconstrainedHeight = PRBool(aMaxSize.height == NS_UNCONSTRAINEDSIZE);
    +    firstRowGroup = PR_TRUE;
    +  }
    +
    +  ~InnerTableReflowState() {
    +  }
    +};
    +
    +
    +
    +/* ----------- nsTableFrame ---------- */
    +
    +
    +nsTableFrame::nsTableFrame(nsIContent* aContent,
    +                           PRInt32 aIndexInParent,
    +                           nsIFrame* aParentFrame)
    +  : nsContainerFrame(aContent, aIndexInParent, aParentFrame),
    +    mColumnLayoutData(nsnull),
    +    mColumnWidths(nsnull),
    +    mFirstPassValid(PR_FALSE),
    +    mPass(kPASS_UNDEFINED),
    +    mIsInvariantWidth(PR_FALSE)
    +{
    +}
    +
    +/**
    + * Method to delete all owned objects assoicated
    + * with the ColumnLayoutObject instance variable
    + */
    +void nsTableFrame::DeleteColumnLayoutData()
    +{
    +  if (nsnull!=mColumnLayoutData)
    +  {
    +    PRInt32 numCols = mColumnLayoutData->Count();
    +    for (PRInt32 i = 0; iElementAt(i));
    +      delete colData;
    +    }
    +    delete mColumnLayoutData;
    +    mColumnLayoutData = nsnull;
    +  }
    +}
    +
    +nsTableFrame::~nsTableFrame()
    +{
    +  DeleteColumnLayoutData();
    +  if (nsnull!=mColumnWidths)
    +    delete [] mColumnWidths;
    +}
    +
    +
    +
    +/**
    +* Lists the column layout data which turns
    +* around and lists the cell layout data.
    +* This is for debugging purposes only.
    +*/
    +void nsTableFrame::ListColumnLayoutData(FILE* out, PRInt32 aIndent) const
    +{
    +  // if this is a continuing frame, there will be no output
    +  if (nsnull!=mColumnLayoutData)
    +  {
    +    fprintf(out,"Column Layout Data \n");
    +    
    +    PRInt32 numCols = mColumnLayoutData->Count();
    +    for (PRInt32 i = 0; iElementAt(i));
    +
    +      for (PRInt32 indent = aIndent; --indent >= 0; ) fputs("  ", out);
    +      fprintf(out,"Column Data [%d] \n",i);
    +      colData->List(out,aIndent+2);
    +    }
    +  }
    +}
    +
    +
    +/**
    + * Find the CellLayoutData assocated with the TableCell
    +**/
    +nsCellLayoutData* nsTableFrame::FindCellLayoutData(nsTableCell* aCell) 
    +{
    +  if (aCell != nsnull)
    +  {
    +    if (nsnull!=mColumnLayoutData)
    +    {
    +      PRInt32 numCols = mColumnLayoutData->Count();
    +      for (PRInt32 i = 0; iElementAt(i));
    +        PRInt32 index = colLayoutData->IndexOf(aCell);
    +        if (index != -1)
    +          return colLayoutData->ElementAt(index);
    +      }
    +    }
    +  }
    +  return nsnull;
    +}
    +
    +
    +/**
    + * For the TableCell in CellData, find the CellLayoutData assocated
    + * and add it to the list
    +**/
    +void nsTableFrame::AppendLayoutData(nsVoidArray* aList, nsTableCell* aTableCell)
    +{
    +
    +  if (aTableCell != nsnull)
    +  {
    +    nsCellLayoutData* layoutData = FindCellLayoutData(aTableCell);
    +    if (layoutData != nsnull)
    +      aList->AppendElement((void*)layoutData);
    +  }
    +}
    +
    +void nsTableFrame::ResetColumnLayoutData()
    +{
    +
    +  nsTablePart*  table = (nsTablePart*)mContent;
    +  nsCellMap*    cellMap = table->GetCellMap();
    +  PRInt32       colCount = cellMap->GetColCount();
    +  PRInt32       rowCount = cellMap->GetRowCount();
    +  PRInt32       row = 0;
    +  PRInt32       col = 0;
    +
    +  nsTableCell*  above = nsnull;
    +  nsTableCell*  below = nsnull;
    +  nsTableCell*  left = nsnull;
    +  nsTableCell*  right = nsnull;
    +
    +
    +  PRInt32       edge = 0;
    +  nsVoidArray*  boundaryCells[4];
    +
    +  for (edge = 0; edge < 4; edge++)
    +    boundaryCells[edge] = new nsVoidArray();
    +
    +
    +  if (colCount != 0 && rowCount != 0)
    +  {
    +    for (row = 0; row < rowCount; row++)
    +    {
    +      for (col = 0; col < colCount; col++)
    +      {
    +        CellData*     cellData = cellMap->GetCellAt(row,col);
    +        nsTableCell*  cell = cellData->mCell;
    +        
    +        if (!cell)
    +          continue;
    +
    +        PRInt32       colSpan = cell->GetColSpan();
    +        PRInt32       rowSpan = cell->GetRowSpan();
    +
    +        // clear the cells for all for edges
    +        for (edge = 0; edge < 4; edge++)
    +          boundaryCells[edge]->Clear();
    +
    +    
    +        // Check to see if the cell data represents the top,left
    +        // corner of a a table cell
    +
    +        // Check to see if cell the represents a left edge cell
    +        if (row == 0)
    +          above = nsnull;
    +        else
    +        {
    +          cellData = cellMap->GetCellAt(row-1,col);
    +          if (cellData != nsnull)
    +            above = cellData->mCell;
    +
    +          // Does the cell data point to the same cell?
    +          // If it is, then continue
    +          if (above != nsnull && above == cell)
    +            continue;
    +        }           
    +
    +        // Check to see if cell the represents a top edge cell
    +        if (col == 0)
    +          left == nsnull;
    +        else
    +        {
    +          cellData = cellMap->GetCellAt(row,col-1);
    +          if (cellData != nsnull)
    +            left = cellData->mCell;
    +
    +          if (left != nsnull && left == cell)
    +            continue;
    +        }
    +
    +        // If this is the top,left edged cell
    +        // Then add the cells on the for edges to the array
    +        
    +        // Do the top and bottom edge
    +        PRInt32   r,c;
    +        PRInt32   r1,r2;
    +        PRInt32   c1,c2;
    +        PRInt32   last;
    +        
    +
    +        r1 = row - 1;
    +        r2 = row + rowSpan;
    +        c = col;
    +        last = col + colSpan -1;
    +        
    +        while (c <= last)
    +        {
    +          if (r1 != -1)
    +          {
    +            // Add top edge cells
    +            if (c != col)
    +            {
    +              cellData = cellMap->GetCellAt(r1,c);
    +              if (cellData->mCell != above)
    +              {
    +                above = cellData->mCell;
    +                if (above != nsnull)
    +                  AppendLayoutData(boundaryCells[NS_SIDE_TOP],above);
    +              }
    +            }
    +            else if (above != nsnull)
    +            {
    +              AppendLayoutData(boundaryCells[NS_SIDE_TOP],above);
    +            }
    +          }
    +
    +          if (r2 < rowCount)
    +          {
    +            // Add bottom edge cells
    +            cellData = cellMap->GetCellAt(r2,c);
    +            if (cellData->mCell != below)
    +            {
    +              below = cellData->mCell;
    +              if (below != nsnull)
    +                AppendLayoutData(boundaryCells[NS_SIDE_BOTTOM],below);
    +            }
    +          }
    +          c++;
    +        }
    +
    +        // Do the left and right edge
    +        c1 = col - 1;
    +        c2 = col + colSpan;
    +        r = row ;
    +        last = row + rowSpan-1;
    +        
    +        while (r <= last)
    +        {
    +          // Add left edge cells
    +          if (c1 != -1)
    +          {
    +            if (r != row)
    +            {
    +              cellData = cellMap->GetCellAt(r,c1);
    +              if (cellData->mCell != left)
    +              {
    +                left = cellData->mCell;
    +                if (left != nsnull)
    +                  AppendLayoutData(boundaryCells[NS_SIDE_LEFT],left);
    +              }
    +            }
    +            else if (left != nsnull)
    +            {
    +              AppendLayoutData(boundaryCells[NS_SIDE_LEFT],left);
    +            }
    +          }
    +
    +          if (c2 < colCount)
    +          {
    +            // Add right edge cells
    +            cellData = cellMap->GetCellAt(r,c2);
    +            if (cellData->mCell != right)
    +            {
    +              right = cellData->mCell;
    +              if (right != nsnull)
    +                AppendLayoutData(boundaryCells[NS_SIDE_RIGHT],right);
    +            }
    +          }
    +          r++;
    +        }
    +        
    +        nsCellLayoutData* cellLayoutData = FindCellLayoutData(cell); 
    +        cellLayoutData->RecalcLayoutData(this,boundaryCells);
    +      }
    +    }
    +  }
    +  for (edge = 0; edge < 4; edge++)
    +    delete boundaryCells[edge];
    +
    +}
    +
    +
    +
    +
    +/* SEC: TODO: adjust the rect for captions */
    +void nsTableFrame::Paint(nsIPresContext& aPresContext,
    +                         nsIRenderingContext& aRenderingContext,
    +                         const nsRect& aDirtyRect)
    +{
    +  // table paint code is concerned primarily with borders and bg color
    +  nsStyleColor* myColor =
    +    (nsStyleColor*)mStyleContext->GetData(kStyleColorSID);
    +  nsStyleMolecule* myMol =
    +    (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID);
    +  NS_ASSERTION(nsnull != myColor, "null style color");
    +  NS_ASSERTION(nsnull != myMol, "null style molecule");
    +  if (nsnull!=myMol)
    +  {
    +    nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this,
    +                                    aDirtyRect, mRect, *myColor);
    +    nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this,
    +                                aDirtyRect, mRect, *myMol, 0);
    +  }
    +
    +  // for debug...
    +  if (nsIFrame::GetShowFrameBorders()) {
    +    aRenderingContext.SetColor(NS_RGB(0,128,0));
    +    aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height);
    +  }
    +
    +  PaintChildren(aPresContext, aRenderingContext, aDirtyRect);
    +}
    +
    +PRBool nsTableFrame::NeedsReflow(const nsSize& aMaxSize)
    +{
    +  PRBool result = PR_TRUE;
    +  if (PR_TRUE==mIsInvariantWidth)
    +    result = PR_FALSE;
    +  // TODO: other cases...
    +  return result;
    +}
    +
    +// SEC: TODO need to worry about continuing frames prev/next in flow for splitting across pages.
    +// SEC: TODO need to keep "first pass done" state, update it when ContentChanged notifications come in
    +
    +/* overview:
    +  if mFirstPassValid is false, this is our first time through since content was last changed
    +    set pass to 1
    +    do pass 1
    +      get min/max info for all cells in an infinite space
    +      do column balancing
    +    set mFirstPassValid to true
    +    do pass 2
    +  if pass is 1,
    +    set pass to 2
    +    use column widths to ResizeReflow cells
    +    shrinkWrap Cells in each row to tallest, realigning contents within the cell
    +*/
    +
    +/** Layout the entire inner table.
    +  */
    +nsIFrame::ReflowStatus nsTableFrame::ResizeReflow( nsIPresContext* aPresContext,
    +                                                   nsReflowMetrics& aDesiredSize,
    +                                                   const nsSize& aMaxSize,
    +                                                   nsSize* aMaxElementSize)
    +{
    +  NS_PRECONDITION(nsnull != aPresContext, "null arg");
    +  if (gsDebug==PR_TRUE) 
    +  {
    +    printf("-----------------------------------------------------------------\n");
    +    printf("nsTableFrame::ResizeReflow: maxSize=%d,%d\n",
    +                               aMaxSize.width, aMaxSize.height);
    +  }
    +
    +#ifdef NS_DEBUG
    +  PreReflowCheck();
    +#endif
    +
    +  ReflowStatus result = frComplete;
    +
    +  PRIntervalTime startTime = PR_IntervalNow();
    +
    +  if (PR_TRUE==gsDebug) 
    +    printf ("*** tableframe reflow\t\t%d\n", this);
    +
    +  if (PR_TRUE==NeedsReflow(aMaxSize))
    +  {
    +    nsStyleMolecule* tableStyleMol =
    +        (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID);
    +    NS_ASSERTION(nsnull != tableStyleMol, "null style molecule");
    +    if (nsnull==tableStyleMol)
    +      return frComplete;  // SEC:  this is an error!
    +
    +    if (PR_FALSE==IsFirstPassValid())
    +    { // we treat the table as if we've never seen the layout data before
    +      mPass = kPASS_FIRST;
    +      result = ResizeReflowPass1(aPresContext, aDesiredSize, aMaxSize, aMaxElementSize, tableStyleMol);
    +      // check result
    +    }
    +    mPass = kPASS_SECOND;
    +
    +    // assign column widths, and assign aMaxElementSize->width
    +    BalanceColumnWidths(aPresContext, tableStyleMol, aMaxSize, aMaxElementSize);
    +
    +    // assign table width
    +    SetTableWidth(aPresContext, tableStyleMol);
    +
    +    result = ResizeReflowPass2(aPresContext, aDesiredSize, aMaxSize, aMaxElementSize, tableStyleMol, 0, 0);
    +
    +    PRIntervalTime endTime = PR_IntervalNow();
    +    if (gsTiming) printf("Table reflow took %ld ticks for frame %d\n", endTime-startTime, this);
    +
    +    mPass = kPASS_UNDEFINED;
    +  }
    +  else
    +  {
    +    // set aDesiredSize and aMaxElementSize
    +  }
    +
    +#ifdef NS_DEBUG
    +  PostReflowCheck(result);
    +#endif  
    +
    +  return result;
    +}
    +
    +/** the first of 2 reflow passes
    +  * lay out the captions and row groups in an infinite space (NS_UNCONSTRAINEDSIZE)
    +  * cache the results for each caption and cell.
    +  * if successful, set mFirstPassValid=PR_TRUE, so we know we can skip this step 
    +  * next time.  mFirstPassValid is set to PR_FALSE when content is changed.
    +  * NOTE: should never get called on a continuing frame!  All cached pass1 state
    +  *       is stored in the inner table first-in-flow.
    +  */
    +nsIFrame::ReflowStatus nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext,
    +                                                       nsReflowMetrics& aDesiredSize,
    +                                                       const nsSize& aMaxSize,
    +                                                       nsSize* aMaxElementSize,
    +                                                       nsStyleMolecule* aTableStyle)
    +{
    +  NS_ASSERTION(nsnull!=aPresContext, "bad pres context param");
    +  NS_ASSERTION(nsnull!=aTableStyle, "bad style param");
    +  NS_ASSERTION(nsnull==mPrevInFlow, "illegal call, cannot call pass 1 on a continuing frame.");
    +
    +  if (gsDebug==PR_TRUE) printf("nsTableFrame::ResizeReflow Pass1: maxSize=%d,%d\n",
    +                               aMaxSize.width, aMaxSize.height);
    +  if (PR_TRUE==gsDebug) printf ("*** tableframe reflow pass1\t\t%d\n", this); 
    +  ReflowStatus result = frComplete;
    +
    +  mChildCount = 0;
    +  mFirstContentOffset = mLastContentOffset = 0;
    +
    +  nsIContent* c = mContent;
    +  NS_ASSERTION(nsnull != c, "null content");
    +  ((nsTablePart *)c)->GetMaxColumns();  // as a side effect, does important initialization
    +
    +  nsSize availSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); // availSize is the space available at any given time in the process
    +  nsSize maxSize(0, 0);       // maxSize is the size of the largest child so far in the process
    +  nsSize kidMaxSize(0,0);
    +  nsSize* pKidMaxSize = (nsnull != aMaxElementSize) ? &kidMaxSize : nsnull;
    +  nsReflowMetrics kidSize;
    +  nscoord y = 0;
    +  nscoord maxAscent = 0;
    +  nscoord maxDescent = 0;
    +  PRInt32 kidIndex = 0;
    +  PRInt32 lastIndex = c->ChildCount();
    +  PRInt32 contentOffset=0;
    +  nsIFrame* prevKidFrame = nsnull;/* XXX incremental reflow! */
    +
    +  // Compute the insets (sum of border and padding)
    +  nscoord topInset = aTableStyle->borderPadding.top;
    +  nscoord rightInset = aTableStyle->borderPadding.right;
    +  nscoord bottomInset =aTableStyle->borderPadding.bottom;
    +  nscoord leftInset = aTableStyle->borderPadding.left;
    +
    +  /* assumes that Table's children are in the following order:
    +   *  Captions
    +   *  ColGroups, in order
    +   *  THead, in order
    +   *  TFoot, in order
    +   *  TBody, in order
    +   */
    +  for (;;) {
    +    nsIContent* kid = c->ChildAt(kidIndex);   // kid: REFCNT++
    +    if (nsnull == kid) {
    +      result = frComplete;
    +      break;
    +    }
    +
    +    mLastContentIsComplete = PR_TRUE;
    +
    +    const PRInt32 contentType = ((nsTableContent *)kid)->GetType();
    +    if (contentType==nsITableContent::kTableRowGroupType)
    +    {
    +      // Resolve style
    +      nsIStyleContext* kidStyleContext =
    +        aPresContext->ResolveStyleContextFor(kid, this);
    +      NS_ASSERTION(nsnull != kidStyleContext, "null style context for kid");
    +      nsStyleMolecule* kidStyle =
    +        (nsStyleMolecule*)kidStyleContext->GetData(kStyleMoleculeSID);
    +      NS_ASSERTION(nsnull != kidStyle, "null style molecule for kid");
    +
    +      // SEC: TODO:  when content is appended or deleted, be sure to clear out the frame hierarchy!!!!
    +
    +      nsIFrame* kidFrame = ChildAt(kidIndex);
    +      // if this is the first time, allocate the caption frame
    +      if (nsnull==kidFrame)
    +      {
    +        nsIContentDelegate* kidDel;
    +        kidDel = kid->GetDelegate(aPresContext);
    +        kidFrame = kidDel->CreateFrame(aPresContext, kid, contentOffset, this);
    +        NS_RELEASE(kidDel);
    +        kidFrame->SetStyleContext(kidStyleContext);
    +      }
    +      NS_RELEASE(kidStyleContext);
    +
    +      nsSize maxKidElementSize;
    +      result = ReflowChild(kidFrame, aPresContext, kidSize, availSize, pKidMaxSize);
    +
    +      // Place the child since some of it's content fit in us.
    +      if (gsDebug) {
    +        if (nsnull != pKidMaxSize) {
    +          printf ("reflow of row group returned desired=%d,%d, max-element=%d,%d\n",
    +                  kidSize.width, kidSize.height, pKidMaxSize->width, pKidMaxSize->height);
    +        } else {
    +          printf ("reflow of row group returned desired=%d,%d\n", kidSize.width, kidSize.height);
    +        }
    +      }
    +      PRInt32 yCoord = y;
    +      if (NS_UNCONSTRAINEDSIZE!=yCoord)
    +        yCoord+= topInset;
    +      kidFrame->SetRect(nsRect(leftInset, yCoord,
    +                               kidSize.width, kidSize.height));
    +      if (NS_UNCONSTRAINEDSIZE==kidSize.height)
    +        y = NS_UNCONSTRAINEDSIZE;
    +      else
    +        y += kidSize.height;
    +      if (nsnull != pKidMaxSize) {
    +        if (pKidMaxSize->width > maxSize.width) {
    +          maxSize.width = pKidMaxSize->width;
    +        }
    +        if (pKidMaxSize->height > maxSize.height) {
    +          maxSize.height = pKidMaxSize->height;
    +        }
    +      }
    +
    +      // Link child frame into the list of children
    +      if (nsnull != prevKidFrame) {
    +        prevKidFrame->SetNextSibling(kidFrame);
    +      } else {
    +        // Our first child (**blush**)
    +        mFirstChild = kidFrame;
    +        SetFirstContentOffset(kidFrame);
    +        if (gsDebug) printf("INNER: set first content offset to %d\n", GetFirstContentOffset()); //@@@
    +      }
    +      prevKidFrame = kidFrame;
    +      mChildCount++;
    +
    +      if (frNotComplete == result) {
    +        // If the child didn't finish layout then it means that it used
    +        // up all of our available space (or needs us to split).
    +        mLastContentIsComplete = PR_FALSE;
    +        NS_RELEASE(kid);  // kid: REFCNT--
    +        break;
    +      }
    +    }
    +    contentOffset++;
    +    kidIndex++;
    +    if (frNotComplete == result) {
    +      // If the child didn't finish layout then it means that it used
    +      // up all of our available space (or needs us to split).
    +      mLastContentIsComplete = PR_FALSE;
    +      NS_RELEASE(kid);  // kid: REFCNT--
    +      break;
    +    }
    +    NS_RELEASE(kid);  // kid: REFCNT--
    +  }
    +
    +  if (nsnull != prevKidFrame) {
    +    NS_ASSERTION(LastChild() == prevKidFrame, "unexpected last child");
    +                                           // can't use SetLastContentOffset here
    +    mLastContentOffset = contentOffset-1;    // takes into account colGroup frame we're not using
    +    if (gsDebug) printf("INNER: set last content offset to %d\n", GetLastContentOffset()); //@@@
    +  }
    +
    +  mFirstPassValid = PR_TRUE;
    +
    +  return result;
    +}
    +
    +/** the second of 2 reflow passes
    +  */
    +nsIFrame::ReflowStatus nsTableFrame::ResizeReflowPass2(nsIPresContext* aPresContext,
    +                                                       nsReflowMetrics& aDesiredSize,
    +                                                       const nsSize& aMaxSize,
    +                                                       nsSize* aMaxElementSize,
    +                                                       nsStyleMolecule* aTableStyle,
    +                                                       PRInt32 aMinCaptionWidth,
    +                                                       PRInt32 mMaxCaptionWidth)
    +{
    +  if (PR_TRUE==gsDebug) printf ("***tableframe reflow pass2\t\t%d\n", this);
    +  if (gsDebug==PR_TRUE)
    +    printf("nsTableFrame::ResizeReflow Pass2: maxSize=%d,%d\n",
    +           aMaxSize.width, aMaxSize.height);
    +
    +  ReflowStatus result = frComplete;
    +
    +  // now that we've computed the column  width information, reflow all children
    +  nsIContent* c = mContent;
    +  NS_ASSERTION(nsnull != c, "null kid");
    +  nsSize kidMaxSize(0,0);
    +
    +  PRInt32 kidIndex = 0;
    +  PRInt32 lastIndex = c->ChildCount();
    +  nsIFrame* prevKidFrame = nsnull;/* XXX incremental reflow! */
    +
    +#ifdef NS_DEBUG
    +  PreReflowCheck();
    +#endif
    +
    +  // Initialize out parameter
    +  if (nsnull != aMaxElementSize) {
    +    aMaxElementSize->width = 0;
    +    aMaxElementSize->height = 0;
    +  }
    +
    +  PRBool        reflowMappedOK = PR_TRUE;
    +  ReflowStatus  status = frComplete;
    +
    +  // Check for an overflow list
    +  MoveOverflowToChildList();
    +
    +  nsStyleMolecule* myMol =
    +    (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID);
    +  InnerTableReflowState state(aPresContext, aMaxSize, myMol);
    +
    +  // Reflow the existing frames
    +  if (nsnull != mFirstChild) {
    +    reflowMappedOK = ReflowMappedChildren(aPresContext, state, aMaxElementSize);
    +    if (PR_FALSE == reflowMappedOK) {
    +      status = frNotComplete;
    +    }
    +  }
    +
    +  // Did we successfully relow our mapped children?
    +  if (PR_TRUE == reflowMappedOK) {
    +    // Any space left?
    +    if ((nsnull != mFirstChild) && (state.availSize.height <= 0)) {
    +      // No space left. Don't try to pull-up children or reflow unmapped
    +      if (NextChildOffset() < mContent->ChildCount()) {
    +        status = frNotComplete;
    +      }
    +    } else if (NextChildOffset() < mContent->ChildCount()) {
    +      // Try and pull-up some children from a next-in-flow
    +      if ((nsnull == mNextInFlow) ||
    +          PullUpChildren(aPresContext, state, aMaxElementSize)) {
    +        // If we still have unmapped children then create some new frames
    +        if (NextChildOffset() < mContent->ChildCount()) {
    +          status = ReflowUnmappedChildren(aPresContext, state, aMaxElementSize);
    +        }
    +      } else {
    +        // We were unable to pull-up all the existing frames from the
    +        // next in flow
    +        status = frNotComplete;
    +      }
    +    }
    +  }
    +
    +  // Return our size and our status
    +
    +  if (frComplete == status) {
    +    // Don't forget to add in the bottom margin from our last child.
    +    // Only add it in if there's room for it.
    +    nscoord margin = state.prevMaxPosBottomMargin -
    +      state.prevMaxNegBottomMargin;
    +    if (state.availSize.height >= margin) {
    +      state.y += margin;
    +    }
    +  }
    +
    +  // Return our desired rect
    +  NS_ASSERTION(0width, aMaxElementSize->height);
    +    else
    +      printf("Reflow complete, returning aDesiredSize = %d,%d and NSNULL aMaxElementSize\n",
    +              aDesiredSize.width, aDesiredSize.height);
    +  }
    +
    +  // SEC: assign our real width and height based on this reflow step and return
    +
    +  mPass = kPASS_UNDEFINED;  // we're no longer in-process
    +
    +#ifdef NS_DEBUG
    +  PostReflowCheck(status);
    +#endif
    +
    +  return status;
    +
    +}
    +
    +// Collapse child's top margin with previous bottom margin
    +nscoord nsTableFrame::GetTopMarginFor(nsIPresContext*      aCX,
    +                                      InnerTableReflowState& aState,
    +                                      nsStyleMolecule*     aKidMol)
    +{
    +  nscoord margin;
    +  nscoord maxNegTopMargin = 0;
    +  nscoord maxPosTopMargin = 0;
    +  if ((margin = aKidMol->margin.top) < 0) {
    +    maxNegTopMargin = -margin;
    +  } else {
    +    maxPosTopMargin = margin;
    +  }
    +
    +  nscoord maxPos = PR_MAX(aState.prevMaxPosBottomMargin, maxPosTopMargin);
    +  nscoord maxNeg = PR_MAX(aState.prevMaxNegBottomMargin, maxNegTopMargin);
    +  margin = maxPos - maxNeg;
    +
    +  return margin;
    +}
    +
    +// Position and size aKidFrame and update our reflow state. The origin of
    +// aKidRect is relative to the upper-left origin of our frame, and includes
    +// any left/top margin.
    +void nsTableFrame::PlaceChild(nsIPresContext*    aPresContext,
    +                              InnerTableReflowState& aState,
    +                              nsIFrame*          aKidFrame,
    +                              const nsRect&      aKidRect,
    +                              nsStyleMolecule*   aKidMol,
    +                              nsSize*            aMaxElementSize,
    +                              nsSize&            aKidMaxElementSize)
    +{
    +  // Place and size the child
    +  aKidFrame->SetRect(aKidRect);
    +
    +  // Adjust the running y-offset
    +  aState.y += aKidRect.height;
    +
    +  // If our height is constrained then update the available height
    +  if (PR_FALSE == aState.unconstrainedHeight) {
    +    aState.availSize.height -= aKidRect.height;
    +  }
    +
    +  // Update the maximum element size
    +  if (PR_TRUE==aState.firstRowGroup)
    +  {
    +    aState.firstRowGroup = PR_FALSE;
    +    if (nsnull != aMaxElementSize) {
    +      aMaxElementSize->width = aKidMaxElementSize.width;
    +      aMaxElementSize->height = aKidMaxElementSize.height;
    +    }
    +  }
    +}
    +
    +/**
    + * Reflow the frames we've already created
    + *
    + * @param   aPresContext presentation context to use
    + * @param   aState current inline state
    + * @return  true if we successfully reflowed all the mapped children and false
    + *            otherwise, e.g. we pushed children to the next in flow
    + */
    +PRBool nsTableFrame::ReflowMappedChildren( nsIPresContext*      aPresContext,
    +                                           InnerTableReflowState& aState,
    +                                           nsSize*              aMaxElementSize)
    +{
    +#ifdef NS_DEBUG
    +  VerifyLastIsComplete();
    +#endif
    +#ifdef NOISY
    +  ListTag(stdout);
    +  printf(": reflow mapped (childCount=%d) [%d,%d,%c]\n",
    +         mChildCount,
    +         mFirstContentOffset, mLastContentOffset,
    +         (mLastContentIsComplete ? 'T' : 'F'));
    +#ifdef NOISY_FLOW
    +  {
    +    nsTableFrame* flow = (nsTableFrame*) mNextInFlow;
    +    while (flow != 0) {
    +      printf("  %p: [%d,%d,%c]\n",
    +             flow, flow->mFirstContentOffset, flow->mLastContentOffset,
    +             (flow->mLastContentIsComplete ? 'T' : 'F'));
    +      flow = (nsTableFrame*) flow->mNextInFlow;
    +    }
    +  }
    +#endif
    +#endif
    +  NS_PRECONDITION(nsnull != mFirstChild, "no children");
    +
    +  PRInt32   childCount = 0;
    +  nsIFrame* prevKidFrame = nsnull;
    +
    +  // Remember our original mLastContentIsComplete so that if we end up
    +  // having to push children, we have the correct value to hand to
    +  // PushChildren.
    +  PRBool    lastContentIsComplete = mLastContentIsComplete;
    +
    +  nsSize    kidMaxElementSize;
    +  nsSize*   pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull;
    +  PRBool    result = PR_TRUE;
    +
    +  for (nsIFrame*  kidFrame = mFirstChild; nsnull != kidFrame; ) {
    +    nsSize                  kidAvailSize(aState.availSize);
    +    nsReflowMetrics         desiredSize;
    +    nsIFrame::ReflowStatus  status;
    +
    +    // Get top margin for this kid
    +    nsIContent* kid = kidFrame->GetContent();
    +    if (((nsTableContent *)kid)->GetType() == nsITableContent::kTableRowGroupType)
    +    { // skip children that are not row groups
    +      nsIStyleContext* kidSC = kidFrame->GetStyleContext(aPresContext);
    +      nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID);
    +      nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol);
    +      nscoord bottomMargin = kidMol->margin.bottom;
    +      NS_RELEASE(kid);
    +      NS_RELEASE(kidSC);
    +
    +      // Figure out the amount of available size for the child (subtract
    +      // off the top margin we are going to apply to it)
    +      if (PR_FALSE == aState.unconstrainedHeight) {
    +        kidAvailSize.height -= topMargin;
    +      }
    +      // Subtract off for left and right margin
    +      if (PR_FALSE == aState.unconstrainedWidth) {
    +        kidAvailSize.width -= kidMol->margin.left + kidMol->margin.right;
    +      }
    +
    +      // Only skip the reflow if this is not our first child and we are
    +      // out of space.
    +      if ((kidFrame == mFirstChild) || (kidAvailSize.height > 0)) {
    +        // Reflow the child into the available space
    +        status = ReflowChild(kidFrame, aPresContext, desiredSize,
    +                             kidAvailSize, pKidMaxElementSize);
    +      }
    +
    +      // Did the child fit?
    +      if ((kidFrame != mFirstChild) &&
    +          ((kidAvailSize.height <= 0) ||
    +           (desiredSize.height > kidAvailSize.height)))
    +      {
    +        // The child's height is too big to fit at all in our remaining space,
    +        // and it's not our first child.
    +        //
    +        // Note that if the width is too big that's okay and we allow the
    +        // child to extend horizontally outside of the reflow area
    +
    +        // Since we are giving the next-in-flow our last child, we
    +        // give it our original mLastContentIsComplete, too (in case we
    +        // are pushing into an empty next-in-flow)
    +        PushChildren(kidFrame, prevKidFrame, lastContentIsComplete);
    +
    +        // Our mLastContentIsComplete was already set by the last kid we
    +        // reflowed reflow's status
    +        result = PR_FALSE;
    +        break;
    +      }
    +
    +      // Place the child after taking into account it's margin
    +      aState.y += topMargin;
    +      nsRect kidRect (0, 0, desiredSize.width, desiredSize.height);
    +      kidRect.x += kidMol->margin.left;
    +      kidRect.y += aState.y;
    +      PlaceChild(aPresContext, aState, kidFrame, kidRect, kidMol, aMaxElementSize,
    +                 kidMaxElementSize);
    +      if (bottomMargin < 0) {
    +        aState.prevMaxNegBottomMargin = -bottomMargin;
    +      } else {
    +        aState.prevMaxPosBottomMargin = bottomMargin;
    +      }
    +      childCount++;
    +
    +      // Update mLastContentIsComplete now that this kid fits
    +      mLastContentIsComplete = PRBool(status == frComplete);
    +
    +      // Special handling for incomplete children
    +      if (frNotComplete == status) {
    +        // XXX It's good to assume that we might still have room
    +        // even if the child didn't complete (floaters will want this)
    +        nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow();
    +        if (nsnull == kidNextInFlow) {
    +          // No the child isn't complete, and it doesn't have a next in flow so
    +          // create a continuing frame. This hooks the child into the flow.
    +          nsIFrame* continuingFrame =
    +            kidFrame->CreateContinuingFrame(aPresContext, this);
    +
    +          // Insert the frame. We'll reflow it next pass through the loop
    +          nsIFrame* nextSib = kidFrame->GetNextSibling();
    +          continuingFrame->SetNextSibling(nextSib);
    +          kidFrame->SetNextSibling(continuingFrame);
    +          if (nsnull == nextSib) {
    +            // Assume that the continuation frame we just created is
    +            // complete, for now. It will get reflowed by our
    +            // next-in-flow (we are going to push it now)
    +            lastContentIsComplete = PR_TRUE;
    +          }
    +        }
    +      }
    +    }
    +
    +    // Get the next child
    +    prevKidFrame = kidFrame;
    +    kidFrame = kidFrame->GetNextSibling();
    +
    +    // XXX talk with troy about checking for available space here
    +  }
    +
    +  // Update the child count
    +  mChildCount = childCount;
    +  NS_POSTCONDITION(LengthOf(mFirstChild) == mChildCount, "bad child count");
    +
    +  // Set the last content offset based on the last child we mapped.
    +  NS_ASSERTION(LastChild() == prevKidFrame, "unexpected last child");
    +  SetLastContentOffset(prevKidFrame);
    +
    +#ifdef NS_DEBUG
    +  VerifyLastIsComplete();
    +#endif
    +#ifdef NOISY
    +  ListTag(stdout);
    +  printf(": reflow mapped %sok (childCount=%d) [%d,%d,%c]\n",
    +         (result ? "" : "NOT "),
    +         mChildCount,
    +         mFirstContentOffset, mLastContentOffset,
    +         (mLastContentIsComplete ? 'T' : 'F'));
    +#ifdef NOISY_FLOW
    +  {
    +    nsTableFrame* flow = (nsTableFrame*) mNextInFlow;
    +    while (flow != 0) {
    +      printf("  %p: [%d,%d,%c]\n",
    +             flow, flow->mFirstContentOffset, flow->mLastContentOffset,
    +             (flow->mLastContentIsComplete ? 'T' : 'F'));
    +      flow = (nsTableFrame*) flow->mNextInFlow;
    +    }
    +  }
    +#endif
    +#endif
    +  return result;
    +}
    +
    +/**
    + * Try and pull-up frames from our next-in-flow
    + *
    + * @param   aPresContext presentation context to use
    + * @param   aState current inline state
    + * @return  true if we successfully pulled-up all the children and false
    + *            otherwise, e.g. child didn't fit
    + */
    +PRBool nsTableFrame::PullUpChildren(nsIPresContext*      aPresContext,
    +                                            InnerTableReflowState& aState,
    +                                            nsSize*              aMaxElementSize)
    +{
    +#ifdef NS_DEBUG
    +  VerifyLastIsComplete();
    +#endif
    +#ifdef NOISY
    +  ListTag(stdout);
    +  printf(": pullup (childCount=%d) [%d,%d,%c]\n",
    +         mChildCount,
    +         mFirstContentOffset, mLastContentOffset,
    +         (mLastContentIsComplete ? 'T' : 'F'));
    +#ifdef NOISY_FLOW
    +  {
    +    nsTableFrame* flow = (nsTableFrame*) mNextInFlow;
    +    while (flow != 0) {
    +      printf("  %p: [%d,%d,%c]\n",
    +             flow, flow->mFirstContentOffset, flow->mLastContentOffset,
    +             (flow->mLastContentIsComplete ? 'T' : 'F'));
    +      flow = (nsTableFrame*) flow->mNextInFlow;
    +    }
    +  }
    +#endif
    +#endif
    +  NS_PRECONDITION(nsnull != mNextInFlow, "null next-in-flow");
    +  nsTableFrame*  nextInFlow = (nsTableFrame*)mNextInFlow;
    +  nsSize        kidMaxElementSize;
    +  nsSize*       pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull;
    +
    +  // The frame previous to the current frame we are reflowing. This
    +  // starts out initially as our last frame.
    +  nsIFrame*     prevKidFrame = LastChild();
    +
    +  // This will hold the prevKidFrame's mLastContentIsComplete
    +  // status. If we have to push the frame that follows prevKidFrame
    +  // then this will become our mLastContentIsComplete state. Since
    +  // prevKidFrame is initially our last frame, it's completion status
    +  // is our mLastContentIsComplete value.
    +  PRBool        prevLastContentIsComplete = mLastContentIsComplete;
    +  PRBool        result = PR_TRUE;
    +
    +  while (nsnull != nextInFlow) {
    +    nsReflowMetrics desiredSize;
    +    nsSize  kidAvailSize(aState.availSize);
    +
    +    // Get first available frame from the next-in-flow
    +    nsIFrame* kidFrame = PullUpOneChild(nextInFlow, prevKidFrame);
    +    if (nsnull == kidFrame) {
    +      // We've pulled up all the children from that next-in-flow, so
    +      // move to the next next-in-flow.
    +      nextInFlow = (nsTableFrame*) nextInFlow->mNextInFlow;
    +      continue;
    +    }
    +
    +    // Get top margin for this kid
    +    nsIContent* kid = kidFrame->GetContent();
    +    nsIStyleContext* kidSC = kidFrame->GetStyleContext(aPresContext);
    +    nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID);
    +    nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol);
    +    nscoord bottomMargin = kidMol->margin.bottom;
    +
    +    // Figure out the amount of available size for the child (subtract
    +    // off the top margin we are going to apply to it)
    +    if (PR_FALSE == aState.unconstrainedHeight) {
    +      kidAvailSize.height -= topMargin;
    +    }
    +    // Subtract off for left and right margin
    +    if (PR_FALSE == aState.unconstrainedWidth) {
    +      kidAvailSize.width -= kidMol->margin.left + kidMol->margin.right;
    +    }
    +
    +    ReflowStatus status;
    +    do {
    +      // Only skip the reflow if this is not our first child and we are
    +      // out of space.
    +      if ((kidFrame == mFirstChild) || (kidAvailSize.height > 0)) {
    +        status = ReflowChild(kidFrame, aPresContext, desiredSize,
    +                             kidAvailSize, pKidMaxElementSize);
    +      }
    +
    +      // Did the child fit?
    +      if ((kidFrame != mFirstChild) &&
    +          ((kidAvailSize.height <= 0) ||
    +           (desiredSize.height > kidAvailSize.height)))
    +      {
    +        // The child's height is too big to fit at all in our remaining space,
    +        // and it wouldn't have been our first child.
    +        //
    +        // Note that if the width is too big that's okay and we allow the
    +        // child to extend horizontally outside of the reflow area
    +        PRBool lastComplete = PRBool(nsnull == kidFrame->GetNextInFlow());
    +        PushChildren(kidFrame, prevKidFrame, lastComplete);
    +        mLastContentIsComplete = prevLastContentIsComplete;
    +        mChildCount--;
    +        result = PR_FALSE;
    +        NS_RELEASE(kid);
    +        NS_RELEASE(kidSC);
    +        goto push_done;
    +      }
    +
    +      // Place the child
    +      aState.y += topMargin;
    +      nsRect kidRect (0, 0, desiredSize.width, desiredSize.height);
    +      kidRect.x += kidMol->margin.left;
    +      kidRect.y += aState.y;
    +      PlaceChild(aPresContext, aState, kidFrame, kidRect, kidMol, aMaxElementSize,
    +                 kidMaxElementSize);
    +      if (bottomMargin < 0) {
    +        aState.prevMaxNegBottomMargin = -bottomMargin;
    +      } else {
    +        aState.prevMaxPosBottomMargin = bottomMargin;
    +      }
    +      mLastContentIsComplete = PRBool(status == frComplete);
    +
    +#ifdef NOISY
    +      ListTag(stdout);
    +      printf(": pulled up ");
    +      ((nsFrame*)kidFrame)->ListTag(stdout);
    +      printf("\n");
    +#endif
    +
    +      // Is the child we just pulled up complete?
    +      if (frNotComplete == status) {
    +        // No the child isn't complete.
    +        nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow();
    +        if (nsnull == kidNextInFlow) {
    +          // The child doesn't have a next-in-flow so create a
    +          // continuing frame. The creation appends it to the flow and
    +          // prepares it for reflow.
    +          nsIFrame* continuingFrame =
    +            kidFrame->CreateContinuingFrame(aPresContext, this);
    +
    +          // Add the continuing frame to our sibling list.
    +          continuingFrame->SetNextSibling(kidFrame->GetNextSibling());
    +          kidFrame->SetNextSibling(continuingFrame);
    +          prevKidFrame = kidFrame;
    +          prevLastContentIsComplete = mLastContentIsComplete;
    +          kidFrame = continuingFrame;
    +          mChildCount++;
    +        } else {
    +          // The child has a next-in-flow, but it's not one of ours.
    +          // It *must* be in one of our next-in-flows. Collect it
    +          // then.
    +          NS_ASSERTION(kidNextInFlow->GetGeometricParent() != this,
    +                       "busted kid next-in-flow");
    +          break;
    +        }
    +      }
    +    } while (frNotComplete == status);
    +    NS_RELEASE(kid);
    +    NS_RELEASE(kidSC);
    +
    +    prevKidFrame = kidFrame;
    +    prevLastContentIsComplete = mLastContentIsComplete;
    +  }
    +
    + push_done:;
    +  // Update our last content index
    +  if (nsnull != prevKidFrame) {
    +    NS_ASSERTION(LastChild() == prevKidFrame, "bad last child");
    +    SetLastContentOffset(prevKidFrame);
    +  }
    +
    +  // We need to make sure the first content offset is correct for any empty
    +  // next-in-flow frames (frames where we pulled up all the child frames)
    +  nextInFlow = (nsTableFrame*)mNextInFlow;
    +  if ((nsnull != nextInFlow) && (nsnull == nextInFlow->mFirstChild)) {
    +    // We have at least one empty frame. Did we succesfully pull up all the
    +    // child frames?
    +    if (PR_FALSE == result) {
    +      // No, so we need to adjust the first content offset of all the empty
    +      // frames
    +      AdjustOffsetOfEmptyNextInFlows();
    +#ifdef NS_DEBUG
    +    } else {
    +      // Yes, we successfully pulled up all the child frames which means all
    +      // the next-in-flows must be empty. Do a sanity check
    +      while (nsnull != nextInFlow) {
    +        NS_ASSERTION(nsnull == nextInFlow->mFirstChild, "non-empty next-in-flow");
    +        nextInFlow = (nsTableFrame*)nextInFlow->GetNextInFlow();
    +      }
    +#endif
    +    }
    +  }
    +
    +#ifdef NS_DEBUG
    +  PRInt32 len = LengthOf(mFirstChild);
    +  NS_ASSERTION(len == mChildCount, "bad child count");
    +  VerifyLastIsComplete();
    +#endif
    +#ifdef NOISY
    +  ListTag(stdout);
    +  printf(": pullup %sok (childCount=%d) [%d,%d,%c]\n",
    +         (result ? "" : "NOT "),
    +         mChildCount,
    +         mFirstContentOffset, mLastContentOffset,
    +         (mLastContentIsComplete ? 'T' : 'F'));
    +#ifdef NOISY_FLOW
    +  {
    +    nsTableFrame* flow = (nsTableFrame*) mNextInFlow;
    +    while (flow != 0) {
    +      printf("  %p: [%d,%d,%c]\n",
    +             flow, flow->mFirstContentOffset, flow->mLastContentOffset,
    +             (flow->mLastContentIsComplete ? 'T' : 'F'));
    +      flow = (nsTableFrame*) flow->mNextInFlow;
    +    }
    +  }
    +#endif
    +#endif
    +  return result;
    +}
    +
    +/**
    + * Create new frames for content we haven't yet mapped
    + *
    + * @param   aPresContext presentation context to use
    + * @param   aState current inline state
    + * @return  frComplete if all content has been mapped and frNotComplete
    + *            if we should be continued
    + */
    +nsIFrame::ReflowStatus
    +nsTableFrame::ReflowUnmappedChildren(nsIPresContext*      aPresContext,
    +                                             InnerTableReflowState& aState,
    +                                             nsSize*              aMaxElementSize)
    +{
    +#ifdef NS_DEBUG
    +  VerifyLastIsComplete();
    +#endif
    +  nsIFrame*     kidPrevInFlow = nsnull;
    +  ReflowStatus  result = frNotComplete;
    +
    +  // If we have no children and we have a prev-in-flow then we need to pick
    +  // up where it left off. If we have children, e.g. we're being resized, then
    +  // our content offset should already be set correctly...
    +  if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) {
    +    nsTableFrame* prev = (nsTableFrame*)mPrevInFlow;
    +    NS_ASSERTION(prev->mLastContentOffset >= prev->mFirstContentOffset, "bad prevInFlow");
    +
    +    mFirstContentOffset = prev->NextChildOffset();
    +    if (!prev->mLastContentIsComplete) {
    +      // Our prev-in-flow's last child is not complete
    +      kidPrevInFlow = prev->LastChild();
    +    }
    +  }
    +
    +  PRBool originalLastContentIsComplete = mLastContentIsComplete;
    +
    +  // Place our children, one at a time, until we are out of children
    +  nsSize    kidMaxElementSize;
    +  nsSize*   pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull;
    +  PRInt32   kidIndex = NextChildOffset();
    +  nsIFrame* prevKidFrame = LastChild();  // XXX remember this...
    +
    +  for (;;) {
    +    // Get the next content object
    +    nsIContent* kid = mContent->ChildAt(kidIndex);
    +    if (nsnull == kid) {
    +      result = frComplete;
    +      break;
    +    }
    +
    +    // Make sure we still have room left
    +    if (aState.availSize.height <= 0) {
    +      // Note: return status was set to frNotComplete above...
    +      NS_RELEASE(kid);
    +      break;
    +    }
    +
    +    // Resolve style
    +    nsIStyleContext* kidStyleContext =
    +      aPresContext->ResolveStyleContextFor(kid, this);
    +    nsStyleMolecule* kidMol =
    +      (nsStyleMolecule*)kidStyleContext->GetData(kStyleMoleculeSID);
    +    nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol);
    +    nscoord bottomMargin = kidMol->margin.bottom;
    +
    +    nsIFrame*       kidFrame;
    +    ReflowStatus    status;
    +
    +    // Create a child frame
    +    if (nsnull == kidPrevInFlow) {
    +      nsIContentDelegate* kidDel = nsnull;
    +      kidDel = kid->GetDelegate(aPresContext);
    +      kidFrame = kidDel->CreateFrame(aPresContext, kid, kidIndex, this);
    +      NS_RELEASE(kidDel);
    +      kidFrame->SetStyleContext(kidStyleContext);
    +    } else {
    +      kidFrame = kidPrevInFlow->CreateContinuingFrame(aPresContext, this);
    +    }
    +
    +    // Link the child frame into the list of children and update the
    +    // child count
    +    if (nsnull != prevKidFrame) {
    +      NS_ASSERTION(nsnull == prevKidFrame->GetNextSibling(), "bad append");
    +      prevKidFrame->SetNextSibling(kidFrame);
    +    } else {
    +      NS_ASSERTION(nsnull == mFirstChild, "bad create");
    +      mFirstChild = kidFrame;
    +      SetFirstContentOffset(kidFrame);
    +    }
    +    mChildCount++;
    +
    +    do {
    +      nsSize  kidAvailSize(aState.availSize);
    +      nsReflowMetrics  desiredSize;
    +
    +      // Figure out the amount of available size for the child (subtract
    +      // off the margin we are going to apply to it)
    +      if (PR_FALSE == aState.unconstrainedHeight) {
    +        kidAvailSize.height -= topMargin;
    +      }
    +      // Subtract off for left and right margin
    +      if (PR_FALSE == aState.unconstrainedWidth) {
    +        kidAvailSize.width -= kidMol->margin.left + kidMol->margin.right;
    +      }
    +
    +      // Try to reflow the child into the available space. It might not
    +      // fit or might need continuing
    +      if (kidAvailSize.height > 0) {
    +        status = ReflowChild(kidFrame, aPresContext, desiredSize,
    +                             kidAvailSize, pKidMaxElementSize);
    +      }
    +
    +      // Did the child fit?
    +      if ((nsnull != mFirstChild) &&
    +          ((kidAvailSize.height <= 0) ||
    +           (desiredSize.height > kidAvailSize.height))) {
    +        // The child's height is too big to fit in our remaining
    +        // space, and it's not our first child.
    +        NS_ASSERTION(nsnull == mOverflowList, "bad overflow list");
    +        NS_ASSERTION(nsnull == mNextInFlow, "whoops");
    +
    +        // Chop off the part of our child list that's being overflowed
    +        NS_ASSERTION(prevKidFrame->GetNextSibling() == kidFrame, "bad list");
    +        prevKidFrame->SetNextSibling(nsnull);
    +
    +        // Create overflow list
    +        mOverflowList = kidFrame;
    +
    +        // Fixup child count by subtracting off the number of children
    +        // that just ended up on the reflow list.
    +        PRInt32 overflowKids = 0;
    +        nsIFrame* f = kidFrame;
    +        while (nsnull != f) {
    +          overflowKids++;
    +          f = f->GetNextSibling();
    +        }
    +        mChildCount -= overflowKids;
    +        NS_RELEASE(kidStyleContext);
    +        NS_RELEASE(kid);
    +        goto done;
    +      }
    +
    +      // Advance y by the topMargin between children. Zero out the
    +      // topMargin in case this frame is continued because
    +      // continuations do not have a top margin. Update the prev
    +      // bottom margin state in the body reflow state so that we can
    +      // apply the bottom margin when we hit the next child (or
    +      // finish).
    +      aState.y += topMargin;
    +      nsRect kidRect (0, 0, desiredSize.width, desiredSize.height);
    +      kidRect.x += kidMol->margin.left;
    +      kidRect.y += aState.y;
    +      PlaceChild(aPresContext, aState, kidFrame, kidRect, kidMol, aMaxElementSize,
    +                 kidMaxElementSize);
    +      if (bottomMargin < 0) {
    +        aState.prevMaxNegBottomMargin = -bottomMargin;
    +      } else {
    +        aState.prevMaxPosBottomMargin = bottomMargin;
    +      }
    +      topMargin = 0;
    +
    +      mLastContentIsComplete = PRBool(status == frComplete);
    +      if (frNotComplete == status) {
    +        // Child didn't complete so create a continuing frame
    +        kidPrevInFlow = kidFrame;
    +        nsIFrame* continuingFrame =
    +          kidFrame->CreateContinuingFrame(aPresContext, this);
    +
    +        // Add the continuing frame to the sibling list
    +        continuingFrame->SetNextSibling(kidFrame->GetNextSibling());
    +        kidFrame->SetNextSibling(continuingFrame);
    +        prevKidFrame = kidFrame;
    +        kidFrame = continuingFrame;
    +        mChildCount++;
    +
    +        // XXX We probably shouldn't assume that there is no room for
    +        // the continuation
    +      }
    +    } while (frNotComplete == status);
    +    NS_RELEASE(kidStyleContext);
    +    NS_RELEASE(kid);
    +
    +    prevKidFrame = kidFrame;
    +    kidPrevInFlow = nsnull;
    +
    +    // Update the kidIndex
    +    kidIndex++;
    +  }
    +
    +done:
    +  // Update the content mapping
    +  NS_ASSERTION(LastChild() == prevKidFrame, "bad last child");
    +  if (0 != mChildCount) {
    +    SetLastContentOffset(prevKidFrame);
    +  }
    +#ifdef NS_DEBUG
    +  PRInt32 len = LengthOf(mFirstChild);
    +  NS_ASSERTION(len == mChildCount, "bad child count");
    +  VerifyLastIsComplete();
    +#endif
    +  return result;
    +}
    +
    +/**
    +  Now I've got all the cells laid out in an infinite space.
    +  For each column, use the min size for each cell in that column
    +  along with the attributes of the table, column group, and column
    +  to assign widths to each column.
    +  */
    +// use the cell map to determine which cell is in which column.
    +void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext, 
    +                                       nsStyleMolecule* aTableStyle,
    +                                       const nsSize& aMaxSize, 
    +                                       nsSize* aMaxElementSize)
    +{
    +  NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!");
    +
    +  if (gsDebug)
    +    printf ("BalanceColumnWidths...\n");
    +
    +  nsVoidArray *columnLayoutData = GetColumnLayoutData();
    +  PRInt32 numCols = columnLayoutData->Count();
    +  if (nsnull==mColumnWidths)
    +  {
    +    mColumnWidths = new PRInt32[numCols];
    +    // SEC should be a memset
    +    for (PRInt32 i = 0; ifixedWidth)         // if there is a fixed width attribute, use it
    +  {
    +    maxWidth = aTableStyle->fixedWidth;
    +  }
    +  else if ((NS_UNCONSTRAINEDSIZE!=maxWidth) && 
    +           (-1!=aTableStyle->proportionalWidth  &&  0!=aTableStyle->proportionalWidth))
    +  {
    +    maxWidth = (maxWidth*aTableStyle->proportionalWidth)/100;
    +  }
    +  // now, if maxWidth is not NS_UNCONSTRAINED, subtract out my border and padding
    +  if (NS_UNCONSTRAINEDSIZE!=maxWidth)
    +  {
    +    maxWidth -= aTableStyle->borderPadding.left + aTableStyle->borderPadding.right;
    +    if (0>maxWidth)  // nonsense style specification
    +      maxWidth = 0;
    +  }
    +
    +  if (gsDebug) printf ("  maxWidth=%d from aMaxSize=%d,%d\n", maxWidth, aMaxSize.width, aMaxSize.height);
    +
    +  // Step 1 - assign the width of all fixed-width columns
    +  AssignFixedColumnWidths(aPresContext, maxWidth, numCols, aTableStyle,
    +                          totalFixedWidth, minTableWidth, maxTableWidth);
    +
    +  if (nsnull!=aMaxElementSize)
    +  {
    +    aMaxElementSize->width = minTableWidth;
    +    if (gsDebug) printf("  setting aMaxElementSize->width = %d\n", aMaxElementSize->width);
    +  }
    +  else
    +  {
    +    if (gsDebug) printf("  nsnull aMaxElementSize\n");
    +  }
    +
    +  // Step 2 - assign the width of all proportional-width columns in the remaining space
    +  PRInt32 availWidth=maxWidth - totalFixedWidth;
    +  if (gsDebug==PR_TRUE) printf ("Step 2...\n  availWidth = %d\n", availWidth);
    +  if (TableIsAutoWidth())
    +  {
    +    if (gsDebug==PR_TRUE) printf ("  calling BalanceProportionalColumnsForAutoWidthTable\n");
    +    BalanceProportionalColumnsForAutoWidthTable(aPresContext, aTableStyle, 
    +                                                availWidth, maxWidth,
    +                                                minTableWidth, maxTableWidth);
    +  }
    +  else
    +  {
    +    if (gsDebug==PR_TRUE) printf ("  calling BalanceProportionalColumnsForSpecifiedWidthTable\n");
    +    BalanceProportionalColumnsForSpecifiedWidthTable(aPresContext, aTableStyle,
    +                                                     availWidth, maxWidth,
    +                                                     minTableWidth, maxTableWidth);
    +  }
    +
    +/*
    +STEP 1
    +for every col
    +  if the col has a fixed width
    +    set the width to max(fixed width, maxElementSize)
    +    if the cell spans columns, divide the cell width between the columns
    +  else skip it for now
    +
    +take borders and padding into account
    +
    +STEP 2
    +determine the min and max size for the table width
    +if col is proportionately specified
    +  if (col width specified to 0)
    +    col width = minColWidth
    +  else if (minTableWidth >= aMaxSize.width)
    +    set col widths to min, install a hor. scroll bar
    +  else if (maxTableWidth <= aMaxSize.width)
    +    set each col to its max size
    +  else
    +    W = aMaxSize.width -  minTableWidth
    +    D = maxTableWidth - minTableWidth
    +    for each col
    +      d = maxColWidth - minColWidth
    +      col width = minColWidth + ((d*W)/D)
    +
    +STEP 3
    +if there is space left over
    +  for every col
    +    if col is proportionately specified
    +      add space to col width until it is that proportion of the table width
    +      do this non-destructively in case there isn't enough space
    +  if there isn't enough space as determined in the prior step,
    +    add space in proportion to the proportionate width attribute
    +  */
    +
    +}
    +
    +// Step 1 - assign the width of all fixed-width columns, 
    +  //          and calculate min/max table width
    +    // still needs to take insets into account
    +PRBool nsTableFrame::AssignFixedColumnWidths(nsIPresContext* aPresContext, PRInt32 maxWidth, 
    +                                             PRInt32 aNumCols, nsStyleMolecule* aTableStyleMol,
    +                                             PRInt32 &aTotalFixedWidth,
    +                                             PRInt32 &aMinTableWidth, PRInt32 &aMaxTableWidth)
    +{
    +  NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!");
    +
    +  if (gsDebug==PR_TRUE) printf ("  AssignFixedColumnWidths\n");
    +  for (PRInt32 colIndex = 0; colIndexElementAt(colIndex));
    +    NS_ASSERTION(nsnull != colData, "bad column data");
    +    nsTableCol *col = colData->GetCol();    // col: ADDREF++
    +    NS_ASSERTION(nsnull != col, "bad col");
    +    nsStyleMolecule* colStyle =
    +      (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID);
    +    NS_ASSERTION(nsnull != colStyle, "bad style for col.");
    +    // need to track min/max column width for setting min/max table widths
    +    PRInt32 minColWidth = 0;
    +    PRInt32 maxColWidth = 0;
    +    nsVoidArray *cells = colData->GetCells();
    +    PRInt32 numCells = cells->Count();
    +    if (gsDebug==PR_TRUE) printf ("  for column %d  numCells = %d\n", colIndex, numCells);
    +    for (PRInt32 cellIndex = 0; cellIndexElementAt(cellIndex));
    +      NS_ASSERTION(nsnull != data, "bad data");
    +      nsSize * cellMinSize = data->GetMaxElementSize();
    +      nsReflowMetrics * cellDesiredSize = data->GetDesiredSize();
    +      NS_ASSERTION(nsnull != cellDesiredSize, "bad cellDesiredSize");
    +      if (gsDebug==PR_TRUE) 
    +        printf ("    for cell %d  min = %d,%d  and  des = %d,%d\n", cellIndex, cellMinSize->width, cellMinSize->height,
    +                cellDesiredSize->width, cellDesiredSize->height);
    +      /* the first cell in a column (in row 0) has special standing.
    +       * if the first cell has a width specification, it overrides the COL width
    +       */
    +      if (0==cellIndex)
    +      {
    +        // SEC: TODO -- when we have a style system, set the mol for the col
    +        nsCellLayoutData * data = (nsCellLayoutData *)(cells->ElementAt(0));
    +        nsTableCellFrame *cellFrame = data->GetCellFrame();
    +        nsTableCell *cell = (nsTableCell *)cellFrame->GetContent();          // cell: REFCNT++
    +        nsStyleMolecule* cellStyle = (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID);
    +        NS_ASSERTION(nsnull != cellStyle, "bad style for cell.");
    +        // SEC: this is the code to replace
    +        if (-1!=cellStyle->fixedWidth)
    +          colStyle->proportionalWidth = cellStyle->proportionalWidth;
    +        if (-1!=cellStyle->proportionalWidth)
    +          colStyle->proportionalWidth = cellStyle->proportionalWidth;
    +        // SEC: end code to replace
    +        NS_RELEASE(cell);                                                    // cell: REFCNT--  
    +      }
    +      if (-1!=colStyle->fixedWidth)
    +      { // this col has fixed width, so set the cell's width 
    +        // to the larger of (specified width, largest max_element_size of the cells in the column)      
    +        PRInt32 widthForThisCell = max(cellMinSize->width, colStyle->fixedWidth);
    +        if (mColumnWidths[colIndex] < widthForThisCell)
    +        {
    +          if (gsDebug) printf ("    setting fixed width to %d\n",widthForThisCell);
    +          mColumnWidths[colIndex] = widthForThisCell;
    +          maxColWidth = widthForThisCell;
    +        }
    +      }
    +      // regardless of the width specification, keep track of the min/max column widths
    +      /* TODO:  must distribute COLSPAN'd cell widths between columns, either here 
    +       *        or in the subsequent Balance***ColumnWidth routines 
    +       */
    +      if (minColWidth < cellMinSize->width)
    +        minColWidth = cellMinSize->width;
    +      if (maxColWidth < cellDesiredSize->width)
    +        maxColWidth = cellDesiredSize->width;
    +      if (gsDebug==PR_TRUE) 
    +        printf ("    after cell %d, minColWidth = %d and maxColWidth = %d\n", cellIndex, minColWidth, maxColWidth);
    +      /* take colspan into account? */
    +      /*
    +      PRInt32 colSpan = col->GetColSpan();
    +      cellIndex += colSpan-1;
    +      */
    +    }
    +    if (-1!=colStyle->fixedWidth)
    +    {
    +      // if the col is fixed-width, expand the col to the specified fixed width if necessary
    +      if (colStyle->fixedWidth > mColumnWidths[colIndex])
    +        mColumnWidths[colIndex] = colStyle->fixedWidth;
    +      // keep a running total of the amount of space taken up by all fixed-width columns
    +      aTotalFixedWidth += mColumnWidths[colIndex];
    +      if (gsDebug) 
    +        printf ("    after col %d, aTotalFixedWidth = %d\n", colIndex, aTotalFixedWidth);
    +    }
    +    // add col[i] metrics to the running totals for the table min/max width
    +    if (NS_UNCONSTRAINEDSIZE!=aMinTableWidth)
    +      aMinTableWidth += minColWidth;  // SEC: insets!
    +    if (aMinTableWidth<=0) 
    +      aMinTableWidth = NS_UNCONSTRAINEDSIZE; // handle overflow
    +    if (NS_UNCONSTRAINEDSIZE!=aMaxTableWidth)
    +      aMaxTableWidth += maxColWidth;  // SEC: insets!
    +    if (aMaxTableWidth<=0) 
    +      aMaxTableWidth = NS_UNCONSTRAINEDSIZE; // handle overflow
    +    if (gsDebug==PR_TRUE) 
    +      printf ("  after this col, minTableWidth = %d and maxTableWidth = %d\n", aMinTableWidth, aMaxTableWidth);
    +  
    +    NS_IF_RELEASE(col);               // col: ADDREF--
    +  } // end Step 1 for fixed-width columns
    +  return PR_TRUE;
    +}
    +
    +PRBool nsTableFrame::BalanceProportionalColumnsForSpecifiedWidthTable(nsIPresContext* aPresContext,
    +                                                                      nsStyleMolecule* aTableStyleMol,
    +                                                                      PRInt32 aAvailWidth,
    +                                                                      PRInt32 aMaxWidth,
    +                                                                      PRInt32 aMinTableWidth, 
    +                                                                      PRInt32 aMaxTableWidth)
    +{
    +  NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!");
    +
    +  PRBool result = PR_TRUE;
    +
    +  if (NS_UNCONSTRAINEDSIZE==aMaxWidth)
    +  { // the max width of the table fits comfortably in the available space
    +    if (gsDebug) printf ("  * table laying out in NS_UNCONSTRAINEDSIZE, calling BalanceColumnsTableFits\n");
    +    result = BalanceColumnsTableFits(aPresContext, aTableStyleMol, aAvailWidth);
    +  }
    +  else if (aMinTableWidth > aMaxWidth)
    +  { // the table doesn't fit in the available space
    +    if (gsDebug) printf ("  * min table does not fit, calling SetColumnsToMinWidth\n");
    +    result = SetColumnsToMinWidth(aPresContext);
    +  }
    +  else if (aMaxTableWidth < aMaxWidth)
    +  { // the max width of the table fits comfortably in the available space
    +    if (gsDebug) printf ("  * table desired size fits, calling BalanceColumnsTableFits\n");
    +    result = BalanceColumnsTableFits(aPresContext, aTableStyleMol, aAvailWidth);
    +  }
    +  else
    +  { // the table fits somewhere between its min and desired size
    +    if (gsDebug) printf ("  * table desired size does not fit, calling BalanceColumnsHTML4Constrained\n");
    +    result = BalanceColumnsHTML4Constrained(aPresContext, aTableStyleMol, aAvailWidth,
    +                                            aMaxWidth, aMinTableWidth, aMaxTableWidth);
    +  }
    +  return result;
    +}
    +
    +PRBool nsTableFrame::BalanceProportionalColumnsForAutoWidthTable( nsIPresContext* aPresContext,
    +                                                                  nsStyleMolecule* aTableStyleMol,
    +                                                                  PRInt32 aAvailWidth,
    +                                                                  PRInt32 aMaxWidth,
    +                                                                  PRInt32 aMinTableWidth, 
    +                                                                  PRInt32 aMaxTableWidth)
    +{
    +  PRBool result = PR_TRUE;
    +
    +  if (NS_UNCONSTRAINEDSIZE==aMaxWidth)
    +  { // the max width of the table fits comfortably in the available space
    +    if (gsDebug) printf ("  * table laying out in NS_UNCONSTRAINEDSIZE, calling BalanceColumnsTableFits\n");
    +    result = BalanceColumnsTableFits(aPresContext, aTableStyleMol, aAvailWidth);
    +  }
    +  else if (aMinTableWidth > aMaxWidth)
    +  { // the table doesn't fit in the available space
    +    if (gsDebug) printf ("  * min table does not fit, calling SetColumnsToMinWidth\n");
    +    result = SetColumnsToMinWidth(aPresContext);
    +  }
    +  else if (aMaxTableWidth < aMaxWidth)
    +  { // the max width of the table fits comfortably in the available space
    +    if (gsDebug) printf ("  * table desired size fits, calling BalanceColumnsTableFits\n");
    +    result = BalanceColumnsTableFits(aPresContext, aTableStyleMol, aAvailWidth);
    +  }
    +  else
    +  { // the table fits somewhere between its min and desired size
    +    if (gsDebug) printf ("  * table desired size does not fit, calling BalanceColumnsHTML4Constrained\n");
    +    result = BalanceColumnsHTML4Constrained(aPresContext, aTableStyleMol, aAvailWidth,
    +                                            aMaxWidth, aMinTableWidth, aMaxTableWidth);
    +  }
    +  return result;
    +}
    +
    +PRBool nsTableFrame::SetColumnsToMinWidth(nsIPresContext* aPresContext)
    +{
    +  PRBool result = PR_TRUE;
    +  nsVoidArray *columnLayoutData = GetColumnLayoutData();
    +  PRInt32 numCols = columnLayoutData->Count();
    +  for (PRInt32 colIndex = 0; colIndexElementAt(colIndex));
    +    nsTableCol *col = colData->GetCol();  // col: ADDREF++
    +    nsStyleMolecule* colStyle =
    +      (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID);
    +    nsVoidArray *cells = colData->GetCells();
    +    PRInt32 minColWidth = 0;
    +    PRInt32 maxColWidth = 0;
    +    PRInt32 numCells = cells->Count();
    +    if (gsDebug==PR_TRUE) printf ("  for col %d\n", colIndex);
    +    if (PR_TRUE==IsProportionalWidth(colStyle))
    +    {
    +      for (PRInt32 cellIndex = 0; cellIndexElementAt(cellIndex));
    +        NS_ASSERTION(nsnull != data, "bad data");
    +        nsSize * cellMinSize = data->GetMaxElementSize();
    +        NS_ASSERTION(nsnull != cellMinSize, "bad cellMinSize");
    +        nsReflowMetrics * cellDesiredSize = data->GetDesiredSize();
    +        NS_ASSERTION(nsnull != cellDesiredSize, "bad cellDesiredSize");
    +        if (minColWidth < cellMinSize->width)
    +          minColWidth = cellMinSize->width;
    +        if (maxColWidth < cellDesiredSize->width)
    +          maxColWidth = cellDesiredSize->width;
    +        /*
    +        if (gsDebug==PR_TRUE) 
    +          printf ("    after cell %d, minColWidth = %d and maxColWidth = %d\n", 
    +                  cellIndex, minColWidth, maxColWidth);
    +        */
    +      }
    +
    +      if (gsDebug==PR_TRUE) 
    +      {
    +        printf ("  for determining width of col %d %s:\n",colIndex, IsProportionalWidth(colStyle)? "(P)":"(A)");
    +        printf ("    minColWidth = %d and maxColWidth = %d\n", minColWidth, maxColWidth);
    +      }
    +      if (PR_TRUE==IsProportionalWidth(colStyle))
    +      { // this col has proportional width, so set its width based on the table width
    +        mColumnWidths[colIndex] = minColWidth;
    +        if (gsDebug==PR_TRUE) 
    +          printf ("  2: col %d, set to width = %d\n", colIndex, mColumnWidths[colIndex]);
    +      }
    +    }
    +    NS_IF_RELEASE(col);               // col: ADDREF--
    +  }
    +  return result;
    +}
    +
    +PRBool nsTableFrame::BalanceColumnsTableFits(nsIPresContext* aPresContext, 
    +                                             nsStyleMolecule* aTableStyleMol, 
    +                                             PRInt32 aAvailWidth)
    +{
    +  NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!");
    +
    +  PRBool result = PR_TRUE;
    +  nsVoidArray *columnLayoutData = GetColumnLayoutData();
    +  PRInt32 numCols = columnLayoutData->Count();
    +  for (PRInt32 colIndex = 0; colIndexElementAt(colIndex));
    +    nsTableCol *col = colData->GetCol();  // col: ADDREF++
    +    nsStyleMolecule* colStyle =
    +      (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID);
    +    nsVoidArray *cells = colData->GetCells();
    +    PRInt32 minColWidth = 0;
    +    PRInt32 maxColWidth = 0;
    +    PRInt32 numCells = cells->Count();
    +    if (gsDebug==PR_TRUE) printf ("  for col %d\n", colIndex);
    +    /* TODO:  must distribute COLSPAN'd cell widths between columns, either here 
    +     *        or in the prior Balance***ColumnWidth routines 
    +     */
    +    if (PR_TRUE==IsProportionalWidth(colStyle))
    +    {
    +      for (PRInt32 cellIndex = 0; cellIndexElementAt(cellIndex));
    +        NS_ASSERTION(nsnull != data, "bad data");
    +        nsSize * cellMinSize = data->GetMaxElementSize();
    +        NS_ASSERTION(nsnull != cellMinSize, "bad cellMinSize");
    +        nsReflowMetrics * cellDesiredSize = data->GetDesiredSize();
    +        NS_ASSERTION(nsnull != cellDesiredSize, "bad cellDesiredSize");
    +        if (minColWidth < cellMinSize->width)
    +          minColWidth = cellMinSize->width;
    +        if (maxColWidth < cellDesiredSize->width)
    +          maxColWidth = cellDesiredSize->width;
    +        if (gsDebug==PR_TRUE) 
    +          printf ("    after cell %d, minColWidth = %d and maxColWidth = %d\n", 
    +                  cellIndex, minColWidth, maxColWidth);
    +      }
    +
    +      if (gsDebug==PR_TRUE) 
    +      {
    +        printf ("  for determining width of col %d %s:\n",colIndex, IsProportionalWidth(colStyle)? "(P)":"(A)");
    +        printf ("    minColWidth = %d and maxColWidth = %d\n", minColWidth, maxColWidth);
    +        printf ("    aAvailWidth = %d\n", aAvailWidth);
    +      }
    +      if (PR_TRUE==IsProportionalWidth(colStyle))
    +      { // this col has proportional width, so set its width based on the table width
    +        if (0==colStyle->proportionalWidth)
    +        { // col width is specified to be the minimum
    +          mColumnWidths[colIndex] = minColWidth;
    +          if (gsDebug==PR_TRUE) 
    +            printf ("  3 (0): col %d set to min width = %d because style set proportionalWidth=0\n", 
    +                    colIndex, mColumnWidths[colIndex]);
    +        }
    +        if (PR_TRUE==AutoColumnWidths(aTableStyleMol))
    +        {  // give each remaining column it's desired width
    +           // if there is width left over, we'll factor that in after this loop is complete
    +          mColumnWidths[colIndex] = maxColWidth;
    +          if (gsDebug==PR_TRUE) 
    +            printf ("  3a: col %d with availWidth %d, set to width = %d\n", 
    +                    colIndex, aAvailWidth, mColumnWidths[colIndex]);
    +        }
    +        else
    +        {  // give each remaining column an equal percentage of the remaining space
    +          PRInt32 percentage = -1;
    +          if (NS_UNCONSTRAINEDSIZE==aAvailWidth)
    +          {
    +            mColumnWidths[colIndex] = maxColWidth;
    +          }
    +          else
    +          {
    +            percentage = colStyle->proportionalWidth;
    +            if (-1==percentage)
    +              percentage = 100/numCols;
    +            mColumnWidths[colIndex] = (percentage*aAvailWidth)/100;
    +            // if the column was computed to be too small, enlarge the column
    +            if (mColumnWidths[colIndex] <= minColWidth)
    +              mColumnWidths[colIndex] = minColWidth;
    +          }
    +          if (gsDebug==PR_TRUE) 
    +            printf ("  3b: col %d given %d percent of availWidth %d, set to width = %d\n", 
    +                    colIndex, percentage, aAvailWidth, mColumnWidths[colIndex]);
    +        }
    +      }
    +    }
    +    NS_IF_RELEASE(col);               // col: ADDREF--
    +  }
    +  return result;
    +}
    +
    +PRBool nsTableFrame::BalanceColumnsHTML4Constrained(nsIPresContext* aPresContext,
    +                                                    nsStyleMolecule* aTableStyleMol, 
    +                                                    PRInt32 aAvailWidth,
    +                                                    PRInt32 aMaxWidth,
    +                                                    PRInt32 aMinTableWidth, 
    +                                                    PRInt32 aMaxTableWidth)
    +{
    +  NS_ASSERTION(nsnull==mPrevInFlow, "never ever call me on a continuing frame!");
    +
    +  PRBool result = PR_TRUE;
    +  PRInt32 maxOfAllMinColWidths = 0;
    +  nsVoidArray *columnLayoutData = GetColumnLayoutData();
    +  PRInt32 numCols = columnLayoutData->Count();
    +  for (PRInt32 colIndex = 0; colIndexElementAt(colIndex));
    +    nsTableCol *col = colData->GetCol();  // col: ADDREF++
    +    nsStyleMolecule* colStyle =
    +      (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID);
    +    nsVoidArray *cells = colData->GetCells();
    +    PRInt32 minColWidth = 0;
    +    PRInt32 maxColWidth = 0;
    +    PRInt32 numCells = cells->Count();
    +    if (gsDebug==PR_TRUE) printf ("  for col %d\n", colIndex);
    +    if (PR_TRUE==IsProportionalWidth(colStyle))
    +    {
    +      for (PRInt32 cellIndex = 0; cellIndexElementAt(cellIndex));
    +        NS_ASSERTION(nsnull != data, "bad data");
    +        nsSize * cellMinSize = data->GetMaxElementSize();
    +        NS_ASSERTION(nsnull != cellMinSize, "bad cellMinSize");
    +        nsReflowMetrics * cellDesiredSize = data->GetDesiredSize();
    +        NS_ASSERTION(nsnull != cellDesiredSize, "bad cellDesiredSize");
    +        if (minColWidth < cellMinSize->width)
    +          minColWidth = cellMinSize->width;
    +        if (maxColWidth < cellDesiredSize->width)
    +          maxColWidth = cellDesiredSize->width;
    +        /*
    +        if (gsDebug==PR_TRUE) 
    +          printf ("    after cell %d, minColWidth = %d and maxColWidth = %d\n", 
    +                  cellIndex, minColWidth, maxColWidth);
    +        */
    +      }
    +
    +      if (gsDebug==PR_TRUE) 
    +      {
    +        printf ("  for determining width of col %d %s:\n",colIndex, IsProportionalWidth(colStyle)? "(P)":"(A)");
    +        printf ("    minTableWidth = %d and maxTableWidth = %d\n", aMinTableWidth, aMaxTableWidth);
    +        printf ("    minColWidth = %d and maxColWidth = %d\n", minColWidth, maxColWidth);
    +        printf ("    aAvailWidth = %d\n", aAvailWidth);
    +      }
    +      if (PR_TRUE==IsProportionalWidth(colStyle))
    +      { // this col has proportional width, so set its width based on the table width
    +        // the table fits in the space somewhere between its min and max size
    +        // so dole out the available space appropriately
    +        if (0==colStyle->proportionalWidth)
    +        { // col width is specified to be the minimum
    +          mColumnWidths[colIndex] = minColWidth;
    +          if (gsDebug==PR_TRUE) 
    +            printf ("  4 (0): col %d set to min width = %d because style set proportionalWidth=0\n", 
    +                    colIndex, mColumnWidths[colIndex]);
    +        }
    +        else if (AutoColumnWidths(aTableStyleMol))
    +        {
    +          PRInt32 W = aMaxWidth - aMinTableWidth;
    +          PRInt32 D = aMaxTableWidth - aMinTableWidth;
    +          PRInt32 d = maxColWidth - minColWidth;
    +          mColumnWidths[colIndex] = minColWidth + ((d*W)/D);
    +          if (gsDebug==PR_TRUE) 
    +            printf ("  4 auto-width:  col %d  W=%d  D=%d  d=%d, set to width = %d\n", 
    +                    colIndex, W, D, d, mColumnWidths[colIndex]);
    +        }
    +        else
    +        {  // give each remaining column an equal percentage of the remaining space
    +          PRInt32 percentage = colStyle->proportionalWidth;
    +          if (-1==percentage)
    +            percentage = 100/numCols;
    +          mColumnWidths[colIndex] = (percentage*aAvailWidth)/100;
    +          // if the column was computed to be too small, enlarge the column
    +          if (mColumnWidths[colIndex] <= minColWidth)
    +          {
    +            mColumnWidths[colIndex] = minColWidth;
    +            if (maxOfAllMinColWidths < minColWidth)
    +              maxOfAllMinColWidths = minColWidth;
    +          }
    +          if (gsDebug==PR_TRUE) 
    +          {
    +            printf ("  4 equal width: col %d given %d percent of availWidth %d, set to width = %d\n", 
    +                    colIndex, percentage, aAvailWidth, mColumnWidths[colIndex]);
    +            if (0!=maxOfAllMinColWidths)
    +              printf("   and setting maxOfAllMins to %d\n", maxOfAllMinColWidths);
    +          }
    +        }
    +      }
    +    }
    +    NS_IF_RELEASE(col);               // col: ADDREF--
    +  }
    +
    +  // post-process if necessary
    +
    +  // if columns have equal width, and some column's content couldn't squeeze into the computed size, 
    +  // then expand every column to the min size of the column with the largest min size
    +  if (!AutoColumnWidths(aTableStyleMol) && 0!=maxOfAllMinColWidths)
    +  {
    +    if (gsDebug==PR_TRUE) printf("  EqualColWidths specified, so setting all col widths to %d\n", maxOfAllMinColWidths);
    +    for (PRInt32 colIndex = 0; colIndexCount();
    +  for (PRInt32 i = 0; iborderPadding.right;
    +  nscoord leftInset = aTableStyle->borderPadding.left;
    +  tableWidth += (leftInset + rightInset);
    +  nsRect tableSize = GetRect();
    +  tableSize.width = tableWidth;
    +  if (gsDebug==PR_TRUE)
    +  {
    +    printf ("setting table rect to %d, %d after adding insets %d, %d\n", 
    +            tableSize.width, tableSize.height, rightInset, leftInset);
    +  }
    +  SetRect(tableSize);
    +}
    +
    +/**
    +  */
    +void nsTableFrame::ShrinkWrapChildren(nsIPresContext* aPresContext, 
    +                                      nsReflowMetrics& aDesiredSize,
    +                                      nsSize* aMaxElementSize)
    +{
    +#ifdef NS_DEBUG
    +  PRBool gsDebugWas = gsDebug;
    +  gsDebug = PR_FALSE;  // turn on debug in this method
    +#endif
    +  // iterate children, tell all row groups to ShrinkWrap
    +  PRInt32 childCount = ChildCount();
    +  PRBool atLeastOneRowSpanningCell = PR_FALSE;
    +  PRInt32 tableHeight = 0;
    +  for (PRInt32 i = 0; i < childCount; i++)
    +  {
    +    PRInt32 childHeight=0;
    +    // for every child that is a rowFrame, set the row frame height  = sum of row heights
    +    nsIFrame * kidFrame = ChildAt(i); // frames are not ref counted
    +    NS_ASSERTION(nsnull != kidFrame, "bad kid frame");
    +    nsTableContent* kid = (nsTableContent*)(kidFrame->GetContent());  // kid: REFCNT++
    +    NS_ASSERTION(nsnull != kid, "bad kid");
    +    if (kid->GetType() == nsITableContent::kTableRowGroupType)
    +    {
    +      /* Step 1:  set the row height to the height of the tallest cell,
    +       *          and resize all cells in that row to that height (except cells with rowspan>1)
    +       */
    +      PRInt32 rowGroupHeight = 0;
    +      nsTableRowGroupFrame * rowGroupFrame = (nsTableRowGroupFrame *)kidFrame;
    +      PRInt32 numRows = rowGroupFrame->ChildCount();
    +      PRInt32 *rowHeights = new PRInt32[numRows];
    +      if (gsDebug==PR_TRUE) printf("Height Step 1...\n");
    +      for (PRInt32 rowIndex = 0; rowIndex < numRows; rowIndex++)
    +      {
    +        // get the height of the tallest cell in the row (excluding cells that span rows)
    +        nsTableRowFrame *rowFrame = (nsTableRowFrame *)(rowGroupFrame->ChildAt(rowIndex));
    +        NS_ASSERTION(nsnull != rowFrame, "bad row frame");
    +        rowHeights[rowIndex] = rowFrame->GetTallestChild();
    +        rowFrame->SizeTo(rowFrame->GetWidth(), rowHeights[rowIndex]);
    +        rowGroupHeight += rowHeights[rowIndex];
    +        // resize all the cells based on the rowHeight
    +        PRInt32 numCells = rowFrame->ChildCount();
    +        for (PRInt32 cellIndex = 0; cellIndex < numCells; cellIndex++)
    +        {
    +          nsTableCellFrame *cellFrame = (nsTableCellFrame *)(rowFrame->ChildAt(cellIndex));
    +          PRInt32 rowSpan = cellFrame->GetRowSpan();
    +          if (1==rowSpan)
    +          {
    +            if (gsDebug==PR_TRUE) printf("  setting cell[%d,%d] height to %d\n", rowIndex, cellIndex, rowHeights[rowIndex]);
    +            cellFrame->SizeTo(cellFrame->GetWidth(), rowHeights[rowIndex]);
    +            // Realign cell content based on new height
    +            cellFrame->VerticallyAlignChild(aPresContext);
    +          }
    +          else
    +          {
    +            if (gsDebug==PR_TRUE) printf("  skipping cell[%d,%d] with a desired height of %d\n", rowIndex, cellIndex, cellFrame->GetHeight());
    +            atLeastOneRowSpanningCell = PR_TRUE;
    +          }
    +        }
    +      }
    +
    +      /* Step 2:  now account for cells that span rows.
    +       *          a spanning cell's height is the sum of the heights of the rows it spans,
    +       *          or it's own desired height, whichever is greater.
    +       *          If the cell's desired height is the larger value, resize the rows and contained
    +       *          cells by an equal percentage of the additional space.
    +       */
    +      /* TODO
    +       * 1. optimization, if (PR_TRUE==atLeastOneRowSpanningCell) ... otherwise skip this step entirely
    +       * 2. find cases where spanning cells effect other spanning cells that began in rows above themselves.
    +       *    I think in this case, we have to make another pass through step 2.
    +       *    There should be a "rational" check to terminate that kind of loop after n passes, probably 3 or 4.
    +       */
    +      if (gsDebug==PR_TRUE) printf("Height Step 2...\n");
    +      rowGroupHeight=0;
    +      for (rowIndex = 0; rowIndex < numRows; rowIndex++)
    +      {
    +        nsTableRowFrame *rowFrame = (nsTableRowFrame *)(rowGroupFrame->ChildAt(rowIndex));
    +        PRInt32 numCells = rowFrame->ChildCount();
    +        for (PRInt32 cellIndex = 0; cellIndex < numCells; cellIndex++)
    +        {
    +          nsTableCellFrame *cellFrame = (nsTableCellFrame *)(rowFrame->ChildAt(cellIndex));
    +          PRInt32 rowSpan = cellFrame->GetRowSpan();
    +          if (1cellFrame->GetHeight())
    +            {
    +              if (gsDebug==PR_TRUE) printf("  cell[%d,%d] fits, setting height to %d\n", rowIndex, cellIndex, heightOfRowsSpanned);
    +              cellFrame->SizeTo(cellFrame->GetWidth(), heightOfRowsSpanned);
    +              // Realign cell content based on new height
    +              cellFrame->VerticallyAlignChild(aPresContext);
    +            }
    +            /* otherwise, we have a real mess on our hands.
    +             * distribute the excess height to the rows effected, and to the cells in those rows
    +             */
    +            else
    +            {
    +              PRInt32 excessHeight = cellFrame->GetHeight() - heightOfRowsSpanned;
    +              PRInt32 excessHeightPerRow = excessHeight/rowSpan;
    +              if (gsDebug==PR_TRUE) printf("  cell[%d,%d] does not fit, excessHeight = %d, excessHeightPerRow = %d\n", 
    +                      rowIndex, cellIndex, excessHeight, excessHeightPerRow);
    +              // for the rows effected...
    +              for (i=rowIndex; iChildAt(i));
    +                if (iSizeTo(rowFrameToBeResized->GetWidth(), rowHeights[i]);
    +                  PRInt32 cellCount = rowFrameToBeResized->ChildCount();
    +                  for (PRInt32 j=0; jChildAt(j));
    +                    if (frame->GetRowSpan()==1)
    +                    {
    +                      if (gsDebug==PR_TRUE) printf("      cell[%d, %d] set height to %d\n", i, j, frame->GetHeight()+excessHeightPerRow);
    +                      frame->SizeTo(frame->GetWidth(), frame->GetHeight()+excessHeightPerRow);
    +                      // Realign cell content based on new height
    +                      frame->VerticallyAlignChild(aPresContext);
    +                    }
    +                  }
    +                }
    +                // if we're dealing with a row below the row containing the spanning cell, 
    +                // push that row down by the amount we've expanded the cell heights by
    +                if (i>rowIndex)
    +                {
    +                  nsRect rowRect = rowFrameToBeResized->GetRect();
    +                  rowFrameToBeResized->MoveTo(rowRect.x, rowRect.y + (excessHeightPerRow*(i-rowIndex)));
    +                  if (gsDebug==PR_TRUE) printf("      row %d moved to y-offset %d\n", i, 
    +                                                rowRect.y + (excessHeightPerRow*(i-rowIndex)));
    +                }
    +              }
    +            }
    +          }
    +        }
    +        rowGroupHeight += rowHeights[rowIndex];
    +      }
    +      if (gsDebug==PR_TRUE) printf("row group height set to %d\n", rowGroupHeight);
    +      rowGroupFrame->SizeTo(rowGroupFrame->GetWidth(), rowGroupHeight);
    +      tableHeight += rowGroupHeight;
    +    }
    +    NS_RELEASE(kid);                                                  // kid: REFCNT--
    +  }
    +  if (0!=tableHeight)
    +  {
    +    if (gsDebug==PR_TRUE) printf("table desired height set to %d\n", tableHeight);
    +    aDesiredSize.height = tableHeight;
    +  }
    +#ifdef NS_DEBUG
    +  gsDebug = gsDebugWas;
    +#endif
    +}
    +
    +PRBool nsTableFrame::IsProportionalWidth(nsStyleMolecule* aMol)
    +{
    +  PRBool result = PR_FALSE;
    +  if ((-1!=aMol->proportionalWidth) ||
    +      ((-1==aMol->proportionalWidth) && (-1==aMol->fixedWidth)))
    +    result = PR_TRUE;
    +  return result;
    +}
    +
    +/**
    +  */
    +nsIFrame::ReflowStatus
    +nsTableFrame::IncrementalReflow(nsIPresContext*  aCX,
    +                              nsReflowMetrics& aDesiredSize,
    +                              const nsSize&    aMaxSize,
    +                              nsReflowCommand& aReflowCommand)
    +{
    +  NS_ASSERTION(nsnull != aCX, "bad arg");
    +  if (gsDebug==PR_TRUE) printf ("nsTableFrame::IncrementalReflow: maxSize=%d,%d\n",
    +                                aMaxSize.width, aMaxSize.height);
    +
    +  // mFirstPassValid needs to be set somewhere in response to change notifications.
    +
    +  aDesiredSize.width = mRect.width;
    +  aDesiredSize.height = mRect.height;
    +  return frComplete;
    +}
    +
    +void nsTableFrame::VerticallyAlignChildren(nsIPresContext* aPresContext,
    +                                          nscoord* aAscents,
    +                                          nscoord aMaxAscent,
    +                                          nscoord aMaxHeight)
    +{
    +}
    +
    +nsVoidArray * nsTableFrame::GetColumnLayoutData()
    +{
    +  nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
    +  NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
    +  return firstInFlow->mColumnLayoutData;
    +}
    +
    +/** Associate aData with the cell at (aRow,aCol)
    +  * @return PR_TRUE if the data was successfully associated with a Cell
    +  *         PR_FALSE if there was an error, such as aRow or aCol being invalid
    +  */
    +PRBool nsTableFrame::SetCellLayoutData(nsCellLayoutData * aData, nsTableCell *aCell)
    +{
    +  NS_ASSERTION(nsnull != aData, "bad arg");
    +  NS_ASSERTION(nsnull != aCell, "bad arg");
    +
    +  PRBool result = PR_TRUE;
    +
    +  nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
    +  NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
    +  if (this!=firstInFlow)
    +    result = firstInFlow->SetCellLayoutData(aData, aCell);
    +  else
    +  {
    +    if (kPASS_FIRST==GetReflowPass())
    +    {
    +      if (nsnull==mColumnLayoutData)
    +      {
    +        mColumnLayoutData = new nsVoidArray();
    +        NS_ASSERTION(nsnull != mColumnLayoutData, "bad alloc");
    +        nsTablePart * tablePart = (nsTablePart *)mContent;
    +        PRInt32 cols = tablePart->GetMaxColumns();
    +        PRInt32 tableKidCount = tablePart->ChildCount();
    +        for (PRInt32 i=0; iChildAt(i);
    +          NS_ASSERTION(nsnull != tableKid, "bad kid");
    +          const int contentType = tableKid->GetType();
    +          if (contentType == nsITableContent::kTableColGroupType)
    +          {
    +            PRInt32 colsInGroup = tableKid->ChildCount();
    +            for (PRInt32 j=0; jChildAt(j);
    +              NS_ASSERTION(nsnull != col, "bad content");
    +              nsColLayoutData *colData = new nsColLayoutData(col);
    +              mColumnLayoutData->AppendElement((void *)colData);
    +              NS_RELEASE(col);                                                    // col: REFCNT--
    +            }
    +          }
    +          // can't have col groups after row groups, so stop if you find a row group
    +          else if (contentType == nsITableContent::kTableRowGroupType)
    +          {
    +            NS_RELEASE(tableKid);                                                 // tableKid: REFCNT--
    +            break;
    +          }
    +          NS_RELEASE(tableKid);                                                 // tableKid: REFCNT--
    +        }
    +      }
    +
    +    // create cell layout data objects for the passed in data, one per column spanned
    +    // for now, divide width equally between spanned columns
    +
    +      PRInt32 firstColIndex = aCell->GetColIndex();
    +      nsTableRow *row = aCell->GetRow();            // row: ADDREF++
    +      PRInt32 rowIndex = row->GetRowIndex();
    +      NS_RELEASE(row);                              // row: ADDREF--
    +      PRInt32 colSpan = aCell->GetColSpan();
    +      nsColLayoutData * colData = (nsColLayoutData *)(mColumnLayoutData->ElementAt(firstColIndex));
    +      nsVoidArray *col = colData->GetCells();
    +      if (gsDebugCLD) printf ("     ~ SetCellLayoutData with row = %d, firstCol = %d, colSpan = %d, colData = %ld, col=%ld\n", 
    +                           rowIndex, firstColIndex, colSpan, colData, col);
    +      for (PRInt32 i=0; iGetMaxElementSize();
    +        nsSize partialCellSize(*cellSize);
    +        partialCellSize.width = (cellSize->width)/colSpan;
    +        // This method will copy the nsReflowMetrics pointed at by aData->GetDesiredSize()
    +        nsCellLayoutData * kidLayoutData = new nsCellLayoutData(aData->GetCellFrame(),
    +                                                                aData->GetDesiredSize(),
    +                                                                &partialCellSize);
    +        PRInt32 numCells = col->Count();
    +        if (gsDebugCLD) printf ("     ~ before setting data, number of cells in this column = %d\n", numCells);
    +        if ((numCells==0) || numCellsAppendElement((void *)kidLayoutData);
    +        }
    +        else
    +        {
    +          if (gsDebugCLD) printf ("     ~ replacing  %d + rowIndex = %d\n", i, i+rowIndex);
    +          nsCellLayoutData* data = (nsCellLayoutData*)col->ElementAt(i+rowIndex);
    +          col->ReplaceElementAt((void *)kidLayoutData, i+rowIndex);
    +          if (data != nsnull)
    +            delete data;
    +        }
    +        if (gsDebugCLD) printf ("     ~ after setting data, number of cells in this column = %d\n", col->Count());
    +      }
    +    }
    +    else
    +      result = PR_FALSE;
    +  }
    +
    +  return result;
    +}
    +
    +/** Get the layout data associated with the cell at (aRow,aCol)
    +  * @return nsnull if there was an error, such as aRow or aCol being invalid
    +  *         otherwise, the data is returned.
    +  */
    +nsCellLayoutData * nsTableFrame::GetCellLayoutData(nsTableCell *aCell)
    +{
    +  NS_ASSERTION(nsnull != aCell, "bad arg");
    +
    +  nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
    +  NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
    +  nsCellLayoutData *result = nsnull;
    +  if (this!=firstInFlow)
    +    result = firstInFlow->GetCellLayoutData(aCell);
    +  else
    +  {
    +    if (nsnull!=mColumnLayoutData)
    +    {
    +      PRInt32 firstColIndex = aCell->GetColIndex();
    +      nsColLayoutData * colData = (nsColLayoutData *)(mColumnLayoutData->ElementAt(firstColIndex));
    +      nsVoidArray *cells = colData->GetCells();
    +      PRInt32 count = cells->Count();
    +      for (PRInt32 i=0; iElementAt(i));
    +        nsTableCell *cell = (nsTableCell *)(data->GetCellFrame()->GetContent());  // cell: REFCNT++
    +        if (cell == aCell)
    +        {
    +          result = data;
    +          NS_RELEASE(cell);                                                         // cell: REFCNT--
    +          break;
    +        }
    +        NS_RELEASE(cell);                                                         // cell: REFCNT--
    +      }
    +    }
    +  }
    +  return result;
    +}
    +
    +
    +
    +PRInt32 nsTableFrame::GetReflowPass() const
    +{
    +  nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
    +  NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
    +  return firstInFlow->mPass;
    +}
    +
    +void nsTableFrame::SetReflowPass(PRInt32 aReflowPass)
    +{
    +  nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
    +  NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
    +  firstInFlow->mPass = aReflowPass;
    +}
    +
    +PRBool nsTableFrame::IsFirstPassValid() const
    +{
    +  nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
    +  NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
    +  return firstInFlow->mFirstPassValid;
    +}
    +
    +//ZZZ TOTAL HACK
    +PRBool isTableAutoWidth = PR_TRUE;
    +PRBool isAutoColumnWidths = PR_TRUE;
    +
    +PRBool nsTableFrame::TableIsAutoWidth()
    +{ // ZZZ: TOTAL HACK
    +  return isTableAutoWidth; 
    +}
    +
    +PRBool nsTableFrame::AutoColumnWidths(nsStyleMolecule* aTableStyleMol)
    +{ // ZZZ: TOTAL HACK
    +  return isAutoColumnWidths;
    +}
    +
    +nsIFrame* nsTableFrame::CreateContinuingFrame(nsIPresContext* aPresContext,
    +                                              nsIFrame*       aParent)
    +{
    +  nsTableFrame* cf = new nsTableFrame(mContent, mIndexInParent, aParent);
    +  PrepareContinuingFrame(aPresContext, aParent, cf);
    +  if (PR_TRUE==gsDebug) printf("nsTableFrame::CCF parent = %p, this=%p, cf=%p\n", aParent, this, cf);
    +  // set my width, because all frames in a table flow are the same width
    +  // code in nsTableOuterFrame depends on this being set
    +  cf->SetRect(nsRect(0, 0, GetWidth(), 0));
    +  // add headers and footers to cf
    +  nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
    +  PRInt32 childCount = firstInFlow->ChildCount();
    +  PRInt32 childIndex = 0;
    +  for (; childIndex < childCount; childIndex++)
    +  {
    +    // TODO: place copies of the header and footer row groups here
    +    // maybe need to do this in ResizeReflow at the beginning, when we determine we are a continuing frame
    +  }
    +
    +  return cf;
    +}
    +
    +PRInt32 nsTableFrame::GetColumnWidth(PRInt32 aColIndex)
    +{
    +  nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
    +  NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
    +  PRInt32 result = 0;
    +  if (this!=firstInFlow)
    +    result = firstInFlow->GetColumnWidth(aColIndex);
    +  else
    +  {
    +    NS_ASSERTION(nsnull!=mColumnWidths, "illegal state");
    +    if (nsnull!=mColumnWidths)
    +     result = mColumnWidths[aColIndex];
    +  }
    +  return result;
    +}
    +
    +void  nsTableFrame::SetColumnWidth(PRInt32 aColIndex, PRInt32 aWidth)
    +{
    +  nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow();
    +  NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow");
    +  if (this!=firstInFlow)
    +    firstInFlow->SetColumnWidth(aColIndex, aWidth);
    +  else
    +  {
    +    NS_ASSERTION(nsnull!=mColumnWidths, "illegal state");
    +    if (nsnull!=mColumnWidths)
    +      mColumnWidths[aColIndex] = aWidth;
    +  }
    +}
    +
    +
    +/* ---------- static methods ---------- */
    +
    +nsresult nsTableFrame::NewFrame(nsIFrame** aInstancePtrResult,
    +                                nsIContent* aContent,
    +                                PRInt32     aIndexInParent,
    +                                nsIFrame*   aParent)
    +{
    +  NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr");
    +  if (nsnull == aInstancePtrResult) {
    +    return NS_ERROR_NULL_POINTER;
    +  }
    +  nsIFrame* it = new nsTableFrame(aContent, aIndexInParent, aParent);
    +  if (nsnull == it) {
    +    return NS_ERROR_OUT_OF_MEMORY;
    +  }
    +  *aInstancePtrResult = it;
    +  return NS_OK;
    +}
    +
    +/* valuable code not yet used anywhere
    +
    +    // since the table is a specified width, we need to expand the columns to fill the table
    +    nsVoidArray *columnLayoutData = GetColumnLayoutData();
    +    PRInt32 numCols = columnLayoutData->Count();
    +    PRInt32 spaceUsed = 0;
    +    for (PRInt32 colIndex = 0; colIndexElementAt(colIndex));
    +        nsTableCol *col = colData->GetCol();  // col: ADDREF++
    +        nsStyleMolecule* colStyle =
    +          (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID);
    +        if (PR_TRUE==IsProportionalWidth(colStyle))
    +        {
    +          PRInt32 percentage = (100*mColumnWidths[colIndex]) / aMaxWidth;
    +          PRInt32 additionalSpace = (spaceRemaining*percentage)/100;
    +          mColumnWidths[colIndex] += additionalSpace;
    +          additionalSpaceAdded += additionalSpace;
    +        }
    +        NS_IF_RELEASE(col);               // col: ADDREF--
    +      }
    +      if (spaceUsed+additionalSpaceAdded < aMaxTableWidth)
    +        mColumnWidths[numCols-1] += (aMaxTableWidth - (spaceUsed+additionalSpaceAdded));
    +    }
    +*/
    +
    +
    +
    +
    diff --git a/mozilla/layout/tables/nsTableFrame.h b/mozilla/layout/tables/nsTableFrame.h
    new file mode 100644
    index 00000000000..c4dcdf4bd19
    --- /dev/null
    +++ b/mozilla/layout/tables/nsTableFrame.h
    @@ -0,0 +1,290 @@
    +/* -*- 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.
    + */
    +#ifndef nsTableFrame_h__
    +#define nsTableFrame_h__
    +
    +#include "nscore.h"
    +#include "nsContainerFrame.h"
    +
    +class nsCellLayoutData;
    +class nsTableCell;
    +class nsVoidArray;
    +class nsTableCellFrame;
    +class CellData;
    +struct nsStyleMolecule;
    +struct InnerTableReflowState;
    +
    +/**
    +  */
    +class nsTableFrame : public nsContainerFrame
    +{
    +public:
    +
    +  friend class nsTableOuterFrame;
    +
    +  static nsresult NewFrame(nsIFrame** aInstancePtrResult,
    +                           nsIContent* aContent,
    +                           PRInt32     aIndexInParent,
    +                           nsIFrame*   aParent);
    +
    +  virtual void Paint(nsIPresContext& aPresContext,
    +                     nsIRenderingContext& aRenderingContext,
    +                     const nsRect& aDirtyRect);
    +
    +  virtual ReflowStatus ResizeReflow(nsIPresContext* aPresContext,
    +                                    nsReflowMetrics& aDesiredSize,
    +                                    const nsSize& aMaxSize,
    +                                    nsSize* aMaxElementSize);
    +
    +  virtual ReflowStatus  IncrementalReflow(nsIPresContext* aPresContext,
    +                                          nsReflowMetrics& aDesiredSize,
    +                                          const nsSize&    aMaxSize,
    +                                          nsReflowCommand& aReflowCommand);
    +
    +  /**
    +   * @see nsContainerFrame
    +   */
    +  virtual nsIFrame* CreateContinuingFrame(nsIPresContext* aPresContext,
    +                                          nsIFrame*       aParent);
    +
    +  /** resize myself and my children according to the arcane rules of cell height magic. 
    +    * By default, the height of a cell is the max (height of cells in its row)
    +    * In the case of a cell with rowspan>1 (lets call this C),
    +    *   if the sum of the height of the rows spanned (excluding C in the calculation)
    +    *   is greater than or equal to the height of C, 
    +    *     the cells in the rows are sized normally and 
    +    *     the height of C is set to the sum of the heights (taking into account borders, padding, and margins)
    +    *   else
    +    *     the height of each row is expanded by a percentage of the difference between
    +    *     the row's desired height and the height of C
    +    */
    +  virtual void ShrinkWrapChildren(nsIPresContext* aPresContext, 
    +                                  nsReflowMetrics& aDesiredSize,
    +                                  nsSize* aMaxElementSize);
    +  
    +  /** return the column layout data for this inner table frame.
    +    * if this is a continuing frame, return the first-in-flow's column layout data.
    +    */
    +  virtual nsVoidArray *GetColumnLayoutData();
    +
    +  /** Associate aData with the cell at (aRow,aCol)
    +    * @return PR_TRUE if the data was successfully associated with a Cell
    +    *         PR_FALSE if there was an error, such as aRow or aCol being invalid
    +    */
    +  virtual PRBool SetCellLayoutData(nsCellLayoutData * aData, nsTableCell *aCell);
    +
    +  /** Get the layout data associated with the cell at (aRow,aCol)
    +    * @return PR_NULL if there was an error, such as aRow or aCol being invalid
    +    *         otherwise, the data is returned.
    +    */
    +  virtual nsCellLayoutData * GetCellLayoutData(nsTableCell *aCell);
    +
    +  /**
    +    */
    +          PRBool IsProportionalWidth(nsStyleMolecule* aMol);
    +
    +
    +          
    +  /**
    +    * DEBUG METHOD
    +    *
    +    */
    +  
    +  void    ListColumnLayoutData(FILE* out = stdout, PRInt32 aIndent = 0) const;
    +
    +  
    +  /**
    +    */
    +          PRInt32 GetColumnWidth(PRInt32 aColIndex);
    +
    +  /**
    +    */
    +          void SetColumnWidth(PRInt32 aColIndex, PRInt32 aWidth);
    +
    +
    +          
    +  /**
    +    * Calculate Layout Information
    +    *
    +    */
    +  nsCellLayoutData* FindCellLayoutData(nsTableCell* aCell);
    +  void    AppendLayoutData(nsVoidArray* aList, nsTableCell* aTableCell);
    +  void    ResetColumnLayoutData();
    +  void    ResetCellLayoutData( nsTableCell* aCell, 
    +                               nsTableCell* aAbove,
    +                               nsTableCell* aBelow,
    +                               nsTableCell* aLeft,
    +                               nsTableCell* aRight);
    +
    +
    +
    +protected:
    +
    +  nsTableFrame(nsIContent* aContent,
    +                PRInt32 aIndexInParent,
    +                nsIFrame* aParentFrame);
    +
    +  virtual ~nsTableFrame();
    +
    +  /**
    +    */
    +  virtual void DeleteColumnLayoutData();
    +
    +  /**
    +    */
    +  virtual nsIFrame::ReflowStatus ResizeReflowPass1(nsIPresContext*  aPresContext,
    +                                                   nsReflowMetrics& aDesiredSize,
    +                                                   const nsSize&    aMaxSize,
    +                                                   nsSize*          aMaxElementSize,
    +                                                   nsStyleMolecule* aTableStyle);
    +
    +  /**
    +    * aMinCaptionWidth - the max of all the minimum caption widths.  0 if no captions.
    +    * aMaxCaptionWidth - the max of all the desired caption widths.  0 if no captions.
    +    */
    +  virtual nsIFrame::ReflowStatus ResizeReflowPass2(nsIPresContext*  aPresContext,
    +                                                   nsReflowMetrics& aDesiredSize,
    +                                                   const nsSize&    aMaxSize,
    +                                                   nsSize*          aMaxElementSize,
    +                                                   nsStyleMolecule* aTableStyle,
    +                                                   PRInt32 aMinCaptionWidth,
    +                                                   PRInt32 mMaxCaptionWidth);
    +
    +  nscoord GetTopMarginFor(nsIPresContext* aCX,
    +                          InnerTableReflowState& aState,
    +                          nsStyleMolecule* aKidMol);
    +
    +  void PlaceChild(nsIPresContext*    aPresContext,
    +                  InnerTableReflowState& aState,
    +                  nsIFrame*          aKidFrame,
    +                  const nsRect&      aKidRect,
    +                  nsStyleMolecule*   aKidMol,
    +                  nsSize*            aMaxElementSize,
    +                  nsSize&            aKidMaxElementSize);
    +
    +  PRBool        ReflowMappedChildren(nsIPresContext*        aPresContext,
    +                                     InnerTableReflowState& aState,
    +                                     nsSize*                aMaxElementSize);
    +
    +  PRBool        PullUpChildren(nsIPresContext*        aPresContext,
    +                               InnerTableReflowState& aState,
    +                               nsSize*                aMaxElementSize);
    +
    +  ReflowStatus  ReflowUnmappedChildren(nsIPresContext*        aPresContext,
    +                                       InnerTableReflowState& aState,
    +                                       nsSize*                aMaxElementSize);
    +
    +
    +  /** 
    +    */
    +  virtual void BalanceColumnWidths(nsIPresContext*  aPresContext, 
    +                                   nsStyleMolecule* aTableStyle,
    +                                   const nsSize&    aMaxSize, 
    +                                   nsSize*          aMaxElementSize);
    +
    +  /**
    +    */
    +  virtual PRBool AssignFixedColumnWidths(nsIPresContext* aPresContext, 
    +                                         PRInt32   aMaxWidth, 
    +                                         PRInt32   aNumCols, 
    +                                         nsStyleMolecule* aTableStyleMol,
    +                                         PRInt32 & aTotalFixedWidth,
    +                                         PRInt32 & aMinTableWidth, 
    +                                         PRInt32 & aMaxTableWidth);
    +  /**
    +   */
    +  virtual PRBool BalanceProportionalColumnsForSpecifiedWidthTable(nsIPresContext*  aPresContext,
    +                                                                  nsStyleMolecule* aTableStyleMol,
    +                                                                  PRInt32 aAvailWidth,
    +                                                                  PRInt32 aMaxWidth,
    +                                                                  PRInt32 aMinTableWidth, 
    +                                                                  PRInt32 aMaxTableWidth);
    +
    +  /**
    +   */
    +  virtual PRBool BalanceProportionalColumnsForAutoWidthTable(nsIPresContext*  aPresContext,
    +                                                             nsStyleMolecule* aTableStyleMol,
    +                                                             PRInt32 aAvailWidth,
    +                                                             PRInt32 aMaxWidth,
    +                                                             PRInt32 aMinTableWidth, 
    +                                                             PRInt32 aMaxTableWidth);
    +
    +  virtual PRBool SetColumnsToMinWidth(nsIPresContext* aPresContext);
    +
    +  virtual PRBool BalanceColumnsTableFits(nsIPresContext*  aPresContext, 
    +                                         nsStyleMolecule* aTableStyleMol, 
    +                                         PRInt32          aAvailWidth);
    +
    +  virtual PRBool BalanceColumnsHTML4Constrained(nsIPresContext*  aPresContext,
    +                                                nsStyleMolecule* aTableStyleMol, 
    +                                                PRInt32 aAvailWidth,
    +                                                PRInt32 aMaxWidth,
    +                                                PRInt32 aMinTableWidth, 
    +                                                PRInt32 aMaxTableWidth);
    +
    +  /**
    +  */
    +  virtual void SetTableWidth(nsIPresContext*  aPresContext, 
    +                             nsStyleMolecule* aTableStyle);
    +
    +  /**
    +    */
    +  virtual void VerticallyAlignChildren(nsIPresContext* aPresContext,
    +                                        nscoord* aAscents,
    +                                        nscoord aMaxAscent,
    +                                        nscoord aMaxHeight);
    +
    +  /** support routine returns PR_TRUE if the table should be sized "automatically" 
    +    * according to its content.  
    +    * In NAV4, this is the default (no WIDTH, no COLS).
    +    */
    +  virtual PRBool TableIsAutoWidth();
    +
    +  /** support routine returns PR_TRUE if the table columns should be sized "automatically" 
    +    * according to its content.  
    +    * In NAV4, this is when there is a COLS attribute on the table.
    +    */
    +  virtual PRBool AutoColumnWidths(nsStyleMolecule* aTableStyleMol);
    +
    +  /** given the new parent size, do I really need to do a reflow? */
    +  virtual PRBool NeedsReflow(const nsSize& aMaxSize);
    +
    +  virtual PRInt32 GetReflowPass() const;
    +
    +  virtual void SetReflowPass(PRInt32 aReflowPass);
    +
    +  virtual PRBool IsFirstPassValid() const;
    +
    +private:
    +  void nsTableFrame::DebugPrintCount() const; // Debugging routine
    +
    +
    +  /**  table reflow is a multi-pass operation.  Use these constants to keep track of
    +    *  which pass is currently being executed.
    +    */
    +  enum {kPASS_UNDEFINED=0, kPASS_FIRST=1, kPASS_SECOND=2, kPASS_THIRD=3};
    +
    +  nsVoidArray *mColumnLayoutData;   // array of array of cellLayoutData's
    +  PRInt32     *mColumnWidths;       // widths of each column
    +  PRBool       mFirstPassValid;     // PR_TRUE if first pass data is still legit
    +  PRInt32      mPass;               // which Reflow pass are we currently in?
    +  PRBool       mIsInvariantWidth;   // PR_TRUE if table width cannot change
    +
    +};
    +
    +#endif
    diff --git a/mozilla/layout/tables/nsTableOuterFrame.cpp b/mozilla/layout/tables/nsTableOuterFrame.cpp
    new file mode 100644
    index 00000000000..88fe79a6eef
    --- /dev/null
    +++ b/mozilla/layout/tables/nsTableOuterFrame.cpp
    @@ -0,0 +1,1211 @@
    +/* -*- 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 "nsTableOuterFrame.h"
    +#include "nsTableFrame.h"
    +#include "nsTableCaptionFrame.h"
    +#include "nsITableContent.h"
    +#include "nsTableContent.h"
    +#include "nsBodyFrame.h"
    +#include "nsReflowCommand.h"
    +#include "nsIStyleContext.h"
    +#include "nsStyleConsts.h"
    +#include "nsIPresContext.h"
    +#include "nsIRenderingContext.h"
    +#include "nsCSSRendering.h"
    +#include "nsIContent.h"
    +#include "nsIContentDelegate.h"
    +#include "nsCSSLayout.h"
    +#include "nsVoidArray.h"
    +#include "nsReflowCommand.h"
    +
    +#ifdef NS_DEBUG
    +static PRBool gsDebug = PR_FALSE;
    +//#define NOISY
    +//#define NOISY_FLOW
    +//#define NOISY_MARGINS
    +#else
    +static const PRBool gsDebug = PR_FALSE;
    +#endif
    +
    +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID);
    +static NS_DEFINE_IID(kITableContentIID, NS_ITABLECONTENT_IID);
    +
    +struct OuterTableReflowState {
    +
    +  // The body's style molecule
    +  nsStyleMolecule* mol;
    +
    +  // The total available size (computed from the parent)
    +  nsSize availSize;
    +  // The available size for the inner table frame
    +  nsSize innerTableMaxSize;
    +
    +  // Margin tracking information
    +  nscoord prevMaxPosBottomMargin;
    +  nscoord prevMaxNegBottomMargin;
    +
    +  // Flags for whether the max size is unconstrained
    +  PRBool  unconstrainedWidth;
    +  PRBool  unconstrainedHeight;
    +
    +  // Running y-offset
    +  nscoord y;
    +
    +  // Flags for where we are in the content
    +  PRBool firstRowGroup;
    +  PRBool processingCaption;
    +
    +  OuterTableReflowState(nsIPresContext*  aPresContext,
    +                        const nsSize&    aMaxSize,
    +                        nsStyleMolecule* aMol)
    +  {
    +    mol = aMol;
    +    availSize.width = aMaxSize.width;
    +    availSize.height = aMaxSize.height;
    +    prevMaxPosBottomMargin = 0;
    +    prevMaxNegBottomMargin = 0;
    +    y=0;  // border/padding/margin???
    +    unconstrainedWidth = PRBool(aMaxSize.width == NS_UNCONSTRAINEDSIZE);
    +    unconstrainedHeight = PRBool(aMaxSize.height == NS_UNCONSTRAINEDSIZE);
    +    firstRowGroup = PR_TRUE;
    +    processingCaption = PR_FALSE;
    +  }
    +
    +  ~OuterTableReflowState() {
    +  }
    +};
    +
    +
    +
    +/* ----------- nsTableOuterFrame ---------- */
    +
    +
    +/**
    +  */
    +nsTableOuterFrame::nsTableOuterFrame(nsIContent* aContent,
    +                                     PRInt32     aIndexInParent,
    +                                     nsIFrame*   aParentFrame)
    +  : nsContainerFrame(aContent, aIndexInParent, aParentFrame),
    +  mInnerTableFrame(nsnull),
    +  mCaptionFrames(nsnull),
    +  mBottomCaptions(nsnull),
    +  mMinCaptionWidth(0),
    +  mMaxCaptionWidth(0),
    +  mFirstPassValid(PR_FALSE)
    +{
    +}
    +
    +nsTableOuterFrame::~nsTableOuterFrame()
    +{
    +  if (nsnull!=mCaptionFrames)
    +    delete mCaptionFrames;
    +  if (nsnull!=mBottomCaptions)
    +    delete mBottomCaptions;
    +}
    +
    +void nsTableOuterFrame::Paint(nsIPresContext& aPresContext,
    +                               nsIRenderingContext& aRenderingContext,
    +                               const nsRect& aDirtyRect)
    +{
    +  // for debug...
    +  if (nsIFrame::GetShowFrameBorders()) {
    +    aRenderingContext.SetColor(NS_RGB(255,0,0));
    +    aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height);
    +  }
    +
    +  PaintChildren(aPresContext, aRenderingContext, aDirtyRect);
    +}
    +
    +PRBool nsTableOuterFrame::NeedsReflow(const nsSize& aMaxSize)
    +{
    +  PRBool result=PR_TRUE;
    +  if (nsnull!=mInnerTableFrame)
    +    result = mInnerTableFrame->NeedsReflow(aMaxSize);
    +  return result;
    +}
    +
    +PRBool nsTableOuterFrame::IsFirstPassValid()
    +{
    +  return mFirstPassValid;
    +}
    +
    +void nsTableOuterFrame::SetFirstPassValid(PRBool aValidState)
    +{
    +  mFirstPassValid = aValidState;
    +}
    +
    +/**
    +  * ResizeReflow is a 2-step process.
    +  * In the first step, we lay out all of the captions and the inner table in NS_UNCONSTRAINEDSIZE space.
    +  * This gives us absolute minimum and maximum widths.
    +  * In the second step, we force all the captions and the table to the width of the widest component, 
    +  * given the table's width constraints.
    +  * With the widths known, we reflow the captions and table.
    +  * NOTE: for breaking across pages, this method has to account for table content that is not laid out
    +  *       linearly vis a vis the frames.  That is, content hierarchy and the frame hierarchy do not match.
    +  */
    +nsIFrame::ReflowStatus nsTableOuterFrame::ResizeReflow(nsIPresContext* aPresContext,
    +                                                       nsReflowMetrics& aDesiredSize,
    +                                                       const nsSize& aMaxSize,
    +                                                       nsSize* aMaxElementSize)
    +{
    +  if (PR_TRUE==gsDebug) printf ("***table outer frame reflow \t\t%d\n", this);
    +  if (gsDebug==PR_TRUE)
    +    printf("nsTableOuterFrame::ResizeReflow : maxSize=%d,%d\n",
    +           aMaxSize.width, aMaxSize.height);
    +
    +#ifdef NS_DEBUG
    +  // replace with a check that does not assume linear placement of children
    +  // PreReflowCheck();
    +#endif
    +
    +  // Initialize out parameter
    +  if (nsnull != aMaxElementSize) {
    +    aMaxElementSize->width = 0;
    +    aMaxElementSize->height = 0;
    +  }
    +
    +  PRBool        reflowMappedOK = PR_TRUE;
    +  ReflowStatus  status = frComplete;
    +  nsSize innerTableMaxElementSize(0,0);
    +
    +  // Set up our kids.  They're already present, on an overflow list, 
    +  // or there are none so we'll create them now
    +  MoveOverflowToChildList();
    +  if (nsnull==mFirstChild)
    +    CreateChildFrames(aPresContext);
    +  if (nsnull!=mPrevInFlow && nsnull==mInnerTableFrame)
    +  { // if I am a continuing frame, my inner table is my prev-in-flow's mInnerTableFrame's next-in-flow
    +    CreateInnerTableFrame(aPresContext);
    +  }
    +  // at this point, we must have at least one child frame, and we must have an inner table frame
    +  NS_ASSERTION(nsnull!=mFirstChild, "no children");
    +  NS_ASSERTION(nsnull!=mInnerTableFrame, "no mInnerTableFrame");
    +  if (nsnull==mFirstChild  ||  nsnull==mInnerTableFrame) //ERROR!
    +    return frComplete;
    +
    +  nsStyleMolecule* tableStyleMol =
    +    (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID);
    +  
    +  OuterTableReflowState state(aPresContext, aMaxSize, tableStyleMol);
    +
    +  // lay out captions pass 1, if necessary
    +  if (PR_FALSE==IsFirstPassValid())
    +  {
    +    mFirstPassValid = PR_TRUE;
    +    status = ResizeReflowCaptionsPass1(aPresContext, tableStyleMol);
    +
    +  }
    +
    +  // lay out inner table, if required
    +  if (PR_FALSE==mInnerTableFrame->IsFirstPassValid())
    +  { // we treat the table as if we've never seen the layout data before
    +    mInnerTableFrame->SetReflowPass(nsTableFrame::kPASS_FIRST);
    +    status = mInnerTableFrame->ResizeReflowPass1(aPresContext, aDesiredSize, aMaxSize, 
    +                                                 &innerTableMaxElementSize, tableStyleMol);
    +  
    +#ifdef NOISY_MARGINS
    +    nsIContent* content = mInnerTableFrame->GetContent();
    +    nsTablePart *table = (nsTablePart*)content;
    +    if (table != nsnull)
    +      table->DumpCellMap();
    +    mInnerTableFrame->ResetColumnLayoutData();
    +    mInnerTableFrame->ListColumnLayoutData(stdout,1);
    +    NS_IF_RELEASE(content);
    +#endif
    +
    +  }
    +  mInnerTableFrame->SetReflowPass(nsTableFrame::kPASS_SECOND);
    +  // assign table width info only if the inner table frame is a first-in-flow
    +  if (nsnull==mInnerTableFrame->GetPrevInFlow())
    +  {
    +    // assign column widths, and assign aMaxElementSize->width
    +    mInnerTableFrame->BalanceColumnWidths(aPresContext, tableStyleMol, aMaxSize, aMaxElementSize);
    +    // assign table width
    +    mInnerTableFrame->SetTableWidth(aPresContext, tableStyleMol);
    +  }
    +  // inner table max is now the computed width and assigned  height
    +  state.innerTableMaxSize.width = mInnerTableFrame->GetWidth();
    +  state.innerTableMaxSize.height = aMaxSize.height; 
    +
    +  // Reflow the child frames
    +  if (nsnull != mFirstChild) {
    +    reflowMappedOK = ReflowMappedChildren(aPresContext, state, aMaxElementSize);
    +    if (PR_FALSE == reflowMappedOK) {
    +      status = frNotComplete;
    +    }
    +  }
    +
    +  // Did we successfully relow our mapped children?
    +  if (PR_TRUE == reflowMappedOK) {
    +    // Any space left?
    +    if ((nsnull != mFirstChild) && (state.availSize.height <= 0)) {
    +      // No space left. Don't try to pull-up children or reflow unmapped
    +      if (NextChildOffset() < mContent->ChildCount()) {
    +        status = frNotComplete;
    +      }
    +    } else if (NextChildOffset() < mContent->ChildCount()) {
    +      // Try and pull-up some children from a next-in-flow
    +      if ((nsnull == mNextInFlow) ||
    +          PullUpChildren(aPresContext, state, aMaxElementSize)) {
    +          // nothing to do, we will never have unmapped children!
    +      } else {
    +        // We were unable to pull-up all the existing frames from the
    +        // next in flow
    +        status = frNotComplete;
    +      }
    +    }
    +  }
    +
    +  if (frComplete == status) {
    +    // Don't forget to add in the bottom margin from our last child.
    +    // Only add it in if there's room for it.
    +    nscoord margin = state.prevMaxPosBottomMargin -
    +      state.prevMaxNegBottomMargin;
    +    if (state.availSize.height >= margin) {
    +      state.y += margin;
    +    }
    +  }
    +
    +  // Return our desired rect
    +  //NS_ASSERTION(0width, aMaxElementSize->height);
    +    else
    +      printf("Outer frame Reflow complete, returning aDesiredSize = %d,%d and NSNULL aMaxElementSize\n",
    +              aDesiredSize.width, aDesiredSize.height);
    +  }
    +
    +#ifdef NS_DEBUG
    +  // replace with a check that does not assume linear placement of children
    +  // PostReflowCheck(status);
    +#endif
    +
    +  return status;
    +
    +}
    +
    +// Collapse child's top margin with previous bottom margin
    +nscoord nsTableOuterFrame::GetTopMarginFor(nsIPresContext*        aCX,
    +                                           OuterTableReflowState& aState,
    +                                           nsStyleMolecule*       aKidMol)
    +{
    +  nscoord margin;
    +  nscoord maxNegTopMargin = 0;
    +  nscoord maxPosTopMargin = 0;
    +  if ((margin = aKidMol->margin.top) < 0) {
    +    maxNegTopMargin = -margin;
    +  } else {
    +    maxPosTopMargin = margin;
    +  }
    +
    +  nscoord maxPos = PR_MAX(aState.prevMaxPosBottomMargin, maxPosTopMargin);
    +  nscoord maxNeg = PR_MAX(aState.prevMaxNegBottomMargin, maxNegTopMargin);
    +  margin = maxPos - maxNeg;
    +
    +  return margin;
    +}
    +
    +// Position and size aKidFrame and update our reflow state. The origin of
    +// aKidRect is relative to the upper-left origin of our frame, and includes
    +// any left/top margin.
    +void nsTableOuterFrame::PlaceChild( nsIPresContext*    aPresContext,
    +                                    OuterTableReflowState& aState,
    +                                    nsIFrame*          aKidFrame,
    +                                    const nsRect&      aKidRect,
    +                                    nsStyleMolecule*   aKidMol,
    +                                    nsSize*            aMaxElementSize,
    +                                    nsSize&            aKidMaxElementSize)
    +{
    +  if (PR_TRUE==gsDebug) printf ("place child: %p with aKidRect %d %d %d %d\n", 
    +                                 aKidFrame, aKidRect.x, aKidRect.y,
    +                                 aKidRect.width, aKidRect.height);
    +  // Place and size the child
    +  aKidFrame->SetRect(aKidRect);
    +
    +  // Adjust the running y-offset
    +  aState.y += aKidRect.height;
    +
    +  // If our height is constrained then update the available height
    +  if (PR_FALSE == aState.unconstrainedHeight) {
    +    aState.availSize.height -= aKidRect.height;
    +  }
    +
    +  /* Update the maximum element size, which is the sum of:
    +   *   the maxElementSize of our first row
    +   *   plus the maxElementSize of the top caption if we include it
    +   *   plus the maxElementSize of the bottom caption if we include it
    +   */
    +  if (PR_TRUE==aState.processingCaption || PR_TRUE==aState.firstRowGroup)
    +  {
    +    if (PR_FALSE==aState.processingCaption)
    +      aState.firstRowGroup = PR_FALSE;
    +    if (nsnull != aMaxElementSize) {
    +      aMaxElementSize->width = aKidMaxElementSize.width;
    +      aMaxElementSize->height = aKidMaxElementSize.height;
    +    }
    +  }
    +}
    +
    +/**
    + * Reflow the frames we've already created
    + *
    + * @param   aPresContext presentation context to use
    + * @param   aState current inline state
    + * @return  true if we successfully reflowed all the mapped children and false
    + *            otherwise, e.g. we pushed children to the next in flow
    + */
    +PRBool nsTableOuterFrame::ReflowMappedChildren( nsIPresContext*      aPresContext,
    +                                                OuterTableReflowState& aState,
    +                                                nsSize*              aMaxElementSize)
    +{
    +#ifdef NS_DEBUG
    +  VerifyLastIsComplete();
    +#endif
    +#ifdef NOISY
    +  ListTag(stdout);
    +  printf(": reflow mapped (childCount=%d) [%d,%d,%c]\n",
    +         mChildCount,
    +         mFirstContentOffset, mLastContentOffset,
    +         (mLastContentIsComplete ? 'T' : 'F'));
    +#ifdef NOISY_FLOW
    +  {
    +    nsTableOuterFrame* flow = (nsTableOuterFrame*) mNextInFlow;
    +    while (flow != 0) {
    +      printf("  %p: [%d,%d,%c]\n",
    +             flow, flow->mFirstContentOffset, flow->mLastContentOffset,
    +             (flow->mLastContentIsComplete ? 'T' : 'F'));
    +      flow = (nsTableOuterFrame*) flow->mNextInFlow;
    +    }
    +  }
    +#endif
    +#endif
    +  NS_PRECONDITION(nsnull != mFirstChild, "no children");
    +
    +  PRInt32   childCount = 0;
    +  nsIFrame* prevKidFrame = nsnull;
    +
    +  // Remember our original mLastContentIsComplete so that if we end up
    +  // having to push children, we have the correct value to hand to
    +  // PushChildren.
    +  PRBool    lastContentIsComplete = mLastContentIsComplete;
    +
    +  nsSize    kidMaxElementSize;
    +  nsSize*   pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull;
    +  PRBool    result = PR_TRUE;
    +
    +  for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; ) {
    +    nsSize                  kidAvailSize(aState.innerTableMaxSize.width, aState.availSize.height);
    +    nsReflowMetrics         desiredSize;
    +    nsIFrame::ReflowStatus  status;
    +
    +    SetReflowState(aState, kidFrame);
    +
    +    if (PR_TRUE==gsDebug) printf ("ReflowMappedChildren: %p with state = %s\n", 
    +                                  kidFrame, aState.processingCaption?"caption":"inner");
    +
    +    // Get top margin for this kid
    +    nsIStyleContext* kidSC = kidFrame->GetStyleContext(aPresContext);
    +    nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID);
    +    nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol);
    +    nscoord bottomMargin = kidMol->margin.bottom;
    +    NS_RELEASE(kidSC);
    +
    +    // Figure out the amount of available size for the child (subtract
    +    // off the top margin we are going to apply to it)
    +    if (PR_FALSE == aState.unconstrainedHeight) {
    +      kidAvailSize.height -= topMargin;
    +    }
    +    // Subtract off for left and right margin
    +    if (PR_FALSE == aState.unconstrainedWidth) {
    +      kidAvailSize.width -= kidMol->margin.left + kidMol->margin.right;
    +    }
    +
    +    // Only skip the reflow if this is not our first child and we are
    +    // out of space.
    +    if ((kidFrame == mFirstChild) || (kidAvailSize.height > 0)) {
    +      // Reflow the child into the available space
    +      status = ReflowChild(kidFrame, aPresContext, desiredSize,
    +                           kidAvailSize, pKidMaxElementSize,
    +                           aState);
    +    }
    +
    +    // Did the child fit?
    +    if ((kidFrame != mFirstChild) &&
    +        ((kidAvailSize.height <= 0) ||
    +         (desiredSize.height > kidAvailSize.height)))
    +    {
    +      // The child's height is too big to fit at all in our remaining space,
    +      // and it's not our first child.
    +      //
    +      // Note that if the width is too big that's okay and we allow the
    +      // child to extend horizontally outside of the reflow area
    +
    +      // Since we are giving the next-in-flow our last child, we
    +      // give it our original mLastContentIsComplete, too (in case we
    +      // are pushing into an empty next-in-flow)
    +      if (PR_TRUE==gsDebug) printf ("ReflowMappedChildren: calling PushChildren\n");
    +      PushChildren(kidFrame, prevKidFrame, lastContentIsComplete);
    +
    +      // Our mLastContentIsComplete was already set by the last kid we
    +      // reflowed reflow's status
    +      result = PR_FALSE;
    +      break;
    +    }
    +
    +    // Place the child after taking into account it's margin
    +    aState.y += topMargin;
    +    nsRect kidRect (0, 0, desiredSize.width, desiredSize.height);
    +    kidRect.x += kidMol->margin.left;
    +    kidRect.y += aState.y;
    +    if (PR_TRUE==gsDebug) printf ("ReflowMappedChildren: calling PlaceChild\n");
    +    PlaceChild(aPresContext, aState, kidFrame, kidRect, kidMol, aMaxElementSize,
    +               kidMaxElementSize);
    +    if (bottomMargin < 0) {
    +      aState.prevMaxNegBottomMargin = -bottomMargin;
    +    } else {
    +      aState.prevMaxPosBottomMargin = bottomMargin;
    +    }
    +    childCount++;
    +
    +    // Update mLastContentIsComplete now that this kid fits
    +    mLastContentIsComplete = PRBool(status == frComplete);
    +
    +    // Special handling for incomplete children
    +    if (frNotComplete == status) {
    +      // XXX It's good to assume that we might still have room
    +      // even if the child didn't complete (floaters will want this)
    +      nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow();
    +      if (nsnull == kidNextInFlow) {
    +        // No the child isn't complete, and it doesn't have a next in flow so
    +        // create a continuing frame. This hooks the child into the flow.
    +        nsIFrame* continuingFrame =
    +          kidFrame->CreateContinuingFrame(aPresContext, this);
    +
    +        // Insert the frame. We'll reflow it next pass through the loop
    +        nsIFrame* nextSib = kidFrame->GetNextSibling();
    +        continuingFrame->SetNextSibling(nextSib);
    +        kidFrame->SetNextSibling(continuingFrame);
    +        if (nsnull == nextSib) {
    +          // Assume that the continuation frame we just created is
    +          // complete, for now. It will get reflowed by our
    +          // next-in-flow (we are going to push it now)
    +          lastContentIsComplete = PR_TRUE;
    +        }
    +      }
    +    }
    +
    +    // Get the next child
    +    prevKidFrame = kidFrame;
    +    kidFrame = kidFrame->GetNextSibling();
    +
    +    // XXX talk with troy about checking for available space here
    +  }
    +
    +  // Update the child count
    +  mChildCount = childCount;
    +  NS_POSTCONDITION(LengthOf(mFirstChild) == mChildCount, "bad child count");
    +
    +  // Set the last content offset based on the last child we mapped.
    +  NS_ASSERTION(LastChild() == prevKidFrame, "unexpected last child");
    +  SetLastContentOffset(prevKidFrame);
    +
    +#ifdef NS_DEBUG
    +  VerifyLastIsComplete();
    +#endif
    +#ifdef NOISY
    +  ListTag(stdout);
    +  printf(": reflow mapped %sok (childCount=%d) [%d,%d,%c]\n",
    +         (result ? "" : "NOT "),
    +         mChildCount,
    +         mFirstContentOffset, mLastContentOffset,
    +         (mLastContentIsComplete ? 'T' : 'F'));
    +#ifdef NOISY_FLOW
    +  {
    +    nsTableOuterFrame* flow = (nsTableOuterFrame*) mNextInFlow;
    +    while (flow != 0) {
    +      printf("  %p: [%d,%d,%c]\n",
    +             flow, flow->mFirstContentOffset, flow->mLastContentOffset,
    +             (flow->mLastContentIsComplete ? 'T' : 'F'));
    +      flow = (nsTableOuterFrame*) flow->mNextInFlow;
    +    }
    +  }
    +#endif
    +#endif
    +  return result;
    +}
    +
    +/**
    + * Try and pull-up frames from our next-in-flow
    + *
    + * @param   aPresContext presentation context to use
    + * @param   aState current inline state
    + * @return  true if we successfully pulled-up all the children and false
    + *            otherwise, e.g. child didn't fit
    + */
    +PRBool nsTableOuterFrame::PullUpChildren(nsIPresContext*      aPresContext,
    +                                            OuterTableReflowState& aState,
    +                                            nsSize*              aMaxElementSize)
    +{
    +#ifdef NS_DEBUG
    +  VerifyLastIsComplete();
    +#endif
    +#ifdef NOISY
    +  ListTag(stdout);
    +  printf(": pullup (childCount=%d) [%d,%d,%c]\n",
    +         mChildCount,
    +         mFirstContentOffset, mLastContentOffset,
    +         (mLastContentIsComplete ? 'T' : 'F'));
    +#ifdef NOISY_FLOW
    +  {
    +    nsTableOuterFrame* flow = (nsTableOuterFrame*) mNextInFlow;
    +    while (flow != 0) {
    +      printf("  %p: [%d,%d,%c]\n",
    +             flow, flow->mFirstContentOffset, flow->mLastContentOffset,
    +             (flow->mLastContentIsComplete ? 'T' : 'F'));
    +      flow = (nsTableOuterFrame*) flow->mNextInFlow;
    +    }
    +  }
    +#endif
    +#endif
    +  NS_PRECONDITION(nsnull != mNextInFlow, "null next-in-flow");
    +  nsTableOuterFrame*  nextInFlow = (nsTableOuterFrame*)mNextInFlow;
    +  nsSize        kidMaxElementSize;
    +  nsSize*       pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull;
    +
    +  // The frame previous to the current frame we are reflowing. This
    +  // starts out initially as our last frame.
    +  nsIFrame*     prevKidFrame = LastChild();
    +
    +  // This will hold the prevKidFrame's mLastContentIsComplete
    +  // status. If we have to push the frame that follows prevKidFrame
    +  // then this will become our mLastContentIsComplete state. Since
    +  // prevKidFrame is initially our last frame, it's completion status
    +  // is our mLastContentIsComplete value.
    +  PRBool        prevLastContentIsComplete = mLastContentIsComplete;
    +  PRBool        result = PR_TRUE;
    +
    +  while (nsnull != nextInFlow) {
    +    nsReflowMetrics desiredSize;
    +    nsSize  kidAvailSize(aState.availSize);
    +
    +    // Get first available frame from the next-in-flow
    +    nsIFrame* kidFrame = PullUpOneChild(nextInFlow, prevKidFrame);
    +    if (nsnull == kidFrame) {
    +      // We've pulled up all the children from that next-in-flow, so
    +      // move to the next next-in-flow.
    +      nextInFlow = (nsTableOuterFrame*) nextInFlow->mNextInFlow;
    +      continue;
    +    }
    +
    +    // Get top margin for this kid
    +    nsIContent* kid = kidFrame->GetContent();
    +    nsIStyleContext* kidSC = kidFrame->GetStyleContext(aPresContext);
    +    nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID);
    +    nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol);
    +    nscoord bottomMargin = kidMol->margin.bottom;
    +
    +    // Figure out the amount of available size for the child (subtract
    +    // off the top margin we are going to apply to it)
    +    if (PR_FALSE == aState.unconstrainedHeight) {
    +      kidAvailSize.height -= topMargin;
    +    }
    +    // Subtract off for left and right margin
    +    if (PR_FALSE == aState.unconstrainedWidth) {
    +      kidAvailSize.width -= kidMol->margin.left + kidMol->margin.right;
    +    }
    +
    +    ReflowStatus status;
    +    do {
    +      // Only skip the reflow if this is not our first child and we are
    +      // out of space.
    +      if ((kidFrame == mFirstChild) || (kidAvailSize.height > 0)) {
    +        SetReflowState(aState, kidFrame);
    +        status = ReflowChild(kidFrame, aPresContext, desiredSize,
    +                             kidAvailSize, pKidMaxElementSize,
    +                             aState);
    +      }
    +
    +      // Did the child fit?
    +      if ((kidFrame != mFirstChild) &&
    +          ((kidAvailSize.height <= 0) ||
    +           (desiredSize.height > kidAvailSize.height)))
    +      {
    +        // The child's height is too big to fit at all in our remaining space,
    +        // and it wouldn't have been our first child.
    +        //
    +        // Note that if the width is too big that's okay and we allow the
    +        // child to extend horizontally outside of the reflow area
    +        PRBool lastComplete = PRBool(nsnull == kidFrame->GetNextInFlow());
    +        PushChildren(kidFrame, prevKidFrame, lastComplete);
    +        mLastContentIsComplete = prevLastContentIsComplete;
    +        mChildCount--;
    +        result = PR_FALSE;
    +        NS_RELEASE(kid);
    +        NS_RELEASE(kidSC);
    +        goto push_done;
    +      }
    +
    +      // Place the child
    +      aState.y += topMargin;
    +      nsRect kidRect (0, 0, desiredSize.width, desiredSize.height);
    +      kidRect.x += kidMol->margin.left;
    +      kidRect.y += aState.y;
    +      PlaceChild(aPresContext, aState, kidFrame, kidRect, kidMol, aMaxElementSize,
    +                 kidMaxElementSize);
    +      if (bottomMargin < 0) {
    +        aState.prevMaxNegBottomMargin = -bottomMargin;
    +      } else {
    +        aState.prevMaxPosBottomMargin = bottomMargin;
    +      }
    +      mLastContentIsComplete = PRBool(status == frComplete);
    +
    +#ifdef NOISY
    +      ListTag(stdout);
    +      printf(": pulled up ");
    +      ((nsFrame*)kidFrame)->ListTag(stdout);
    +      printf("\n");
    +#endif
    +
    +      // Is the child we just pulled up complete?
    +      if (frNotComplete == status) {
    +        // No the child isn't complete.
    +        nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow();
    +        if (nsnull == kidNextInFlow) {
    +          // The child doesn't have a next-in-flow so create a
    +          // continuing frame. The creation appends it to the flow and
    +          // prepares it for reflow.
    +          nsIFrame* continuingFrame =
    +            kidFrame->CreateContinuingFrame(aPresContext, this);
    +
    +          // Add the continuing frame to our sibling list.
    +          continuingFrame->SetNextSibling(kidFrame->GetNextSibling());
    +          kidFrame->SetNextSibling(continuingFrame);
    +          prevKidFrame = kidFrame;
    +          prevLastContentIsComplete = mLastContentIsComplete;
    +          kidFrame = continuingFrame;
    +          mChildCount++;
    +        } else {
    +          // The child has a next-in-flow, but it's not one of ours.
    +          // It *must* be in one of our next-in-flows. Collect it
    +          // then.
    +          NS_ASSERTION(kidNextInFlow->GetGeometricParent() != this,
    +                       "busted kid next-in-flow");
    +          break;
    +        }
    +      }
    +    } while (frNotComplete == status);
    +    NS_RELEASE(kid);
    +    NS_RELEASE(kidSC);
    +
    +    prevKidFrame = kidFrame;
    +    prevLastContentIsComplete = mLastContentIsComplete;
    +  }
    +
    + push_done:;
    +  // Update our last content index
    +  if (nsnull != prevKidFrame) {
    +    NS_ASSERTION(LastChild() == prevKidFrame, "bad last child");
    +    SetLastContentOffset(prevKidFrame);
    +  }
    +
    +  // We need to make sure the first content offset is correct for any empty
    +  // next-in-flow frames (frames where we pulled up all the child frames)
    +  nextInFlow = (nsTableOuterFrame*)mNextInFlow;
    +  if ((nsnull != nextInFlow) && (nsnull == nextInFlow->mFirstChild)) {
    +    // We have at least one empty frame. Did we succesfully pull up all the
    +    // child frames?
    +    if (PR_FALSE == result) {
    +      // No, so we need to adjust the first content offset of all the empty
    +      // frames
    +      AdjustOffsetOfEmptyNextInFlows();
    +#ifdef NS_DEBUG
    +    } else {
    +      // Yes, we successfully pulled up all the child frames which means all
    +      // the next-in-flows must be empty. Do a sanity check
    +      while (nsnull != nextInFlow) {
    +        NS_ASSERTION(nsnull == nextInFlow->mFirstChild, "non-empty next-in-flow");
    +        nextInFlow = (nsTableOuterFrame*)nextInFlow->GetNextInFlow();
    +      }
    +#endif
    +    }
    +  }
    +
    +#ifdef NS_DEBUG
    +  PRInt32 len = LengthOf(mFirstChild);
    +  NS_ASSERTION(len == mChildCount, "bad child count");
    +  VerifyLastIsComplete();
    +#endif
    +#ifdef NOISY
    +  ListTag(stdout);
    +  printf(": pullup %sok (childCount=%d) [%d,%d,%c]\n",
    +         (result ? "" : "NOT "),
    +         mChildCount,
    +         mFirstContentOffset, mLastContentOffset,
    +         (mLastContentIsComplete ? 'T' : 'F'));
    +#ifdef NOISY_FLOW
    +  {
    +    nsTableOuterFrame* flow = (nsTableOuterFrame*) mNextInFlow;
    +    while (flow != 0) {
    +      printf("  %p: [%d,%d,%c]\n",
    +             flow, flow->mFirstContentOffset, flow->mLastContentOffset,
    +             (flow->mLastContentIsComplete ? 'T' : 'F'));
    +      flow = (nsTableOuterFrame*) flow->mNextInFlow;
    +    }
    +  }
    +#endif
    +#endif
    +  return result;
    +}
    +
    +/** set the OuterTableReflowState based on the child frame we are currently processing.
    +  * must be called before ReflowChild, at a minimum.
    +  */
    +void nsTableOuterFrame::SetReflowState(OuterTableReflowState& aState, nsIFrame* aKidFrame)
    +{
    +  nsIContent *kid = aKidFrame->GetContent();                             // kid: REFCNT++
    +  nsITableContent *tableContentInterface = nsnull;
    +  kid->QueryInterface(kITableContentIID, (void**)&tableContentInterface);// tableContentInterface: REFCNT++
    +  if (nsnull!=tableContentInterface)
    +  {
    +    aState.processingCaption = PR_TRUE;
    +    NS_RELEASE(tableContentInterface);                                   // tableContentInterface: REFCNT--
    +  }
    +  else
    +    aState.processingCaption = PR_FALSE;
    +  NS_RELEASE(kid);                                                       // kid: REFCNT--
    +}
    +
    +/**
    + * Reflow a child frame and return the status of the reflow. If the
    + * child is complete and it has next-in-flows (it was a splittable child)
    + * then delete the next-in-flows.
    + */
    +nsIFrame::ReflowStatus
    +nsTableOuterFrame::ReflowChild( nsIFrame*        aKidFrame,
    +                                nsIPresContext*  aPresContext,
    +                                nsReflowMetrics& aDesiredSize,
    +                                const nsSize&    aMaxSize,
    +                                nsSize*          aMaxElementSize,
    +                                OuterTableReflowState& aState)
    +{
    +  ReflowStatus status;
    +
    +  /* call the appropriate reflow method based on the type and position of the child */
    +//  if (((nsSplittableFrame*)aKidFrame)->GetFirstInFlow()!=mInnerTableFrame)
    +  if (PR_TRUE==aState.processingCaption)
    +  { // it's a caption, find out if it's top or bottom
    +    // Resolve style
    +    nsIStyleContext* captionStyleContext = aKidFrame->GetStyleContext(aPresContext);
    +    NS_ASSERTION(nsnull != captionStyleContext, "null style context for caption");
    +    nsStyleMolecule* captionStyle =
    +      (nsStyleMolecule*)captionStyleContext->GetData(kStyleMoleculeSID);
    +    NS_ASSERTION(nsnull != captionStyle, "null style molecule for caption");
    +    if (NS_STYLE_VERTICAL_ALIGN_BOTTOM==captionStyle->verticalAlign)
    +      status = ResizeReflowBottomCaptionsPass2(aPresContext, aDesiredSize,
    +                                               aMaxSize, aMaxElementSize,
    +                                               aState.mol, aState.y);
    +    else
    +      status = ResizeReflowTopCaptionsPass2(aPresContext, aDesiredSize,
    +                                            aMaxSize, aMaxElementSize,
    +                                            aState.mol);
    +  }
    +  else
    +    status = ((nsTableFrame*)aKidFrame)->ResizeReflowPass2(aPresContext, aDesiredSize, aState.innerTableMaxSize, 
    +                                                           aMaxElementSize, aState.mol,
    +                                                           mMinCaptionWidth, mMaxCaptionWidth);
    +
    +  if (frComplete == status) {
    +    nsIFrame* kidNextInFlow = aKidFrame->GetNextInFlow();
    +    if (nsnull != kidNextInFlow) {
    +      // Remove all of the childs next-in-flows. Make sure that we ask
    +      // the right parent to do the removal (it's possible that the
    +      // parent is not this because we are executing pullup code)
    +      nsTableOuterFrame* parent = (nsTableOuterFrame*)
    +        aKidFrame->GetGeometricParent();
    +      parent->DeleteChildsNextInFlow(aKidFrame);
    +    }
    +  }
    +  return status;
    +}
    +
    +void nsTableOuterFrame::CreateChildFrames(nsIPresContext*  aPresContext)
    +{
    +  nsIFrame *prevKidFrame = nsnull;
    +  nsresult frameCreated = nsTableFrame::NewFrame((nsIFrame **)(&mInnerTableFrame), mContent, 0, this);
    +  if (NS_OK!=frameCreated)
    +    return;  // SEC: an error!!!!
    +  // Resolve style
    +  nsIStyleContext* kidStyleContext =
    +    aPresContext->ResolveStyleContextFor(mContent, this);
    +  NS_ASSERTION(nsnull!=kidStyleContext, "bad style context for kid.");
    +  mInnerTableFrame->SetStyleContext(kidStyleContext);
    +  mChildCount++;
    +  // Link child frame into the list of children
    +  mFirstChild = mInnerTableFrame;
    +  prevKidFrame = mInnerTableFrame;
    +
    +  // now create the caption frames, prepending top captions and
    +  // appending bottom captions
    +  mCaptionFrames = new nsVoidArray();
    +  // create caption frames as needed
    +  nsIFrame *lastTopCaption = nsnull;
    +  for (PRInt32 kidIndex=0; /* nada */ ;kidIndex++) {
    +    nsIContent* caption = mContent->ChildAt(kidIndex);   // caption: REFCNT++
    +    if (nsnull == caption) {
    +      break;
    +    }
    +    const PRInt32 contentType = ((nsTableContent *)caption)->GetType();
    +    if (contentType==nsITableContent::kTableCaptionType)
    +    {
    +      nsIFrame *captionFrame=nsnull;
    +      frameCreated = nsTableCaptionFrame::NewFrame(&captionFrame, caption, 0, this);
    +      if (NS_OK!=frameCreated)
    +        return;  // SEC: an error!!!!
    +      // Resolve style
    +      nsIStyleContext* captionStyleContext =
    +        aPresContext->ResolveStyleContextFor(caption, this);
    +      NS_ASSERTION(nsnull!=captionStyleContext, "bad style context for caption.");
    +      nsStyleMolecule* captionStyle = 
    +        (nsStyleMolecule*)captionStyleContext->GetData(kStyleMoleculeSID);
    +      captionFrame->SetStyleContext(captionStyleContext);
    +      mChildCount++;
    +      // Link child frame into the list of children
    +      if (NS_STYLE_VERTICAL_ALIGN_BOTTOM==captionStyle->verticalAlign)
    +      { // bottom captions get added to the end of the outer frame child list
    +        prevKidFrame->SetNextSibling(captionFrame);
    +        prevKidFrame = captionFrame;
    +        // bottom captions get remembered in an instance variable for easy access later
    +        if (nsnull==mBottomCaptions)
    +        {
    +          mBottomCaptions = new nsVoidArray();
    +        }
    +        mBottomCaptions->AppendElement(captionFrame);
    +      }
    +      else
    +      {  // top captions get prepended to the outer frame child list
    +        if (nsnull == lastTopCaption) 
    +        { // our first top caption, therefore our first child
    +          mFirstChild = captionFrame;
    +          mFirstChild->SetNextSibling(mInnerTableFrame);
    +        }
    +        else 
    +        { // just another grub in the brood of top captions
    +          lastTopCaption->SetNextSibling(captionFrame);
    +          lastTopCaption = captionFrame;
    +        }
    +        lastTopCaption = captionFrame;
    +      }
    +      mCaptionFrames->AppendElement(captionFrame);
    +      NS_RELEASE(caption);                                 // caption: REFCNT--
    +    }
    +    else
    +    {
    +      NS_RELEASE(caption);                                 // caption: REFCNT--
    +      break;
    +    }
    +  }
    +}
    +
    +
    +nsIFrame::ReflowStatus
    +nsTableOuterFrame::ResizeReflowCaptionsPass1(nsIPresContext* aPresContext, nsStyleMolecule* aTableStyle)
    +{
    +  if (nsnull!=mCaptionFrames)
    +  {
    +    PRInt32 numCaptions = mCaptionFrames->Count();
    +    for (PRInt32 captionIndex = 0; captionIndex < numCaptions; captionIndex++)
    +    {
    +      nsSize maxElementSize(0,0);
    +      nsSize maxSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    +      nsReflowMetrics desiredSize;
    +      nsTableCaptionFrame *captionFrame = (nsTableCaptionFrame *)mCaptionFrames->ElementAt(captionIndex);
    +      captionFrame->ResizeReflow(aPresContext, desiredSize, maxSize, &maxElementSize);
    +      if (mMinCaptionWidthVerticallyAlignChild(aPresContext);
    +
    +    }
    +  }
    +  return frComplete;
    +}
    +
    +nsIFrame::ReflowStatus
    +nsTableOuterFrame::ResizeReflowTopCaptionsPass2(nsIPresContext*  aPresContext,
    +                                                nsReflowMetrics& aDesiredSize,
    +                                                const nsSize&    aMaxSize,
    +                                                nsSize*          aMaxElementSize,
    +                                                nsStyleMolecule* aTableStyle)
    +{
    +  ReflowStatus result = frComplete;
    +  nscoord topCaptionY = 0;
    +  if (nsnull!=mCaptionFrames)
    +  {
    +    PRInt32 numCaptions = mCaptionFrames->Count();
    +    for (PRInt32 captionIndex = 0; captionIndex < numCaptions; captionIndex++)
    +    {
    +      // get the caption
    +      nsTableCaptionFrame *captionFrame = (nsTableCaptionFrame *)mCaptionFrames->ElementAt(captionIndex);
    +
    +      // Resolve style
    +      nsIStyleContext* captionStyleContext = captionFrame->GetStyleContext(aPresContext);
    +      NS_ASSERTION(nsnull != captionStyleContext, "null style context for caption");
    +      nsStyleMolecule* captionStyle =
    +        (nsStyleMolecule*)captionStyleContext->GetData(kStyleMoleculeSID);
    +      NS_ASSERTION(nsnull != captionStyle, "null style molecule for caption");
    +
    +      if (NS_STYLE_VERTICAL_ALIGN_BOTTOM==captionStyle->verticalAlign)
    +      { 
    +      }
    +      else
    +      { // top-align captions, the default
    +        // reflow the caption, skipping top captions after the first that doesn't fit
    +        if (frComplete==result)
    +        {
    +          nsReflowMetrics desiredSize;
    +          result = nsContainerFrame::ReflowChild(captionFrame, aPresContext, desiredSize, aMaxSize, nsnull);
    +          // place the caption
    +          captionFrame->SetRect(nsRect(0, topCaptionY, desiredSize.width, desiredSize.height));
    +          if (NS_UNCONSTRAINEDSIZE!=desiredSize.height)
    +            topCaptionY += desiredSize.height;
    +          else
    +            topCaptionY = NS_UNCONSTRAINEDSIZE;
    +          mInnerTableFrame->MoveTo(0, topCaptionY);
    +          if (0==captionFrame->GetIndexInParent())
    +          {
    +            SetFirstContentOffset(captionFrame);
    +            if (gsDebug) printf("OUTER: set first content offset to %d\n", GetFirstContentOffset()); //@@@
    +          }
    +        }
    +        // else continue on, so we can build the mBottomCaptions list
    +      }
    +    }
    +  }
    +  aDesiredSize.width = aMaxSize.width;
    +  aDesiredSize.height = topCaptionY;
    +  if (nsnull!=aMaxElementSize)
    +  { // SEC: this isn't right
    +    aMaxElementSize->width = aMaxSize.width;
    +    aMaxElementSize->height = topCaptionY;
    +  }
    +  return result;
    +}
    +
    +nsIFrame::ReflowStatus
    +nsTableOuterFrame::ResizeReflowBottomCaptionsPass2(nsIPresContext*  aPresContext,
    +                                                   nsReflowMetrics& aDesiredSize,
    +                                                   const nsSize&    aMaxSize,
    +                                                   nsSize*          aMaxElementSize,
    +                                                   nsStyleMolecule* aTableStyle,
    +                                                   nscoord          aYOffset)
    +{
    +  ReflowStatus result = frComplete;
    +  nscoord bottomCaptionY = aYOffset;
    +  // for now, assume all captions are stacked vertically
    +  if (nsnull!=mBottomCaptions)
    +  {
    +    PRInt32 numCaptions = mBottomCaptions->Count();
    +    for (PRInt32 captionIndex = 0; captionIndex < numCaptions; captionIndex++)
    +    {
    +      // get the caption
    +      nsTableCaptionFrame *captionFrame = (nsTableCaptionFrame *)mBottomCaptions->ElementAt(captionIndex);
    +
    +      // Resolve style
    +/*
    +      nsIStyleContext* captionStyleContext = captionFrame->GetStyleContext(aPresContext);
    +      NS_ASSERTION(nsnull != captionStyleContext, "null style context for caption");
    +      nsStyleMolecule* captionStyle =
    +        (nsStyleMolecule*)captionStyleContext->GetData(kStyleMoleculeSID);
    +      NS_ASSERTION(nsnull != captionStyle, "null style molecule for caption");
    +*/
    +      // reflow the caption
    +      nsReflowMetrics desiredSize;
    +      result = nsContainerFrame::ReflowChild(captionFrame, aPresContext, desiredSize, aMaxSize, nsnull);
    +
    +      // place the caption
    +      nsRect rect = captionFrame->GetRect();
    +      rect.y = bottomCaptionY;
    +      rect.width=desiredSize.width;
    +      rect.height=desiredSize.height;
    +      captionFrame->SetRect(rect);
    +      if (NS_UNCONSTRAINEDSIZE!=desiredSize.height)
    +        bottomCaptionY += desiredSize.height;
    +      else
    +        bottomCaptionY = NS_UNCONSTRAINEDSIZE;
    +    }
    +  }
    +  aDesiredSize.width = aMaxSize.width;
    +  aDesiredSize.height = bottomCaptionY-aYOffset;
    +  if (nsnull!=aMaxElementSize)
    +  { // SEC: not right
    +    aMaxElementSize->width = aMaxSize.width;
    +    aMaxElementSize->height = bottomCaptionY-aYOffset;
    +  }
    +  return result;
    +}
    +
    +/**
    + * Sets the last content offset based on the last child frame. If the last
    + * child is a pseudo frame then it sets mLastContentIsComplete to be the same
    + * as the last child's mLastContentIsComplete
    + */
    +/*
    +void nsTableOuterFrame::SetLastContentOffset(const nsIFrame* aLastChild)
    +{
    +  NS_PRECONDITION(nsnull != aLastChild, "bad argument");
    +  NS_PRECONDITION(aLastChild->GetGeometricParent() == this, "bad geometric parent");
    +
    +  if (ChildIsPseudoFrame(aLastChild)) {
    +    nsContainerFrame* pseudoFrame = (nsContainerFrame*)aLastChild;
    +    mLastContentOffset = pseudoFrame->GetLastContentOffset();
    +    mLastContentIsComplete = pseudoFrame->GetLastContentIsComplete();
    +  } else {
    +    mLastContentOffset = aLastChild->GetIndexInParent();
    +  }
    +#ifdef NS_DEBUG
    +  if (mLastContentOffset < mFirstContentOffset) {
    +    nsIFrame* top = this;
    +    while (top->GetGeometricParent() != nsnull) {
    +      top = top->GetGeometricParent();
    +    }
    +    top->List();
    +  }
    +#endif
    +  // it is this next line that forces us to re-implement this method here
    +  //NS_ASSERTION(mLastContentOffset >= mFirstContentOffset, "unexpected content mapping");
    +}
    +*/
    +
    +nsIFrame::ReflowStatus
    +nsTableOuterFrame::IncrementalReflow(nsIPresContext* aPresContext,
    +                                    nsReflowMetrics& aDesiredSize,
    +                                    const nsSize&    aMaxSize,
    +                                    nsReflowCommand& aReflowCommand)
    +{
    +  if (gsDebug == PR_TRUE) printf("nsTableOuterFrame::IncrementalReflow\n");
    +  // total hack for now, just some hard-coded values
    +  ResizeReflow(aPresContext, aDesiredSize, aMaxSize, nsnull);
    +
    +  return frComplete;
    +}
    +
    +nsIFrame* nsTableOuterFrame::CreateContinuingFrame(nsIPresContext* aPresContext,
    +                                                   nsIFrame*       aParent)
    +{
    +  nsTableOuterFrame* cf = new nsTableOuterFrame(mContent, mIndexInParent, aParent);
    +  PrepareContinuingFrame(aPresContext, aParent, cf);
    +  cf->SetFirstPassValid(PR_TRUE);
    +  printf("nsTableOuterFrame::CCF parent = %p, this=%p, cf=%p\n", aParent, this, cf);
    +  return cf;
    +}
    +
    +void nsTableOuterFrame::PrepareContinuingFrame(nsIPresContext*    aPresContext,
    +                                               nsIFrame*          aParent,
    +                                               nsTableOuterFrame* aContFrame)
    +{
    +  // Append the continuing frame to the flow
    +  aContFrame->AppendToFlow(this);
    +
    +  // Initialize it's content offsets. Note that we assume for now that
    +  // the continuingFrame will map the remainder of the content and
    +  // that therefore mLastContentIsComplete will be true.
    +  PRInt32 nextOffset;
    +  if (mChildCount > 0) {
    +    nextOffset = mLastContentOffset;
    +    if (mLastContentIsComplete) {
    +      nextOffset++;
    +    }
    +  } else {
    +    nextOffset = mFirstContentOffset;
    +  }
    +
    +  aContFrame->SetFirstContentOffset(nextOffset);
    +  aContFrame->SetLastContentOffset(nextOffset);
    +  aContFrame->SetLastContentIsComplete(PR_TRUE);
    +
    +  // Resolve style for the continuing frame and set its style context.
    +  // XXX presumptive
    +  nsIStyleContext* styleContext =
    +    aPresContext->ResolveStyleContextFor(mContent, aParent);
    +  aContFrame->SetStyleContext(styleContext);
    +  NS_RELEASE(styleContext);
    +}
    +
    +void nsTableOuterFrame::VerifyTree() const
    +{
    +#ifdef NS_DEBUG
    +  
    +#endif 
    +}
    +
    +void nsTableOuterFrame::CreateInnerTableFrame(nsIPresContext* aPresContext)
    +{
    +  // Do we have a prev-in-flow?
    +  if (nsnull == mPrevInFlow) {
    +    // No, create a column pseudo frame
    +    mInnerTableFrame = new nsTableFrame(mContent, mIndexInParent, this);
    +    mChildCount++;
    +
    +    // Resolve style and set the style context
    +    nsIStyleContext* styleContext =
    +      aPresContext->ResolveStyleContextFor(mContent, this);
    +    mInnerTableFrame->SetStyleContext(styleContext);
    +    NS_RELEASE(styleContext);
    +  } else {
    +    nsTableOuterFrame*  prevOuterTable = (nsTableOuterFrame*)mPrevInFlow;
    +
    +    nsIFrame* prevInnerTable = prevOuterTable->mInnerTableFrame;
    +
    +    // Create a continuing column
    +    mInnerTableFrame = (nsTableFrame *)prevInnerTable->GetNextInFlow();
    +    if (nsnull==mInnerTableFrame)
    +    {
    +      mInnerTableFrame = (nsTableFrame *)prevInnerTable->CreateContinuingFrame(aPresContext, this);
    +      mChildCount++;
    +    }
    +  }
    +}
    +
    +/* ----- static methods ----- */
    +
    +nsresult nsTableOuterFrame::NewFrame(nsIFrame** aInstancePtrResult,
    +                                    nsIContent* aContent,
    +                                    PRInt32     aIndexInParent,
    +                                    nsIFrame*   aParent)
    +{
    +  NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr");
    +  if (nsnull == aInstancePtrResult) {
    +    return NS_ERROR_NULL_POINTER;
    +  }
    +  nsIFrame* it = new nsTableOuterFrame(aContent, aIndexInParent, aParent);
    +  if (nsnull == it) {
    +    return NS_ERROR_OUT_OF_MEMORY;
    +  }
    +  *aInstancePtrResult = it;
    +  return NS_OK;
    +}
    diff --git a/mozilla/layout/tables/nsTableOuterFrame.h b/mozilla/layout/tables/nsTableOuterFrame.h
    new file mode 100644
    index 00000000000..cf5c2c9f9ad
    --- /dev/null
    +++ b/mozilla/layout/tables/nsTableOuterFrame.h
    @@ -0,0 +1,197 @@
    +/* -*- 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.
    + */
    +#ifndef nsTableOuterFrame_h__
    +#define nsTableOuterFrame_h__
    +
    +#include "nscore.h"
    +#include "nsContainerFrame.h"
    +
    +class nsTableFrame;
    +class nsVoidArray;
    +struct nsStyleMolecule;
    +class nsTableCaptionFrame;
    +struct OuterTableReflowState;
    +
    +/**
    + * nsTableOuterFrame
    + * main frame for an nsTable content object.
    + * the nsTableOuterFrame contains 0 or more nsTableCaptionFrames, 
    + * and a single nsTableFrame psuedo-frame.
    + *
    + * @author  sclark
    + */
    +class nsTableOuterFrame : public nsContainerFrame
    +{
    +public:
    +  static nsresult NewFrame(nsIFrame** aInstancePtrResult,
    +                           nsIContent* aContent,
    +                           PRInt32     aIndexInParent,
    +                           nsIFrame*   aParent);
    +
    +  virtual void  Paint(nsIPresContext& aPresContext,
    +                      nsIRenderingContext& aRenderingContext,
    +                      const nsRect& aDirtyRect);
    +
    +  ReflowStatus  ResizeReflow(nsIPresContext*  aPresContext,
    +                             nsReflowMetrics& aDesiredSize,
    +                             const nsSize&    aMaxSize,
    +                             nsSize*          aMaxElementSize);
    +
    +  ReflowStatus  IncrementalReflow(nsIPresContext*  aPresContext,
    +                                  nsReflowMetrics& aDesiredSize,
    +                                  const nsSize&    aMaxSize,
    +                                  nsReflowCommand& aReflowCommand);
    +
    +  /**
    +    * @see nsContainerFrame
    +    */
    +  virtual nsIFrame* CreateContinuingFrame(nsIPresContext* aPresContext,
    +                                          nsIFrame*       aParent);
    +  /** destructor */
    +  virtual ~nsTableOuterFrame();
    +
    +protected:
    +
    +  /** constructor */
    +  nsTableOuterFrame(nsIContent* aContent,
    +                   PRInt32 aIndexInParent,
    +					         nsIFrame* aParentFrame);
    +
    +  /** return PR_TRUE if the table needs to be reflowed.  
    +    * the outer table needs to be reflowed if the table content has changed,
    +    * or if the combination of table style attributes and max height/width have
    +    * changed.
    +    */
    +  virtual PRBool NeedsReflow(const nsSize& aMaxSize);
    +
    +  /** returns PR_TRUE if the data obtained from the first reflow pass
    +    * is cached and still valid (ie, no content or style change notifications.)
    +    */
    +  virtual PRBool IsFirstPassValid();
    +
    +  /** setter for mFirstPassValid. 
    +    * should be called with PR_FALSE when:
    +    *   content changes, style changes, or context changes
    +    */
    +  virtual void SetFirstPassValid(PRBool aValidState);
    +
    +  /** create all child frames for this table */
    +  virtual void CreateChildFrames(nsIPresContext*  aPresContext);
    +
    +  /** reflow the captions in an infinite space, caching the min/max sizes for each
    +    */
    +  virtual ReflowStatus ResizeReflowCaptionsPass1(nsIPresContext*  aPresContext, 
    +                                                 nsStyleMolecule* aTableStyle);
    +
    +  /** reflow the top captions in a space constrained by the computed table width
    +    * and the heigth given to us by our parent.  Top captions are laid down
    +    * before the inner table.
    +    */
    +  virtual ReflowStatus ResizeReflowTopCaptionsPass2(nsIPresContext*  aPresContext,
    +                                                    nsReflowMetrics& aDesiredSize,
    +                                                    const nsSize&    aMaxSize,
    +                                                    nsSize*          aMaxElementSize,
    +                                                    nsStyleMolecule* aTableStyle);
    +
    +  /** reflow the bottom captions in a space constrained by the computed table width
    +    * and the heigth given to us by our parent.  Bottom captions are laid down
    +    * after the inner table.
    +    */
    +  virtual ReflowStatus ResizeReflowBottomCaptionsPass2(nsIPresContext*  aPresContext,
    +                                                       nsReflowMetrics& aDesiredSize,
    +                                                       const nsSize&    aMaxSize,
    +                                                       nsSize*          aMaxElementSize,
    +                                                       nsStyleMolecule* aTableStyle,
    +                                                       nscoord          aYOffset);
    +
    +  nscoord       GetTopMarginFor(nsIPresContext* aCX,
    +                                OuterTableReflowState& aState,
    +                                nsStyleMolecule* aKidMol);
    +
    +  void          PlaceChild( nsIPresContext*    aPresContext,
    +                            OuterTableReflowState& aState,
    +                            nsIFrame*          aKidFrame,
    +                            const nsRect&      aKidRect,
    +                            nsStyleMolecule*   aKidMol,
    +                            nsSize*            aMaxElementSize,
    +                            nsSize&            aKidMaxElementSize);
    +
    +  PRBool        ReflowMappedChildren(nsIPresContext*        aPresContext,
    +                                     OuterTableReflowState& aState,
    +                                     nsSize*                aMaxElementSize);
    +
    +  PRBool        PullUpChildren(nsIPresContext*        aPresContext,
    +                               OuterTableReflowState& aState,
    +                               nsSize*                aMaxElementSize);
    +
    +  virtual       void SetReflowState(OuterTableReflowState& aState, 
    +                                    nsIFrame*              aKidFrame);
    +
    +  virtual nsIFrame::ReflowStatus ReflowChild( nsIFrame*        aKidFrame,
    +                                              nsIPresContext*  aPresContext,
    +                                              nsReflowMetrics& aDesiredSize,
    +                                              const nsSize&    aMaxSize,
    +                                              nsSize*          aMaxElementSize,
    +                                              OuterTableReflowState& aState);
    +
    + /**
    +   * Sets the last content offset based on the last child frame. If the last
    +   * child is a pseudo frame then it sets mLastContentIsComplete to be the same
    +   * as the last child's mLastContentIsComplete
    +   */
    +  //virtual void SetLastContentOffset(const nsIFrame* aLastChild);
    +
    +  /**
    +    * See nsContainerFrame::VerifyTree
    +    */
    +  virtual void VerifyTree() const;
    +
    +  /**
    +    * See nsContainerFrame::PrepareContinuingFrame
    +    */
    +  virtual void PrepareContinuingFrame(nsIPresContext*    aPresContext,
    +                                      nsIFrame*          aParent,
    +                                      nsTableOuterFrame* aContFrame);
    +
    +  /**
    +    */
    +  virtual void CreateInnerTableFrame(nsIPresContext* aPresContext);
    +
    +
    +private:
    +  /** used to keep track of this frame's children */
    +  nsTableFrame *mInnerTableFrame;
    +  nsVoidArray * mCaptionFrames;
    +  nsVoidArray * mBottomCaptions;
    +
    +  /** used to keep track of min/max caption requirements */
    +  PRInt32 mMinCaptionWidth;
    +  PRInt32 mMaxCaptionWidth;
    +
    +  /** used to cache reflow results so we can optimize out reflow in some circumstances */
    +  nsReflowMetrics mDesiredSize;
    +  nsSize mMaxElementSize;
    +
    +  /** we can skip the first pass on captions if mFirstPassValid is true */
    +  PRBool mFirstPassValid;
    +
    +};
    +
    +
    +
    +#endif
    diff --git a/mozilla/layout/tables/nsTableRowFrame.cpp b/mozilla/layout/tables/nsTableRowFrame.cpp
    new file mode 100644
    index 00000000000..668e983a8b4
    --- /dev/null
    +++ b/mozilla/layout/tables/nsTableRowFrame.cpp
    @@ -0,0 +1,317 @@
    +/* -*- 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 "nsTableRowFrame.h"
    +#include "nsIRenderingContext.h"
    +#include "nsIPresContext.h"
    +#include "nsIStyleContext.h"
    +#include "nsStyleConsts.h"
    +#include "nsIContent.h"
    +#include "nsIContentDelegate.h"
    +#include "nsTableFrame.h"
    +#include "nsTableCellFrame.h"
    +#include "nsTableCell.h"
    +#include "nsCellLayoutData.h"
    +
    +#ifdef NS_DEBUG
    +static PRBool gsDebug1 = PR_FALSE;
    +static PRBool gsDebug2 = PR_FALSE;
    +//#define NOISY
    +//#define NOISY_FLOW
    +#else
    +static const PRBool gsDebug1 = PR_FALSE;
    +static const PRBool gsDebug2 = PR_FALSE;
    +#endif
    +
    +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID);
    +
    +nsTableRowFrame::nsTableRowFrame(nsIContent* aContent,
    +                     PRInt32     aIndexInParent,
    +                     nsIFrame*   aParentFrame)
    +  : nsContainerFrame(aContent, aIndexInParent, aParentFrame),
    +    mTallestCell(0)
    +{
    +}
    +
    +nsTableRowFrame::~nsTableRowFrame()
    +{
    +}
    +
    +void nsTableRowFrame::ResetMaxChildHeight()
    +{
    +  mTallestCell=0;
    +}
    +
    +void nsTableRowFrame::SetMaxChildHeight(PRInt32 aChildHeight)
    +{
    +  if (mTallestCellGetRect(kidRect);
    +    nsRect damageArea(aDirtyRect);
    +    // Translate damage area into kid's coordinate system
    +    nsRect kidDamageArea(damageArea.x - kidRect.x, damageArea.y - kidRect.y,
    +                         damageArea.width, damageArea.height);
    +    aRenderingContext.PushState();
    +    aRenderingContext.Translate(kidRect.x, kidRect.y);
    +    kid->Paint(aPresContext, aRenderingContext, kidDamageArea);
    +    if (nsIFrame::GetShowFrameBorders()) {
    +      aRenderingContext.SetColor(NS_RGB(255,0,0));
    +      aRenderingContext.DrawRect(0, 0, kidRect.width, kidRect.height);
    +    }
    +    aRenderingContext.PopState();
    +    kid = kid->GetNextSibling();
    +  }
    +}
    +
    +
    +/** returns the tallest child in this row (ignoring any cell with rowspans) */
    +PRInt32 nsTableRowFrame::GetTallestChild() const
    +{
    +  return mTallestCell;
    +}
    +
    +/*
    +
    +want to use min space the child can fit in to
    +determine its real size, unless fixed columns sizes
    +are present.
    +
    +  */
    +
    +/** Layout the entire row.
    +  * This method stacks rows horizontally according to HTML 4.0 rules.
    +  * Rows are responsible for layout of their children.
    +  */
    +nsIFrame::ReflowStatus
    +nsTableRowFrame::ResizeReflow(nsIPresContext*  aPresContext,
    +                              nsReflowMetrics& aDesiredSize,
    +                              const nsSize&    aMaxSize,
    +                              nsSize*          aMaxElementSize)
    +{
    +  if (gsDebug1==PR_TRUE) 
    +    printf("nsTableRowFrame::ResizeReflow - %p with aMaxSize = %d, %d\n",
    +            this, aMaxSize.width, aMaxSize.height);
    +#ifdef NS_DEBUG
    +  PreReflowCheck();
    +#endif
    +
    +  PRInt32 maxCellHeight = 0;
    +  ResetMaxChildHeight();
    +
    +  ReflowStatus result = frComplete;
    +
    +  mFirstContentOffset = mLastContentOffset = 0;
    +
    +  nsIContent* c = mContent;
    +
    +  nsSize availSize(aMaxSize);
    +  nsSize maxSize(0, 0);
    +  nsSize kidMaxSize(0,0);
    +  nsReflowMetrics kidSize;
    +  nscoord cellXOffset = 0;
    +  nscoord maxAscent = 0;
    +  nscoord maxDescent = 0;
    +  PRInt32 kidIndex = 0;
    +  PRInt32 lastIndex = c->ChildCount();
    +  nsIFrame* prevKidFrame = nsnull;/* XXX incremental reflow! */
    +
    +// Row doesn't factor in insets, the cells do that
    +
    +  nsTableFrame *tableFrame = (nsTableFrame *)(GetContentParent()->GetContentParent());
    +
    +  for (;;) {
    +    nsIContent* kid = c->ChildAt(kidIndex);   // kid: REFCNT++
    +    if (nsnull == kid) {
    +      result = frComplete;
    +      break;
    +    }
    +
    +    // get frame, creating one if needed
    +    nsIFrame* kidFrame = ChildAt(kidIndex);
    +    if (nsnull==kidFrame)
    +    {
    +      nsIContentDelegate* kidDel;
    +      kidDel = kid->GetDelegate(aPresContext);
    +      kidFrame = kidDel->CreateFrame(aPresContext, kid, kidIndex, this);
    +      mChildCount++;
    +      NS_RELEASE(kidDel);
    +      // Resolve style
    +      nsIStyleContext* kidStyleContext =
    +        aPresContext->ResolveStyleContextFor(kid, this);
    +      NS_ASSERTION(nsnull!=kidStyleContext, "bad style context for kid.");
    +      kidFrame->SetStyleContext(kidStyleContext);
    +      NS_RELEASE(kidStyleContext);
    +    }
    +
    +    nsTableCell* cell = (nsTableCell *)(kidFrame->GetContent());  // cell: ADDREF++
    +    // Try to reflow the child into the available space.
    +    if (NS_UNCONSTRAINEDSIZE == availSize.width)
    +    {  // Each cell is given the entire row width to try to lay out into
    +      result = ReflowChild(kidFrame, aPresContext, kidSize, availSize, &kidMaxSize);
    +      if (gsDebug1) printf("reflow of cell returned result = %s with desired=%d,%d, min = %d,%d\n",
    +                            result==frComplete?"complete":"NOT complete", 
    +                            kidSize.width, kidSize.height, kidMaxSize.width, kidMaxSize.height);
    +      nsCellLayoutData kidLayoutData((nsTableCellFrame *)kidFrame, &kidSize, &kidMaxSize);
    +      tableFrame->SetCellLayoutData(&kidLayoutData, cell);
    +    }
    +    else
    +    { // we're in a constrained situation, so get the avail width from the known column widths
    +      nsTableFrame *innerTableFrame = (nsTableFrame *)(GetContentParent()->GetContentParent());
    +      nsCellLayoutData *cellData = innerTableFrame->GetCellLayoutData(cell);
    +      PRInt32 cellStartingCol = cell->GetColIndex();
    +      PRInt32 cellColSpan = cell->GetColSpan();
    +      PRInt32 availWidth = 0;
    +      for (PRInt32 numColSpan=0; numColSpanGetColumnWidth(cellStartingCol+numColSpan);
    +      NS_ASSERTION(0GetColIndex(); colIndex++)
    +        cellXOffset += innerTableFrame->GetColumnWidth(colIndex);
    +    }
    +    PRInt32 rowSpan = cell->GetRowSpan();
    +    if ((1==rowSpan) && (maxCellHeightSetRect(nsRect(cellXOffset, 0, kidSize.width, kidSize.height));
    +    if (kidSize.width > maxSize.width) {
    +      maxSize.width = kidSize.width;
    +    }
    +    if ((1==rowSpan) && (kidSize.height > maxSize.height)) {
    +      maxSize.height = kidSize.height;
    +    }
    +    if (NS_UNCONSTRAINEDSIZE!=cellXOffset)
    +      cellXOffset+=kidSize.width;
    +    if (cellXOffset<=0)
    +      cellXOffset = NS_UNCONSTRAINEDSIZE;   // handle overflow
    +
    +    // Link child frame into the list of children
    +    if (nsnull != prevKidFrame) {
    +      prevKidFrame->SetNextSibling(kidFrame);
    +    } else {
    +      // Our first child (**blush**)
    +      mFirstChild = kidFrame;
    +      SetFirstContentOffset(kidFrame);
    +      if (gsDebug1) printf("ROW: set first content offset to %d\n", GetFirstContentOffset()); //@@@
    +    }
    +    prevKidFrame = kidFrame;
    +
    +    kidIndex++;
    +    if (frNotComplete == result) {
    +      // If the child didn't finish layout then it means that it used
    +      // up all of our available space (or needs us to split).
    +      mLastContentIsComplete = PR_FALSE;
    +      break;
    +    }
    +    NS_RELEASE(kid);  // kid: REFCNT--
    +  }
    +
    +  if (nsnull != prevKidFrame) {
    +    NS_ASSERTION(LastChild() == prevKidFrame, "unexpected last child");
    +    SetLastContentOffset(prevKidFrame);
    +  }
    +
    +  // Return our size and our result
    +  aDesiredSize.width = cellXOffset;
    +  aDesiredSize.height = maxSize.height;
    +  aDesiredSize.ascent = maxAscent;
    +  aDesiredSize.descent = maxDescent;
    +  if (nsnull != aMaxElementSize) {
    +    *aMaxElementSize = kidMaxSize;
    +  }
    +  SetMaxChildHeight(maxCellHeight);  // remember height of tallest child who doesn't have a row span
    +
    +#ifdef NS_DEBUG
    +  PostReflowCheck(result);
    +#endif
    +
    +  return result;
    +
    +}
    +
    +nsIFrame::ReflowStatus
    +nsTableRowFrame::IncrementalReflow(nsIPresContext*  aPresContext,
    +                             nsReflowMetrics& aDesiredSize,
    +                             const nsSize&    aMaxSize,
    +                             nsReflowCommand& aReflowCommand)
    +{
    +  if (gsDebug1==PR_TRUE) printf("nsTableRowFrame::IncrementalReflow\n");
    +  return frComplete;
    +}
    +
    +nsIFrame* nsTableRowFrame::CreateContinuingFrame(nsIPresContext* aPresContext,
    +                                                 nsIFrame*       aParent)
    +{
    +  nsTableRowFrame* cf = new nsTableRowFrame(mContent, mIndexInParent, aParent);
    +  PrepareContinuingFrame(aPresContext, aParent, cf);
    +  return cf;
    +}
    +
    +nsresult nsTableRowFrame::NewFrame( nsIFrame** aInstancePtrResult,
    +                                    nsIContent* aContent,
    +                                    PRInt32     aIndexInParent,
    +                                    nsIFrame*   aParent)
    +{
    +  NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr");
    +  if (nsnull == aInstancePtrResult) {
    +    return NS_ERROR_NULL_POINTER;
    +  }
    +  nsIFrame* it = new nsTableRowFrame(aContent, aIndexInParent, aParent);
    +  if (nsnull == it) {
    +    return NS_ERROR_OUT_OF_MEMORY;
    +  }
    +  *aInstancePtrResult = it;
    +  return NS_OK;
    +}
    +
    diff --git a/mozilla/layout/tables/nsTableRowFrame.h b/mozilla/layout/tables/nsTableRowFrame.h
    new file mode 100644
    index 00000000000..d410b77472c
    --- /dev/null
    +++ b/mozilla/layout/tables/nsTableRowFrame.h
    @@ -0,0 +1,86 @@
    +/* -*- 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.
    + */
    +#ifndef nsTableRowFrame_h__
    +#define nsTableRowFrame_h__
    +
    +#include "nscore.h"
    +#include "nsContainerFrame.h"
    +
    +
    +/**
    + * nsTableRowFrame
    + * data structure to maintain information about a single table row's geometry
    + *
    + * @author  sclark
    + */
    +/**
    +  */
    +class nsTableRowFrame : public nsContainerFrame
    +{
    +public:
    +  static nsresult NewFrame(nsIFrame** aInstancePtrResult,
    +                           nsIContent* aContent,
    +                           PRInt32     aIndexInParent,
    +                           nsIFrame*   aParent);
    +
    +  virtual void  Paint(nsIPresContext&      aPresContext,
    +                      nsIRenderingContext& aRenderingContext,
    +                      const nsRect&        aDirtyRect);
    +
    +  virtual void PaintChildren(nsIPresContext&      aPresContext,
    +                             nsIRenderingContext& aRenderingContext,
    +                             const nsRect&        aDirtyRect);
    +
    +  ReflowStatus  ResizeReflow(nsIPresContext*  aPresContext,
    +                             nsReflowMetrics& aDesiredSize,
    +                             const nsSize&    aMaxSize,
    +                             nsSize*          aMaxElementSize);
    +
    +  ReflowStatus  IncrementalReflow(nsIPresContext*  aPresContext,
    +                                  nsReflowMetrics& aDesiredSize,
    +                                  const nsSize&    aMaxSize,
    +                                  nsReflowCommand& aReflowCommand);
    +
    +  /**
    +   * @see nsContainerFrame
    +   */
    +  virtual nsIFrame* CreateContinuingFrame(nsIPresContext* aPresContext,
    +                                          nsIFrame*       aParent);
    +
    +  void ResetMaxChildHeight();
    +
    +  void SetMaxChildHeight(PRInt32 aChildHeight);
    +
    +  /** returns the tallest child in this row (ignoring any cell with rowspans) */
    +  PRInt32 GetTallestChild() const;
    +
    +
    +protected:
    +
    +    nsTableRowFrame(nsIContent* aContent,
    +                  PRInt32 aIndexInParent,
    +					        nsIFrame* aParentFrame);
    +
    +    virtual ~nsTableRowFrame();
    +
    +private:
    +  PRInt32 mTallestCell; // not my height, but the height of my tallest child
    +
    +};
    +
    +#endif
    diff --git a/mozilla/layout/tables/nsTableRowGroupFrame.cpp b/mozilla/layout/tables/nsTableRowGroupFrame.cpp
    new file mode 100644
    index 00000000000..5a460592a85
    --- /dev/null
    +++ b/mozilla/layout/tables/nsTableRowGroupFrame.cpp
    @@ -0,0 +1,957 @@
    +/* -*- 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 "nsTableRowGroupFrame.h"
    +#include "nsTableRowFrame.h"
    +#include "nsTableCellFrame.h"
    +#include "nsIRenderingContext.h"
    +#include "nsIPresContext.h"
    +#include "nsIStyleContext.h"
    +#include "nsStyleConsts.h"
    +#include "nsIContent.h"
    +#include "nsIContentDelegate.h"
    +
    +
    +#ifdef NS_DEBUG
    +static PRBool gsDebug1 = PR_FALSE;
    +static PRBool gsDebug2 = PR_FALSE;
    +//#define NOISY
    +//#define NOISY_FLOW
    +#else
    +static const PRBool gsDebug1 = PR_FALSE;
    +static const PRBool gsDebug2 = PR_FALSE;
    +#endif
    +
    +static NS_DEFINE_IID(kStyleMoleculeSID, NS_STYLEMOLECULE_SID);
    +
    +/* ----------- RowGroupReflowState ---------- */
    +
    +struct RowGroupReflowState {
    +
    +  // The body's style molecule
    +  nsStyleMolecule* mol;
    +
    +  // The body's available size (computed from the body's parent)
    +  nsSize availSize;
    +
    +  // Margin tracking information
    +  nscoord prevMaxPosBottomMargin;
    +  nscoord prevMaxNegBottomMargin;
    +
    +  // Flags for whether the max size is unconstrained
    +  PRBool  unconstrainedWidth;
    +  PRBool  unconstrainedHeight;
    +
    +  // Running y-offset
    +  nscoord y;
    +
    +  // Flag used to set aMaxElementSize to my first row
    +  PRBool  firstRow;
    +
    +  // Remember the height of the first row, because it's our maxElementHeight (plus header/footers)
    +  nscoord firstRowHeight;
    +
    +  RowGroupReflowState(nsIPresContext*  aPresContext,
    +                      const nsSize&    aMaxSize,
    +                      nsStyleMolecule* aMol)
    +  {
    +    mol = aMol;
    +    availSize.width = aMaxSize.width;
    +    availSize.height = aMaxSize.height;
    +    prevMaxPosBottomMargin = 0;
    +    prevMaxNegBottomMargin = 0;
    +    y=0;  // border/padding/margin???
    +    unconstrainedWidth = PRBool(aMaxSize.width == NS_UNCONSTRAINEDSIZE);
    +    unconstrainedHeight = PRBool(aMaxSize.height == NS_UNCONSTRAINEDSIZE);
    +    firstRow = PR_TRUE;
    +    firstRowHeight=0;
    +  }
    +
    +  ~RowGroupReflowState() {
    +  }
    +};
    +
    +
    +
    +
    +/* ----------- nsTableRowGroupFrame ---------- */
    +
    +nsTableRowGroupFrame::nsTableRowGroupFrame(nsIContent* aContent,
    +                     PRInt32     aIndexInParent,
    +                     nsIFrame*   aParentFrame)
    +  : nsContainerFrame(aContent, aIndexInParent, aParentFrame)
    +{
    +}
    +
    +nsTableRowGroupFrame::~nsTableRowGroupFrame()
    +{
    +}
    +
    +
    +void nsTableRowGroupFrame::Paint(nsIPresContext& aPresContext,
    +                                 nsIRenderingContext& aRenderingContext,
    +                                 const nsRect&        aDirtyRect)
    +{
    +
    +  // for debug...
    +  if (nsIFrame::GetShowFrameBorders()) {
    +    aRenderingContext.SetColor(NS_RGB(128,0,0));
    +    aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height);
    +  }
    +
    +  PaintChildren(aPresContext, aRenderingContext, aDirtyRect);
    +}
    +
    +// aDirtyRect is in our coordinate system
    +// child rect's are also in our coordinate system
    +/** overloaded method from nsContainerFrame.  The difference is that 
    +  * we don't want to clip our children, so a cell can do a rowspan
    +  */
    +void nsTableRowGroupFrame::PaintChildren(nsIPresContext&      aPresContext,
    +                                         nsIRenderingContext& aRenderingContext,
    +                                         const nsRect&        aDirtyRect)
    +{
    +  nsIFrame* kid = mFirstChild;
    +  while (nsnull != kid) {
    +    nsRect kidRect;
    +    kid->GetRect(kidRect);
    +    nsRect damageArea(aDirtyRect);
    +    // Translate damage area into kid's coordinate system
    +    nsRect kidDamageArea(damageArea.x - kidRect.x, damageArea.y - kidRect.y,
    +                         damageArea.width, damageArea.height);
    +    aRenderingContext.PushState();
    +    aRenderingContext.Translate(kidRect.x, kidRect.y);
    +    kid->Paint(aPresContext, aRenderingContext, kidDamageArea);
    +    if (nsIFrame::GetShowFrameBorders()) {
    +      aRenderingContext.SetColor(NS_RGB(255,0,0));
    +      aRenderingContext.DrawRect(0, 0, kidRect.width, kidRect.height);
    +    }
    +    aRenderingContext.PopState();
    +    kid = kid->GetNextSibling();
    +  }
    +}
    +
    +// Collapse child's top margin with previous bottom margin
    +nscoord nsTableRowGroupFrame::GetTopMarginFor(nsIPresContext*      aCX,
    +                                              RowGroupReflowState& aState,
    +                                              nsStyleMolecule*     aKidMol)
    +{
    +  nscoord margin;
    +  nscoord maxNegTopMargin = 0;
    +  nscoord maxPosTopMargin = 0;
    +  if ((margin = aKidMol->margin.top) < 0) {
    +    maxNegTopMargin = -margin;
    +  } else {
    +    maxPosTopMargin = margin;
    +  }
    +
    +  nscoord maxPos = PR_MAX(aState.prevMaxPosBottomMargin, maxPosTopMargin);
    +  nscoord maxNeg = PR_MAX(aState.prevMaxNegBottomMargin, maxNegTopMargin);
    +  margin = maxPos - maxNeg;
    +
    +  return margin;
    +}
    +
    +// Position and size aKidFrame and update our reflow state. The origin of
    +// aKidRect is relative to the upper-left origin of our frame, and includes
    +// any left/top margin.
    +void nsTableRowGroupFrame::PlaceChild(nsIPresContext*    aPresContext,
    +                             RowGroupReflowState& aState,
    +                             nsIFrame*          aKidFrame,
    +                             const nsRect&      aKidRect,
    +                             nsStyleMolecule*   aKidMol,
    +                             nsSize*            aMaxElementSize,
    +                             nsSize&            aKidMaxElementSize)
    +{
    +  // Place and size the child
    +  aKidFrame->SetRect(aKidRect);
    +
    +  // Adjust the running y-offset
    +  aState.y += aKidRect.height;
    +
    +  // If our height is constrained then update the available height
    +  if (PR_FALSE == aState.unconstrainedHeight) {
    +    aState.availSize.height -= aKidRect.height;
    +  }
    +
    +  // Update the maximum element size
    +  if (PR_TRUE==aState.firstRow)
    +  {
    +    aState.firstRow = PR_FALSE;
    +    aState.firstRowHeight = aKidRect.height;
    +    if (nsnull != aMaxElementSize) {
    +      aMaxElementSize->width = aKidMaxElementSize.width;
    +      aMaxElementSize->height = aKidMaxElementSize.height;
    +    }
    +  }
    +}
    +
    +/**
    + * Reflow the frames we've already created
    + *
    + * @param   aPresContext presentation context to use
    + * @param   aState current inline state
    + * @return  true if we successfully reflowed all the mapped children and false
    + *            otherwise, e.g. we pushed children to the next in flow
    + */
    +PRBool nsTableRowGroupFrame::ReflowMappedChildren( nsIPresContext*      aPresContext,
    +                                                   RowGroupReflowState& aState,
    +                                                   nsSize*              aMaxElementSize)
    +{
    +#ifdef NS_DEBUG
    +  VerifyLastIsComplete();
    +#endif
    +#ifdef NOISY
    +  ListTag(stdout);
    +  printf(": reflow mapped (childCount=%d) [%d,%d,%c]\n",
    +         mChildCount,
    +         mFirstContentOffset, mLastContentOffset,
    +         (mLastContentIsComplete ? 'T' : 'F'));
    +#ifdef NOISY_FLOW
    +  {
    +    nsTableRowGroupFrame* flow = (nsTableRowGroupFrame*) mNextInFlow;
    +    while (flow != 0) {
    +      printf("  %p: [%d,%d,%c]\n",
    +             flow, flow->mFirstContentOffset, flow->mLastContentOffset,
    +             (flow->mLastContentIsComplete ? 'T' : 'F'));
    +      flow = (nsTableRowGroupFrame*) flow->mNextInFlow;
    +    }
    +  }
    +#endif
    +#endif
    +  NS_PRECONDITION(nsnull != mFirstChild, "no children");
    +
    +  PRInt32   childCount = 0;
    +  nsIFrame* prevKidFrame = nsnull;
    +
    +  // Remember our original mLastContentIsComplete so that if we end up
    +  // having to push children, we have the correct value to hand to
    +  // PushChildren.
    +  PRBool    lastContentIsComplete = mLastContentIsComplete;
    +
    +  nsSize    kidMaxElementSize;
    +  nsSize*   pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull;
    +  PRBool    result = PR_TRUE;
    +
    +  for (nsIFrame*  kidFrame = mFirstChild; nsnull != kidFrame; ) {
    +    nsSize                  kidAvailSize(aState.availSize);
    +    nsReflowMetrics         desiredSize;
    +    nsIFrame::ReflowStatus  status;
    +
    +    // Get top margin for this kid
    +    nsIContent* kid = kidFrame->GetContent();
    +    nsIStyleContext* kidSC = kidFrame->GetStyleContext(aPresContext);
    +    nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID);
    +    nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol);
    +    nscoord bottomMargin = kidMol->margin.bottom;
    +    NS_RELEASE(kid);
    +    NS_RELEASE(kidSC);
    +
    +    // Figure out the amount of available size for the child (subtract
    +    // off the top margin we are going to apply to it)
    +    if (PR_FALSE == aState.unconstrainedHeight) {
    +      kidAvailSize.height -= topMargin;
    +    }
    +    // Subtract off for left and right margin
    +    if (PR_FALSE == aState.unconstrainedWidth) {
    +      kidAvailSize.width -= kidMol->margin.left + kidMol->margin.right;
    +    }
    +
    +    // Only skip the reflow if this is not our first child and we are
    +    // out of space.
    +    if ((kidFrame == mFirstChild) || (kidAvailSize.height > 0)) {
    +      // Reflow the child into the available space
    +      status = ReflowChild(kidFrame, aPresContext, desiredSize,
    +                           kidAvailSize, pKidMaxElementSize);
    +    }
    +
    +    // Did the child fit?
    +    if ((kidFrame != mFirstChild) &&
    +        ((kidAvailSize.height <= 0) ||
    +         (desiredSize.height > kidAvailSize.height)))
    +    {
    +      // The child's height is too big to fit at all in our remaining space,
    +      // and it's not our first child.
    +      //
    +      // Note that if the width is too big that's okay and we allow the
    +      // child to extend horizontally outside of the reflow area
    +
    +      // Since we are giving the next-in-flow our last child, we
    +      // give it our original mLastContentIsComplete, too (in case we
    +      // are pushing into an empty next-in-flow)
    +      PushChildren(kidFrame, prevKidFrame, lastContentIsComplete);
    +
    +      // Our mLastContentIsComplete was already set by the last kid we
    +      // reflowed reflow's status
    +      result = PR_FALSE;
    +      break;
    +    }
    +
    +    // Place the child after taking into account it's margin
    +    aState.y += topMargin;
    +    nsRect kidRect (0, 0, desiredSize.width, desiredSize.height);
    +    kidRect.x += kidMol->margin.left;
    +    kidRect.y += aState.y;
    +    PlaceChild(aPresContext, aState, kidFrame, kidRect, kidMol, aMaxElementSize,
    +               kidMaxElementSize);
    +    if (bottomMargin < 0) {
    +      aState.prevMaxNegBottomMargin = -bottomMargin;
    +    } else {
    +      aState.prevMaxPosBottomMargin = bottomMargin;
    +    }
    +    childCount++;
    +
    +    // Update mLastContentIsComplete now that this kid fits
    +    mLastContentIsComplete = PRBool(status == frComplete);
    +
    +    // Special handling for incomplete children
    +    if (frNotComplete == status) {
    +      // XXX It's good to assume that we might still have room
    +      // even if the child didn't complete (floaters will want this)
    +      nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow();
    +      if (nsnull == kidNextInFlow) {
    +        // No the child isn't complete, and it doesn't have a next in flow so
    +        // create a continuing frame. This hooks the child into the flow.
    +        nsIFrame* continuingFrame =
    +          kidFrame->CreateContinuingFrame(aPresContext, this);
    +
    +        // Insert the frame. We'll reflow it next pass through the loop
    +        nsIFrame* nextSib = kidFrame->GetNextSibling();
    +        continuingFrame->SetNextSibling(nextSib);
    +        kidFrame->SetNextSibling(continuingFrame);
    +        if (nsnull == nextSib) {
    +          // Assume that the continuation frame we just created is
    +          // complete, for now. It will get reflowed by our
    +          // next-in-flow (we are going to push it now)
    +          lastContentIsComplete = PR_TRUE;
    +        }
    +      }
    +    }
    +
    +    // Get the next child
    +    prevKidFrame = kidFrame;
    +    kidFrame = kidFrame->GetNextSibling();
    +
    +    // XXX talk with troy about checking for available space here
    +  }
    +
    +  // Update the child count
    +  mChildCount = childCount;
    +  NS_POSTCONDITION(LengthOf(mFirstChild) == mChildCount, "bad child count");
    +
    +  // Set the last content offset based on the last child we mapped.
    +  NS_ASSERTION(LastChild() == prevKidFrame, "unexpected last child");
    +  SetLastContentOffset(prevKidFrame);
    +
    +#ifdef NS_DEBUG
    +  VerifyLastIsComplete();
    +#endif
    +#ifdef NOISY
    +  ListTag(stdout);
    +  printf(": reflow mapped %sok (childCount=%d) [%d,%d,%c]\n",
    +         (result ? "" : "NOT "),
    +         mChildCount,
    +         mFirstContentOffset, mLastContentOffset,
    +         (mLastContentIsComplete ? 'T' : 'F'));
    +#ifdef NOISY_FLOW
    +  {
    +    nsTableRowGroupFrame* flow = (nsTableRowGroupFrame*) mNextInFlow;
    +    while (flow != 0) {
    +      printf("  %p: [%d,%d,%c]\n",
    +             flow, flow->mFirstContentOffset, flow->mLastContentOffset,
    +             (flow->mLastContentIsComplete ? 'T' : 'F'));
    +      flow = (nsTableRowGroupFrame*) flow->mNextInFlow;
    +    }
    +  }
    +#endif
    +#endif
    +  return result;
    +}
    +
    +/**
    + * Try and pull-up frames from our next-in-flow
    + *
    + * @param   aPresContext presentation context to use
    + * @param   aState current inline state
    + * @return  true if we successfully pulled-up all the children and false
    + *            otherwise, e.g. child didn't fit
    + */
    +PRBool nsTableRowGroupFrame::PullUpChildren(nsIPresContext*      aPresContext,
    +                                            RowGroupReflowState& aState,
    +                                            nsSize*              aMaxElementSize)
    +{
    +#ifdef NS_DEBUG
    +  VerifyLastIsComplete();
    +#endif
    +#ifdef NOISY
    +  ListTag(stdout);
    +  printf(": pullup (childCount=%d) [%d,%d,%c]\n",
    +         mChildCount,
    +         mFirstContentOffset, mLastContentOffset,
    +         (mLastContentIsComplete ? 'T' : 'F'));
    +#ifdef NOISY_FLOW
    +  {
    +    nsTableRowGroupFrame* flow = (nsTableRowGroupFrame*) mNextInFlow;
    +    while (flow != 0) {
    +      printf("  %p: [%d,%d,%c]\n",
    +             flow, flow->mFirstContentOffset, flow->mLastContentOffset,
    +             (flow->mLastContentIsComplete ? 'T' : 'F'));
    +      flow = (nsTableRowGroupFrame*) flow->mNextInFlow;
    +    }
    +  }
    +#endif
    +#endif
    +  NS_PRECONDITION(nsnull != mNextInFlow, "null next-in-flow");
    +  nsTableRowGroupFrame*  nextInFlow = (nsTableRowGroupFrame*)mNextInFlow;
    +  nsSize        kidMaxElementSize;
    +  nsSize*       pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull;
    +
    +  // The frame previous to the current frame we are reflowing. This
    +  // starts out initially as our last frame.
    +  nsIFrame*     prevKidFrame = LastChild();
    +
    +  // This will hold the prevKidFrame's mLastContentIsComplete
    +  // status. If we have to push the frame that follows prevKidFrame
    +  // then this will become our mLastContentIsComplete state. Since
    +  // prevKidFrame is initially our last frame, it's completion status
    +  // is our mLastContentIsComplete value.
    +  PRBool        prevLastContentIsComplete = mLastContentIsComplete;
    +  PRBool        result = PR_TRUE;
    +
    +  while (nsnull != nextInFlow) {
    +    nsReflowMetrics desiredSize;
    +    nsSize  kidAvailSize(aState.availSize);
    +
    +    // Get first available frame from the next-in-flow
    +    nsIFrame* kidFrame = PullUpOneChild(nextInFlow, prevKidFrame);
    +    if (nsnull == kidFrame) {
    +      // We've pulled up all the children from that next-in-flow, so
    +      // move to the next next-in-flow.
    +      nextInFlow = (nsTableRowGroupFrame*) nextInFlow->mNextInFlow;
    +      continue;
    +    }
    +
    +    // Get top margin for this kid
    +    nsIContent* kid = kidFrame->GetContent();
    +    nsIStyleContext* kidSC = kidFrame->GetStyleContext(aPresContext);
    +    nsStyleMolecule* kidMol = (nsStyleMolecule*)kidSC->GetData(kStyleMoleculeSID);
    +    nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol);
    +    nscoord bottomMargin = kidMol->margin.bottom;
    +
    +    // Figure out the amount of available size for the child (subtract
    +    // off the top margin we are going to apply to it)
    +    if (PR_FALSE == aState.unconstrainedHeight) {
    +      kidAvailSize.height -= topMargin;
    +    }
    +    // Subtract off for left and right margin
    +    if (PR_FALSE == aState.unconstrainedWidth) {
    +      kidAvailSize.width -= kidMol->margin.left + kidMol->margin.right;
    +    }
    +
    +    ReflowStatus status;
    +    do {
    +      // Only skip the reflow if this is not our first child and we are
    +      // out of space.
    +      if ((kidFrame == mFirstChild) || (kidAvailSize.height > 0)) {
    +        status = ReflowChild(kidFrame, aPresContext, desiredSize,
    +                             kidAvailSize, pKidMaxElementSize);
    +      }
    +
    +      // Did the child fit?
    +      if ((kidFrame != mFirstChild) &&
    +          ((kidAvailSize.height <= 0) ||
    +           (desiredSize.height > kidAvailSize.height)))
    +      {
    +        // The child's height is too big to fit at all in our remaining space,
    +        // and it wouldn't have been our first child.
    +        //
    +        // Note that if the width is too big that's okay and we allow the
    +        // child to extend horizontally outside of the reflow area
    +        PRBool lastComplete = PRBool(nsnull == kidFrame->GetNextInFlow());
    +        PushChildren(kidFrame, prevKidFrame, lastComplete);
    +        mLastContentIsComplete = prevLastContentIsComplete;
    +        mChildCount--;
    +        result = PR_FALSE;
    +        NS_RELEASE(kid);
    +        NS_RELEASE(kidSC);
    +        goto push_done;
    +      }
    +
    +      // Place the child
    +      aState.y += topMargin;
    +      nsRect kidRect (0, 0, desiredSize.width, desiredSize.height);
    +      kidRect.x += kidMol->margin.left;
    +      kidRect.y += aState.y;
    +      PlaceChild(aPresContext, aState, kidFrame, kidRect, kidMol, aMaxElementSize,
    +                 kidMaxElementSize);
    +      if (bottomMargin < 0) {
    +        aState.prevMaxNegBottomMargin = -bottomMargin;
    +      } else {
    +        aState.prevMaxPosBottomMargin = bottomMargin;
    +      }
    +      mLastContentIsComplete = PRBool(status == frComplete);
    +
    +#ifdef NOISY
    +      ListTag(stdout);
    +      printf(": pulled up ");
    +      ((nsFrame*)kidFrame)->ListTag(stdout);
    +      printf("\n");
    +#endif
    +
    +      // Is the child we just pulled up complete?
    +      if (frNotComplete == status) {
    +        // No the child isn't complete.
    +        nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow();
    +        if (nsnull == kidNextInFlow) {
    +          // The child doesn't have a next-in-flow so create a
    +          // continuing frame. The creation appends it to the flow and
    +          // prepares it for reflow.
    +          nsIFrame* continuingFrame =
    +            kidFrame->CreateContinuingFrame(aPresContext, this);
    +
    +          // Add the continuing frame to our sibling list.
    +          continuingFrame->SetNextSibling(kidFrame->GetNextSibling());
    +          kidFrame->SetNextSibling(continuingFrame);
    +          prevKidFrame = kidFrame;
    +          prevLastContentIsComplete = mLastContentIsComplete;
    +          kidFrame = continuingFrame;
    +          mChildCount++;
    +        } else {
    +          // The child has a next-in-flow, but it's not one of ours.
    +          // It *must* be in one of our next-in-flows. Collect it
    +          // then.
    +          NS_ASSERTION(kidNextInFlow->GetGeometricParent() != this,
    +                       "busted kid next-in-flow");
    +          break;
    +        }
    +      }
    +    } while (frNotComplete == status);
    +    NS_RELEASE(kid);
    +    NS_RELEASE(kidSC);
    +
    +    prevKidFrame = kidFrame;
    +    prevLastContentIsComplete = mLastContentIsComplete;
    +  }
    +
    + push_done:;
    +  // Update our last content index
    +  if (nsnull != prevKidFrame) {
    +    NS_ASSERTION(LastChild() == prevKidFrame, "bad last child");
    +    SetLastContentOffset(prevKidFrame);
    +  }
    +
    +  // We need to make sure the first content offset is correct for any empty
    +  // next-in-flow frames (frames where we pulled up all the child frames)
    +  nextInFlow = (nsTableRowGroupFrame*)mNextInFlow;
    +  if ((nsnull != nextInFlow) && (nsnull == nextInFlow->mFirstChild)) {
    +    // We have at least one empty frame. Did we succesfully pull up all the
    +    // child frames?
    +    if (PR_FALSE == result) {
    +      // No, so we need to adjust the first content offset of all the empty
    +      // frames
    +      AdjustOffsetOfEmptyNextInFlows();
    +#ifdef NS_DEBUG
    +    } else {
    +      // Yes, we successfully pulled up all the child frames which means all
    +      // the next-in-flows must be empty. Do a sanity check
    +      while (nsnull != nextInFlow) {
    +        NS_ASSERTION(nsnull == nextInFlow->mFirstChild, "non-empty next-in-flow");
    +        nextInFlow = (nsTableRowGroupFrame*)nextInFlow->GetNextInFlow();
    +      }
    +#endif
    +    }
    +  }
    +
    +#ifdef NS_DEBUG
    +  PRInt32 len = LengthOf(mFirstChild);
    +  NS_ASSERTION(len == mChildCount, "bad child count");
    +  VerifyLastIsComplete();
    +#endif
    +#ifdef NOISY
    +  ListTag(stdout);
    +  printf(": pullup %sok (childCount=%d) [%d,%d,%c]\n",
    +         (result ? "" : "NOT "),
    +         mChildCount,
    +         mFirstContentOffset, mLastContentOffset,
    +         (mLastContentIsComplete ? 'T' : 'F'));
    +#ifdef NOISY_FLOW
    +  {
    +    nsTableRowGroupFrame* flow = (nsTableRowGroupFrame*) mNextInFlow;
    +    while (flow != 0) {
    +      printf("  %p: [%d,%d,%c]\n",
    +             flow, flow->mFirstContentOffset, flow->mLastContentOffset,
    +             (flow->mLastContentIsComplete ? 'T' : 'F'));
    +      flow = (nsTableRowGroupFrame*) flow->mNextInFlow;
    +    }
    +  }
    +#endif
    +#endif
    +  return result;
    +}
    +
    +/**
    + * Create new frames for content we haven't yet mapped
    + *
    + * @param   aPresContext presentation context to use
    + * @param   aState current inline state
    + * @return  frComplete if all content has been mapped and frNotComplete
    + *            if we should be continued
    + */
    +nsIFrame::ReflowStatus
    +nsTableRowGroupFrame::ReflowUnmappedChildren(nsIPresContext*      aPresContext,
    +                                             RowGroupReflowState& aState,
    +                                             nsSize*              aMaxElementSize)
    +{
    +#ifdef NS_DEBUG
    +  VerifyLastIsComplete();
    +#endif
    +  nsIFrame*     kidPrevInFlow = nsnull;
    +  ReflowStatus  result = frNotComplete;
    +
    +  // If we have no children and we have a prev-in-flow then we need to pick
    +  // up where it left off. If we have children, e.g. we're being resized, then
    +  // our content offset should already be set correctly...
    +  if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) {
    +    nsTableRowGroupFrame* prev = (nsTableRowGroupFrame*)mPrevInFlow;
    +    NS_ASSERTION(prev->mLastContentOffset >= prev->mFirstContentOffset, "bad prevInFlow");
    +
    +    mFirstContentOffset = prev->NextChildOffset();
    +    if (!prev->mLastContentIsComplete) {
    +      // Our prev-in-flow's last child is not complete
    +      kidPrevInFlow = prev->LastChild();
    +    }
    +  }
    +
    +  PRBool originalLastContentIsComplete = mLastContentIsComplete;
    +
    +  // Place our children, one at a time, until we are out of children
    +  nsSize    kidMaxElementSize;
    +  nsSize*   pKidMaxElementSize = (nsnull != aMaxElementSize) ? &kidMaxElementSize : nsnull;
    +  PRInt32   kidIndex = NextChildOffset();
    +  nsIFrame* prevKidFrame = LastChild();  // XXX remember this...
    +
    +  for (;;) {
    +    // Get the next content object
    +    nsIContent* kid = mContent->ChildAt(kidIndex);
    +    if (nsnull == kid) {
    +      result = frComplete;
    +      break;
    +    }
    +
    +    // Make sure we still have room left
    +    if (aState.availSize.height <= 0) {
    +      // Note: return status was set to frNotComplete above...
    +      NS_RELEASE(kid);
    +      break;
    +    }
    +
    +    // Resolve style
    +    nsIStyleContext* kidStyleContext =
    +      aPresContext->ResolveStyleContextFor(kid, this);
    +    nsStyleMolecule* kidMol =
    +      (nsStyleMolecule*)kidStyleContext->GetData(kStyleMoleculeSID);
    +    nscoord topMargin = GetTopMarginFor(aPresContext, aState, kidMol);
    +    nscoord bottomMargin = kidMol->margin.bottom;
    +
    +    //nsBlockFrame*   pseudoFrame = nsnull;
    +    nsIFrame*       kidFrame;
    +    ReflowStatus    status;
    +
    +    // Create a child frame
    +    if (nsnull == kidPrevInFlow) {
    +      nsIContentDelegate* kidDel = nsnull;
    +      kidDel = kid->GetDelegate(aPresContext);
    +      kidFrame = kidDel->CreateFrame(aPresContext, kid, kidIndex, this);
    +      NS_RELEASE(kidDel);
    +      kidFrame->SetStyleContext(kidStyleContext);
    +    } else {
    +      kidFrame = kidPrevInFlow->CreateContinuingFrame(aPresContext, this);
    +    }
    +
    +    // Link the child frame into the list of children and update the
    +    // child count
    +    if (nsnull != prevKidFrame) {
    +      NS_ASSERTION(nsnull == prevKidFrame->GetNextSibling(), "bad append");
    +      prevKidFrame->SetNextSibling(kidFrame);
    +    } else {
    +      NS_ASSERTION(nsnull == mFirstChild, "bad create");
    +      mFirstChild = kidFrame;
    +      SetFirstContentOffset(kidFrame);
    +    }
    +    mChildCount++;
    +
    +    do {
    +      nsSize  kidAvailSize(aState.availSize);
    +      nsReflowMetrics  desiredSize;
    +
    +      // Figure out the amount of available size for the child (subtract
    +      // off the margin we are going to apply to it)
    +      if (PR_FALSE == aState.unconstrainedHeight) {
    +        kidAvailSize.height -= topMargin;
    +      }
    +      // Subtract off for left and right margin
    +      if (PR_FALSE == aState.unconstrainedWidth) {
    +        kidAvailSize.width -= kidMol->margin.left + kidMol->margin.right;
    +      }
    +
    +      // Try to reflow the child into the available space. It might not
    +      // fit or might need continuing
    +      if (kidAvailSize.height > 0) {
    +        status = ReflowChild(kidFrame, aPresContext, desiredSize,
    +                             kidAvailSize, pKidMaxElementSize);
    +      }
    +
    +      // Did the child fit?
    +      if ((nsnull != mFirstChild) &&
    +          ((kidAvailSize.height <= 0) ||
    +           (desiredSize.height > kidAvailSize.height))) {
    +        // The child's height is too big to fit in our remaining
    +        // space, and it's not our first child.
    +        NS_ASSERTION(nsnull == mOverflowList, "bad overflow list");
    +        NS_ASSERTION(nsnull == mNextInFlow, "whoops");
    +
    +        // Chop off the part of our child list that's being overflowed
    +        NS_ASSERTION(prevKidFrame->GetNextSibling() == kidFrame, "bad list");
    +        prevKidFrame->SetNextSibling(nsnull);
    +
    +        // Create overflow list
    +        mOverflowList = kidFrame;
    +
    +        // Fixup child count by subtracting off the number of children
    +        // that just ended up on the reflow list.
    +        PRInt32 overflowKids = 0;
    +        nsIFrame* f = kidFrame;
    +        while (nsnull != f) {
    +          overflowKids++;
    +          f = f->GetNextSibling();
    +        }
    +        mChildCount -= overflowKids;
    +        NS_RELEASE(kidStyleContext);
    +        NS_RELEASE(kid);
    +        goto done;
    +      }
    +
    +      // Advance y by the topMargin between children. Zero out the
    +      // topMargin in case this frame is continued because
    +      // continuations do not have a top margin. Update the prev
    +      // bottom margin state in the body reflow state so that we can
    +      // apply the bottom margin when we hit the next child (or
    +      // finish).
    +      aState.y += topMargin;
    +      nsRect kidRect (0, 0, desiredSize.width, desiredSize.height);
    +      kidRect.x += kidMol->margin.left;
    +      kidRect.y += aState.y;
    +      PlaceChild(aPresContext, aState, kidFrame, kidRect, kidMol, aMaxElementSize,
    +                 kidMaxElementSize);
    +      if (bottomMargin < 0) {
    +        aState.prevMaxNegBottomMargin = -bottomMargin;
    +      } else {
    +        aState.prevMaxPosBottomMargin = bottomMargin;
    +      }
    +      topMargin = 0;
    +
    +      mLastContentIsComplete = PRBool(status == frComplete);
    +      if (frNotComplete == status) {
    +        // Child didn't complete so create a continuing frame
    +        kidPrevInFlow = kidFrame;
    +        nsIFrame* continuingFrame =
    +          kidFrame->CreateContinuingFrame(aPresContext, this);
    +
    +        // Add the continuing frame to the sibling list
    +        continuingFrame->SetNextSibling(kidFrame->GetNextSibling());
    +        kidFrame->SetNextSibling(continuingFrame);
    +        prevKidFrame = kidFrame;
    +        kidFrame = continuingFrame;
    +        mChildCount++;
    +
    +        /*
    +        if (nsnull != pseudoFrame) {
    +          pseudoFrame = (nsBlockFrame*) kidFrame;
    +        }
    +        */
    +        // XXX We probably shouldn't assume that there is no room for
    +        // the continuation
    +      }
    +    } while (frNotComplete == status);
    +    NS_RELEASE(kidStyleContext);
    +    NS_RELEASE(kid);
    +
    +    prevKidFrame = kidFrame;
    +    kidPrevInFlow = nsnull;
    +
    +    // Update the kidIndex
    +    /*
    +    if (nsnull != pseudoFrame) {
    +      // Adjust kidIndex to reflect the number of children mapped by
    +      // the pseudo frame
    +      kidIndex = pseudoFrame->NextChildOffset();
    +    } else {
    +    */
    +      kidIndex++;
    +    /*
    +    }
    +    */
    +  }
    +
    +done:
    +  // Update the content mapping
    +  NS_ASSERTION(LastChild() == prevKidFrame, "bad last child");
    +  if (0 != mChildCount) {
    +    SetLastContentOffset(prevKidFrame);
    +  }
    +#ifdef NS_DEBUG
    +  PRInt32 len = LengthOf(mFirstChild);
    +  NS_ASSERTION(len == mChildCount, "bad child count");
    +  VerifyLastIsComplete();
    +#endif
    +  return result;
    +}
    +
    +/** Layout the entire row group.
    +  * This method stacks rows vertically according to HTML 4.0 rules.
    +  * Rows are responsible for layout of their children.
    +  */
    +nsIFrame::ReflowStatus
    +nsTableRowGroupFrame::ResizeReflow( nsIPresContext*  aPresContext,
    +                                    nsReflowMetrics& aDesiredSize,
    +                                    const nsSize&    aMaxSize,
    +                                    nsSize*          aMaxElementSize)
    +{
    +  if (gsDebug1==PR_TRUE)
    +    printf("nsTableRowGroupFrame::ResizeReflow - aMaxSize = %d, %d\n",
    +            aMaxSize.width, aMaxSize.height);
    +#ifdef NS_DEBUG
    +  PreReflowCheck();
    +#endif
    +
    +  // Initialize out parameter
    +  if (nsnull != aMaxElementSize) {
    +    aMaxElementSize->width = 0;
    +    aMaxElementSize->height = 0;
    +  }
    +
    +  PRBool        reflowMappedOK = PR_TRUE;
    +  ReflowStatus  status = frComplete;
    +
    +  // Check for an overflow list
    +  MoveOverflowToChildList();
    +
    +  nsStyleMolecule* myMol =
    +    (nsStyleMolecule*)mStyleContext->GetData(kStyleMoleculeSID);
    +  RowGroupReflowState state(aPresContext, aMaxSize, myMol);
    +
    +  // Reflow the existing frames
    +  if (nsnull != mFirstChild) {
    +    reflowMappedOK = ReflowMappedChildren(aPresContext, state, aMaxElementSize);
    +    if (PR_FALSE == reflowMappedOK) {
    +      status = frNotComplete;
    +    }
    +  }
    +
    +  // Did we successfully relow our mapped children?
    +  if (PR_TRUE == reflowMappedOK) {
    +    // Any space left?
    +    if ((nsnull != mFirstChild) && (state.availSize.height <= 0)) {
    +      // No space left. Don't try to pull-up children or reflow unmapped
    +      if (NextChildOffset() < mContent->ChildCount()) {
    +        status = frNotComplete;
    +      }
    +    } else if (NextChildOffset() < mContent->ChildCount()) {
    +      // Try and pull-up some children from a next-in-flow
    +      if ((nsnull == mNextInFlow) ||
    +          PullUpChildren(aPresContext, state, aMaxElementSize)) {
    +        // If we still have unmapped children then create some new frames
    +        if (NextChildOffset() < mContent->ChildCount()) {
    +          status = ReflowUnmappedChildren(aPresContext, state, aMaxElementSize);
    +        }
    +      } else {
    +        // We were unable to pull-up all the existing frames from the
    +        // next in flow
    +        status = frNotComplete;
    +      }
    +    }
    +  }
    +
    +  if (frComplete == status) {
    +    // Don't forget to add in the bottom margin from our last child.
    +    // Only add it in if there's room for it.
    +    nscoord margin = state.prevMaxPosBottomMargin -
    +      state.prevMaxNegBottomMargin;
    +    if (state.availSize.height >= margin) {
    +      state.y += margin;
    +    }
    +  }
    +
    +  // Return our desired rect
    +  NS_ASSERTION(0 nsCSSProps.cpp
    +	cp nsCSSProps.cpp nsCSSPropIDs.h ../html/src
    +
    +nsCSSKeywords.cpp: $(GENHASH_PL) $(GENHASH_INC) CSSKeywords.txt Makefile
    +	$(GENHASH) "1,2,3,7" "" nsCSSKeywords KEYWORD_ CSSKeywords.txt nsCSSKeywordIDs.h > nsCSSKeywords.cpp
    +	cp nsCSSKeywords.cpp nsCSSKeywordIDs.h ../html/src
    +
    +nsHTMLTags.cpp: $(GENHASH_PL) $(GENHASH_INC) HTMLTags.txt Makefile
    +	$(GENHASH) "1,2,3" "-o" nsHTMLTags TAG_ HTMLTags.txt nsHTMLTagIDs.h > nsHTMLTags.cpp
    +	cp nsHTMLTags.cpp nsHTMLTagIDs.h ../html/src
    +
    +RGB = nsColorNamesRGB.cpp
    +
    +nsColorNames.cpp: $(GENHASH_PL) $(GENHASH_INC) ColorNames.txt Makefile
    +	sed -e 's/:.*//' < ColorNames.txt > cnames
    +	echo "/* Do not edit - generated by tools/Makefile */" > $(RGB)
    +	echo "#include \"nsColorNames.h\"" >> $(RGB)
    +	echo "nscolor nsColorNames::kColors[COLOR_MAX] = {" >> $(RGB)
    +	sed -e 's/.*://' -e 's/$$/,/' < ColorNames.txt >> $(RGB)
    +	echo "};" >> $(RGB)
    +	$(GENHASH) "1,2,5,6,7,9,11" "-o" nsColorNames COLOR_ cnames nsColorNameIDs.h > nsColorNames.cpp
    +	cp nsColorNames.cpp nsColorNameIDs.h nsColorNamesRGB.cpp ../gfx/src
    +	rm cnames
    diff --git a/mozilla/layout/tools/genhash.inc b/mozilla/layout/tools/genhash.inc
    new file mode 100644
    index 00000000000..338c7a55a28
    --- /dev/null
    +++ b/mozilla/layout/tools/genhash.inc
    @@ -0,0 +1,120 @@
    +@!
    +@! 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.
    +
    +@! This file is used to generate static hash table lookups.
    +@! A perl script merges this file  with the output of gperf to produce
    +@! the hash functions.  Lines starting with @! are comments.  Lines which do
    +@! not being with @! are copied straight to the output file. "@begin NAME
    +@! /REGEX1/ /REGEX2/" means to  skip lines in the input until REGEX1 is
    +@! matched, and then begin  saving output under name NAME, and stop when
    +@! REGEX2 is matched. "@include NAME" inserts the data saved as "NAME".
    +@! "@SUB NAME SUBREGEX" performs a substitution on the data saved in NAME.
    +@!
    +@! The following goop extracts the parts we need from the generated output
    +@! of gperf.  We later merge that goop with custom code to generate
    +@! the tag lookup function.
    +@!
    +@begin MACROS /#define/ /^$/
    +@begin HASH_TABLE /static unsigned [a-z]+ (asso_values|hash_table)/ /};/
    +@begin HASH_FUNC /register int hval = len;/ /return hval/
    +@sub HASH_FUNC /return hval \+/hval +=/
    +@sub HASH_FUNC /str\[/MYLOWER(str[/
    +@sub HASH_FUNC /]]/])]/
    +@begin LENGTH_TABLE /static unsigned char lengthtable/ /};/
    +@begin TAG_TABLE /static struct StaticNameTable *wordlist/ /};/
    +@!
    +
    +/*
    +** This is a generated file, do not edit it. This file is created by
    +** genhash.pl
    +*/
    +
    +#include "plhash.h"
    +@classincl
    +@include MACROS
    +
    +struct StaticNameTable {
    +  char* tag;
    +  PRInt32 id;
    +};
    +
    +static const unsigned char kLowerLookup[256] = {
    +  0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
    +  16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
    +  32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,
    +  48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,
    +  64,
    +    97,98,99,100,101,102,103,104,105,106,107,108,109,
    +    110,111,112,113,114,115,116,117,118,119,120,121,122,
    +
    +   91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
    +  112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
    +
    +  128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
    +  144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
    +  160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
    +  176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
    +  192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
    +  208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
    +  224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
    +  240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
    +};
    +
    +#define MYLOWER(x) kLowerLookup[((x) & 0x7f)]
    +
    +/**
    + * Map a name to an ID or -1
    + */
    +@classfunc
    +{
    +@include HASH_TABLE
    +@include LENGTH_TABLE
    +@include TAG_TABLE
    +
    +  if (str != NULL) {
    +    int len = PL_strlen(str);
    +    if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) {
    +@include HASH_FUNC
    +@! "hval" now contains hash value
    +      if (hval <= MAX_HASH_VALUE && hval >= MIN_HASH_VALUE) {
    +        if (len == lengthtable[hval]) {
    +          register const char *tag = wordlist[hval].tag;
    +
    +          /*
    +          ** While not at the end of the string, if they ever differ
    +          ** they are not equal.  We know "tag" is already lower case.
    +          */
    +          while ((*tag != '\0')&&(*str != '\0')) {
    +            if (*tag != (char) MYLOWER(*str)) {
    +              return -1;
    +            }
    +            tag++;
    +            str++;
    +          }
    +
    +          /*
    +          ** One of the strings has ended, if they are both ended, then they
    +          ** are equal, otherwise not.
    +          */
    +          if ((*tag == '\0')&&(*str == '\0')) {
    +            return wordlist[hval].id;
    +          }
    +        }
    +      }
    +    }
    +  }
    +  return -1;
    +}
    diff --git a/mozilla/layout/tools/genhash.pl b/mozilla/layout/tools/genhash.pl
    new file mode 100644
    index 00000000000..512bbfb24fb
    --- /dev/null
    +++ b/mozilla/layout/tools/genhash.pl
    @@ -0,0 +1,102 @@
    +#! /usr/local/bin/perl
    +
    +# 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.
    +
    +$klist = @ARGV[0];
    +$gperfopts = @ARGV[1];
    +$clazz = @ARGV[2];
    +$prefix = @ARGV[3];
    +$props = @ARGV[4];
    +$ids = @ARGV[5];
    +
    +
    +open(NAMES_FILE, "<$props");
    +open(HASH, "|/tools/ns/bin/gperf -T -t -l $gperfopts -NHashFunc -p -k$klist,\$ > gperf.out.$$");
    +
    +# NOTE: the decl here needs to match the TAG_TABLE rules in genhash.inc!!!
    +print HASH 'struct StaticNameTable { char *name; int id; };
    +%%
    +';
    +
    +open(ID_FILE, ">$ids");
    +
    +# Load in tag names
    +$nextval = 0;
    +while () {
    +  if (/(.*)/) {
    +    $prop = $1;
    +    $vals[$nextval] = $prop;
    +    $nextval = $nextval + 1;
    +  }
    +}
    +
    +# Output tag id's to ID_FILE and hash info to HASH
    +print ID_FILE "/* Do not edit - generated by $0 */\n";
    +for ($i = 0; $i < $nextval; $i++) {
    +  $val = $vals[$i];
    +  $newval = $val;
    +  $newval =~ tr/a-z/A-Z/;
    +  $newval =~ s/-/_/g;
    +  print ID_FILE "#define $prefix$newval $i\n";
    +  print HASH $vals[$i] . ", $i\n";
    +}
    +print ID_FILE "#define $prefix" . "MAX $i\n";
    +
    +close(NAMES_FILE);
    +close(HASH);
    +open(C, ") {
    +  if (/^@begin/) {
    +    ($name, $start, $end) =
    +      m#@begin[ 	]*([A-Za-z0-9_]+)[ 	]*/([^/]*)/[ 	]*/([^/]*)/#;
    +    $line =  until (eof(C) || $line =~ /$start/);
    +    if ($line =~ /$start/) {
    +      $template{$name} .= $line;
    +      do {
    +	$line = ;
    +	$template{$name} .= $line;
    +      } until ($line =~ /$end/ || eof(C));
    +    }
    +  } elsif (/^@include/) {
    +    ($name) = /@include[ 	]*(.*)$/;
    +    print $template{$name};
    +  } elsif (/^@sub/) {
    +    ($name, $old, $new) =
    +      m#@sub[ 	]*([A-Za-z0-9_]*)[ 	]/([^/]*)/([^/]*)/#;
    +    $template{$name} =~ s/$old/$new/g;
    +  } elsif (/^@classfunc/) {
    +    print "PRInt32 $clazz::LookupName(const char* str)\n";
    +  } elsif (/^@classincl/) {
    +    print "#include \"$clazz.h\"\n";
    +  } elsif (/^@/) {
    +    ;
    +  } else {
    +    print $_;
    +  }
    +}
    +
    +# Print out tag name table at the end
    +print "\nconst nsStaticNameTableEntry $clazz::kNameTable[] = {\n";
    +for ($i = 0; $i < $nextval; $i++) {
    +  $val = $vals[$i];
    +  $newval = $val;
    +  $newval =~ tr/a-z/A-Z/;
    +  print "  { \"$vals[$i]\", $i }, \n";
    +}
    +print "};\n";
    diff --git a/mozilla/parser/htmlparser/Makefile b/mozilla/parser/htmlparser/Makefile
    new file mode 100644
    index 00000000000..831fd742c9a
    --- /dev/null
    +++ b/mozilla/parser/htmlparser/Makefile
    @@ -0,0 +1,27 @@
    +#!gmake
    +#
    +# 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.
    +
    +DEPTH = ..
    +
    +# Don't try to build robot just yet
    +# DIRS = src robot
    +
    +DIRS = src
    +
    +include $(DEPTH)/config/config.mk
    +
    +include $(DEPTH)/config/rules.mk
    diff --git a/mozilla/parser/htmlparser/makefile.win b/mozilla/parser/htmlparser/makefile.win
    new file mode 100644
    index 00000000000..78a595cef67
    --- /dev/null
    +++ b/mozilla/parser/htmlparser/makefile.win
    @@ -0,0 +1,23 @@
    +#!nmake
    +#
    +# 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.
    +
    +DEPTH=..
    +IGNORE_MANIFEST=1
    +
    +DIRS = src
    +
    +include <$(DEPTH)\config\rules.mak>
    diff --git a/mozilla/parser/htmlparser/robot/Makefile b/mozilla/parser/htmlparser/robot/Makefile
    new file mode 100644
    index 00000000000..c87a607607f
    --- /dev/null
    +++ b/mozilla/parser/htmlparser/robot/Makefile
    @@ -0,0 +1,54 @@
    +#!gmake
    +#
    +# 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.
    +
    +DEPTH = ../../..
    +
    +include $(DEPTH)/config/config.mk
    +
    +CPPSRCS =			\
    +	RobotMain.cpp		\
    +	nsRobotSink.cpp		\
    +	$(NULL)
    +
    +REQUIRES=xpcom raptor
    +
    +OBJS	= $(CPPSRCS:.cpp=.o)
    +
    +EX_LIBS = \
    +	$(DIST)/lib/libraptorbase.a \
    +	$(DIST)/lib/libraptorhtmlpars.a \
    +	$(DIST)/lib/libnetlib.a \
    +	$(DIST)/lib/libpref.a	\
    +	$(DIST)/lib/libxp.a	\
    +	$(DIST)/lib/libjs.a	\
    +	$(DIST)/lib/libxpcom.a  \
    +	$(DIST)/lib/libplc21.a	\
    +	$(DIST)/lib/libplds21.a	\
    +	$(DIST)/lib/libnspr21.a	\
    +	-lXm			\
    +	-lm			\
    +	$(NULL)
    +
    +PROG = htmlrobot
    +
    +$(PROG):$(OBJS)
    +	@$(MAKE_OBJDIR)
    +	$(CCC) -o $@ $(OBJS) $(LDFLAGS) $(EX_LIBS) $(OS_LIBS)
    +
    +TARGETS = $(PROG)
    +
    +include $(DEPTH)/config/rules.mk
    diff --git a/mozilla/parser/htmlparser/robot/RobotMain.cpp b/mozilla/parser/htmlparser/robot/RobotMain.cpp
    new file mode 100644
    index 00000000000..db3237ae05e
    --- /dev/null
    +++ b/mozilla/parser/htmlparser/robot/RobotMain.cpp
    @@ -0,0 +1,111 @@
    +/* -*- 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 "nsIRobotSink.h"
    +#include "nsIRobotSinkObserver.h"
    +#include "nsIParser.h"
    +#include "nsVoidArray.h"
    +#include "nsString.h"
    +#include "nsIURL.h"
    +
    +static nsVoidArray* gWorkList;
    +
    +static NS_DEFINE_IID(kIRobotSinkObserverIID, NS_IROBOTSINKOBSERVER_IID);
    +
    +class RobotSinkObserver : public nsIRobotSinkObserver {
    +public:
    +  RobotSinkObserver() {
    +    NS_INIT_REFCNT();
    +  }
    +
    +  ~RobotSinkObserver() {
    +  }
    +
    +  NS_DECL_ISUPPORTS
    +
    +  NS_IMETHOD ProcessLink(const nsString& aURLSpec);
    +};
    +
    +NS_IMPL_ISUPPORTS(RobotSinkObserver, kIRobotSinkObserverIID);
    +
    +NS_IMETHODIMP RobotSinkObserver::ProcessLink(const nsString& aURLSpec)
    +{
    +  fputs(aURLSpec, stdout);
    +  printf("\n");
    +  return NS_OK;
    +}
    +
    +//----------------------------------------------------------------------
    +
    +int main(int argc, char **argv)
    +{
    +  gWorkList = new nsVoidArray();
    +
    +  int i;
    +  for (i = 1; i < argc; i++) {
    +    gWorkList->AppendElement(new nsString(argv[i]));
    +  }
    +
    +  RobotSinkObserver* myObserver = new RobotSinkObserver();
    +  NS_ADDREF(myObserver);
    +
    +  for (;;) {
    +    PRInt32 n = gWorkList->Count();
    +    if (0 == n) {
    +      break;
    +    }
    +    nsString* urlName = (nsString*) gWorkList->ElementAt(n - 1);
    +    gWorkList->RemoveElementAt(n - 1);
    +
    +    // Create url
    +    nsIURL* url;
    +    nsresult rv = NS_NewURL(&url, *urlName);
    +    if (NS_OK != rv) {
    +      printf("invalid URL: '");
    +      fputs(*urlName, stdout);
    +      printf("'\n");
    +      return -1;
    +    }
    +    delete urlName;
    +
    +    nsIParser* parser;
    +    rv = NS_NewHTMLParser(&parser);
    +    if (NS_OK != rv) {
    +      printf("can't make parser\n");
    +      return -1;
    +    }
    +
    +    nsIRobotSink* sink;
    +    rv = NS_NewRobotSink(&sink);
    +    if (NS_OK != rv) {
    +      printf("can't make parser\n");
    +      return -1;
    +    }
    +    sink->Init(url);
    +    sink->AddObserver(myObserver);
    +
    +    parser->SetContentSink(sink);
    +    parser->Parse(url);
    +    NS_RELEASE(sink);
    +    NS_RELEASE(parser);
    +    NS_RELEASE(url);
    +  }
    +
    +  NS_RELEASE(myObserver);
    +
    +  return 0;
    +}
    diff --git a/mozilla/parser/htmlparser/robot/makefile.win b/mozilla/parser/htmlparser/robot/makefile.win
    new file mode 100644
    index 00000000000..c64ca35aaf8
    --- /dev/null
    +++ b/mozilla/parser/htmlparser/robot/makefile.win
    @@ -0,0 +1,62 @@
    +#!nmake
    +#
    +# 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.
    +
    +DEPTH=..\..\.. 
    +IGNORE_MANIFEST=1
    +
    +MAKE_OBJ_TYPE   = EXE
    +PROGRAM = .\$(OBJDIR)\htmlrobot.exe
    +
    +MISCDEP=			\
    + $(DIST)\lib\raptorhtmlpars.lib	\
    + $(DIST)\lib\xpcom32.lib	\
    + $(LIBNSPR)			\
    + $(DIST)\lib\libplc21.lib	\
    + $(NULL)
    +
    +MYLIBS=				\
    + $(DIST)\lib\raptorhtmlpars.lib	\
    + $(DIST)\lib\raptorbase.lib	\
    + $(DIST)\lib\xpcom32.lib	\
    + $(LIBNSPR)			\
    + $(DIST)\lib\libplc21.lib	\
    + $(NULL)
    +
    +LLIBS= $(MYLIBS)                \
    + shell32.lib                    \
    + -SUBSYSTEM:CONSOLE
    +
    +DEFINES=-D_IMPL_NS_HTMLPARS 
    +
    +CPPSRCS=			\
    + nsRobotSink.cpp		\
    + RobotMain.cpp			\
    + $(NULL)
    +
    +CPP_OBJS=			\
    + .\$(OBJDIR)\nsRobotSink.obj	\
    + .\$(OBJDIR)\RobotMain.obj
    +
    +LINCS=-I$(XPDIST)\public\xpcom -I$(XPDIST)\public\raptor  -I..\src
    +
    +include <$(DEPTH)\config\rules.mak>
    +
    +install:: $(PROGRAM)
    +	$(MAKE_INSTALL) $(PROGRAM) $(DIST)\bin
    +
    +clobber::
    +	rm -f $(DIST)\bin\htmlrobot.exe
    diff --git a/mozilla/parser/htmlparser/robot/nsIRobotSink.h b/mozilla/parser/htmlparser/robot/nsIRobotSink.h
    new file mode 100644
    index 00000000000..0b53655ef08
    --- /dev/null
    +++ b/mozilla/parser/htmlparser/robot/nsIRobotSink.h
    @@ -0,0 +1,39 @@
    +/* -*- 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.
    + */
    +#ifndef nsIRobotSink_h___
    +#define nsIRobotSink_h___
    +
    +#include "nsIHTMLContentSink.h"
    +class nsIURL;
    +class nsIRobotSinkObserver;
    +
    +/* 61256800-cfd8-11d1-9328-00805f8add32 */
    +#define NS_IROBOTSINK_IID     \
    +{ 0x61256800, 0xcfd8, 0x11d1, \
    +  {0x93, 0x28, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} }
    +
    +class nsIRobotSink : public nsIHTMLContentSink {
    +public:
    +  NS_IMETHOD Init(nsIURL* aDocumentURL) = 0;
    +  NS_IMETHOD AddObserver(nsIRobotSinkObserver* aObserver) = 0;
    +  NS_IMETHOD RemoveObserver(nsIRobotSinkObserver* aObserver) = 0;
    +};
    +
    +extern nsresult NS_NewRobotSink(nsIRobotSink** aInstancePtrResult);
    +
    +#endif /* nsIRobotSink_h___ */
    diff --git a/mozilla/parser/htmlparser/robot/nsIRobotSinkObserver.h b/mozilla/parser/htmlparser/robot/nsIRobotSinkObserver.h
    new file mode 100644
    index 00000000000..da30b85edd6
    --- /dev/null
    +++ b/mozilla/parser/htmlparser/robot/nsIRobotSinkObserver.h
    @@ -0,0 +1,34 @@
    +/* -*- 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.
    + */
    +#ifndef nsIRobotSinkObserver_h___
    +#define nsIRobotSinkObserver_h___
    +
    +#include "nsISupports.h"
    +class nsString;
    +
    +/* fab1d970-cfda-11d1-9328-00805f8add32 */
    +#define NS_IROBOTSINKOBSERVER_IID \
    +{ 0xfab1d970, 0xcfda, 0x11d1,	  \
    +  {0x93, 0x28, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} }
    +
    +class nsIRobotSinkObserver : public nsISupports {
    +public:
    +  NS_IMETHOD ProcessLink(const nsString& aURLSpec) = 0;
    +};
    +
    +#endif /* nsIRobotSinkObserver_h___ */
    diff --git a/mozilla/parser/htmlparser/robot/nsRobotSink.cpp b/mozilla/parser/htmlparser/robot/nsRobotSink.cpp
    new file mode 100644
    index 00000000000..e346c3d9bc0
    --- /dev/null
    +++ b/mozilla/parser/htmlparser/robot/nsRobotSink.cpp
    @@ -0,0 +1,285 @@
    +/* -*- 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 "nsIRobotSink.h"
    +#include "nsIRobotSinkObserver.h"
    +#include "nsIParserNode.h"
    +#include "nsString.h"
    +#include "nsIURL.h"
    +#include "nsCRT.h"
    +#include "nsVoidArray.h"
    +class nsIDocument;
    +
    +// TODO
    +// - add in base tag support
    +// - get links from other sources:
    +//      - LINK tag
    +//      - STYLE SRC
    +//      - IMG SRC
    +//      - LAYER SRC
    +
    +static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
    +static NS_DEFINE_IID(kIHTMLContentSinkIID, NS_IHTMLCONTENTSINK_IID);
    +static NS_DEFINE_IID(kIRobotSinkIID, NS_IROBOTSINK_IID);
    +
    +class RobotSink : public nsIRobotSink {
    +public:
    +  RobotSink();
    +  ~RobotSink();
    +
    +  void* operator new(size_t size) {
    +    void* rv = ::operator new(size);
    +    nsCRT::zero(rv, size);
    +    return (void*) rv;
    +  }
    +
    +  // nsISupports
    +  NS_DECL_ISUPPORTS
    +
    +  // nsIHTMLContentSink
    +  virtual PRBool SetTitle(const nsString& aValue);
    +  virtual PRBool OpenHTML(const nsIParserNode& aNode);
    +  virtual PRBool CloseHTML(const nsIParserNode& aNode);
    +  virtual PRBool OpenHead(const nsIParserNode& aNode);
    +  virtual PRBool CloseHead(const nsIParserNode& aNode);
    +  virtual PRBool OpenBody(const nsIParserNode& aNode);
    +  virtual PRBool CloseBody(const nsIParserNode& aNode);
    +  virtual PRBool OpenForm(const nsIParserNode& aNode);
    +  virtual PRBool CloseForm(const nsIParserNode& aNode);
    +  virtual PRBool OpenFrameset(const nsIParserNode& aNode);
    +  virtual PRBool CloseFrameset(const nsIParserNode& aNode);
    +  virtual PRBool OpenContainer(const nsIParserNode& aNode);
    +  virtual PRBool CloseContainer(const nsIParserNode& aNode);
    +  virtual PRBool CloseTopmostContainer();
    +  virtual PRBool AddLeaf(const nsIParserNode& aNode);
    +
    +  // nsIRobotSink
    +  NS_IMETHOD Init(nsIURL* aDocumentURL);
    +  NS_IMETHOD AddObserver(nsIRobotSinkObserver* aObserver);
    +  NS_IMETHOD RemoveObserver(nsIRobotSinkObserver* aObserver);
    +
    +  void ProcessLink(const nsString& aLink);
    +
    +protected:
    +  nsIURL* mDocumentURL;
    +  nsVoidArray mObservers;
    +};
    +
    +nsresult NS_NewRobotSink(nsIRobotSink** aInstancePtrResult)
    +{
    +  RobotSink* it = new RobotSink();
    +  return it->QueryInterface(kIRobotSinkIID, (void**) aInstancePtrResult);
    +}
    +
    +RobotSink::RobotSink()
    +{
    +}
    +
    +RobotSink::~RobotSink()
    +{
    +  NS_IF_RELEASE(mDocumentURL);
    +  PRInt32 i, n = mObservers.Count();
    +  for (i = 0; i < n; i++) {
    +    nsIRobotSinkObserver* cop = (nsIRobotSinkObserver*)mObservers.ElementAt(i);
    +    NS_RELEASE(cop);
    +  }
    +}  
    +
    +NS_IMPL_ADDREF(RobotSink);
    +
    +NS_IMPL_RELEASE(RobotSink);
    +
    +NS_IMETHODIMP RobotSink::QueryInterface(REFNSIID aIID, void** aInstancePtr)
    +{
    +  if (NULL == aInstancePtr) {
    +    return NS_ERROR_NULL_POINTER;
    +  }
    +  if (aIID.Equals(kIRobotSinkIID)) {
    +    *aInstancePtr = (void*) this;
    +    AddRef();
    +    return NS_OK;
    +  }
    +  if (aIID.Equals(kIHTMLContentSinkIID)) {
    +    *aInstancePtr = (void*) this;
    +    AddRef();
    +    return NS_OK;
    +  }
    +  if (aIID.Equals(kISupportsIID)) {
    +    *aInstancePtr = (void*) ((nsISupports*)this);
    +    AddRef();
    +    return NS_OK;
    +  }
    +  return NS_NOINTERFACE;
    +}
    +
    +PRBool RobotSink::SetTitle(const nsString& aValue)
    +{
    +  return PR_TRUE;
    +}
    +
    +PRBool RobotSink::OpenHTML(const nsIParserNode& aNode)
    +{
    +  return PR_TRUE;
    +}
    +
    +PRBool RobotSink::CloseHTML(const nsIParserNode& aNode)
    +{
    +  return PR_TRUE;
    +}
    +
    +PRBool RobotSink::OpenHead(const nsIParserNode& aNode)
    +{
    +  return PR_TRUE;
    +}
    +
    +PRBool RobotSink::CloseHead(const nsIParserNode& aNode)
    +{
    +  return PR_TRUE;
    +}
    +
    +PRBool RobotSink::OpenBody(const nsIParserNode& aNode)
    +{
    +  return PR_TRUE;
    +}
    +
    +PRBool RobotSink::CloseBody(const nsIParserNode& aNode)
    +{
    +  return PR_TRUE;
    +}
    +
    +PRBool RobotSink::OpenForm(const nsIParserNode& aNode)
    +{
    +  return PR_TRUE;
    +}
    +
    +PRBool RobotSink::CloseForm(const nsIParserNode& aNode)
    +{
    +  return PR_TRUE;
    +}
    +
    +PRBool RobotSink::OpenFrameset(const nsIParserNode& aNode)
    +{
    +  return PR_TRUE;
    +}
    +
    +PRBool RobotSink::CloseFrameset(const nsIParserNode& aNode)
    +{
    +  return PR_TRUE;
    +}
    +
    +PRBool RobotSink::OpenContainer(const nsIParserNode& aNode)
    +{
    +  nsAutoString tmp(aNode.GetText());
    +  tmp.ToUpperCase();
    +  if (tmp.Equals("A")) {
    +    nsAutoString k, v;
    +    PRInt32 ac = aNode.GetAttributeCount();
    +    for (PRInt32 i = 0; i < ac; i++) {
    +      // Get upper-cased key
    +      const nsString& key = aNode.GetKeyAt(i);
    +      k.Truncate();
    +      k.Append(key);
    +      k.ToUpperCase();
    +      if (k.Equals("HREF")) {
    +        // Get value and remove mandatory quotes
    +        v.Truncate();
    +        v.Append(aNode.GetValueAt(i));
    +        PRUnichar first = v.First();
    +        if ((first == '"') || (first == '\'')) {
    +          if (v.Last() == first) {
    +            v.Cut(0, 1);
    +            PRInt32 pos = v.Length() - 1;
    +            if (pos >= 0) {
    +              v.Cut(pos, 1);
    +            }
    +          } else {
    +            // Mismatched quotes - leave them in
    +          }
    +        }
    +        ProcessLink(v);
    +      }
    +    }
    +  }
    +  return PR_TRUE;
    +}
    +
    +PRBool RobotSink::CloseContainer(const nsIParserNode& aNode)
    +{
    +  return PR_TRUE;
    +}
    +
    +PRBool RobotSink::CloseTopmostContainer()
    +{
    +  return PR_TRUE;
    +}
    +
    +PRBool RobotSink::AddLeaf(const nsIParserNode& aNode)
    +{
    +  return PR_TRUE;
    +}
    +
    +NS_IMETHODIMP RobotSink::Init(nsIURL* aDocumentURL)
    +{
    +  NS_IF_RELEASE(mDocumentURL);
    +  mDocumentURL = aDocumentURL;
    +  NS_IF_ADDREF(aDocumentURL);
    +  return NS_OK;
    +}
    +
    +NS_IMETHODIMP RobotSink::AddObserver(nsIRobotSinkObserver* aObserver)
    +{
    +  if (mObservers.AppendElement(aObserver)) {
    +    NS_ADDREF(aObserver);
    +    return NS_OK;
    +  }
    +  return NS_ERROR_OUT_OF_MEMORY;
    +}
    +
    +NS_IMETHODIMP RobotSink::RemoveObserver(nsIRobotSinkObserver* aObserver)
    +{
    +  if (mObservers.RemoveElement(aObserver)) {
    +    NS_RELEASE(aObserver);
    +    return NS_OK;
    +  }
    +  //XXX return NS_ERROR_NOT_FOUND;
    +  return NS_OK;
    +}
    +
    +void RobotSink::ProcessLink(const nsString& aLink)
    +{
    +  nsAutoString absURLSpec(aLink);
    +
    +  // Make link absolute
    +  // XXX base tag handling
    +  nsIURL* docURL = mDocumentURL;
    +  if (nsnull != docURL) {
    +    nsIURL* absurl;
    +    nsresult rv = NS_NewURL(&absurl, docURL, aLink);
    +    if (NS_OK == rv) {
    +      absURLSpec.Truncate();
    +      absurl->ToString(absURLSpec);
    +      NS_RELEASE(absurl);
    +    }
    +  }
    +
    +  // Now give link to robot observers
    +  PRInt32 i, n = mObservers.Count();
    +  for (i = 0; i < n; i++) {
    +    nsIRobotSinkObserver* cop = (nsIRobotSinkObserver*)mObservers.ElementAt(i);
    +    cop->ProcessLink(absURLSpec);
    +  }
    +}
    diff --git a/mozilla/parser/htmlparser/src/Makefile b/mozilla/parser/htmlparser/src/Makefile
    new file mode 100644
    index 00000000000..bc43cfbe641
    --- /dev/null
    +++ b/mozilla/parser/htmlparser/src/Makefile
    @@ -0,0 +1,54 @@
    +#!gmake
    +#
    +# 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.
    +
    +DEPTH = ../..
    +
    +LIBRARY_NAME = raptorhtmlpars
    +
    +DEFINES = -D_IMPL_NS_HTMLPARS
    +
    +CPPSRCS =			\
    +	nsDeque.cpp		\
    +	nsHTMLContentSink.cpp	\
    +	nsHTMLDelegate.cpp	\
    +	nsHTMLParser.cpp	\
    +	nsHTMLTokens.cpp	\
    +	nsParserNode.cpp	\
    +	nsScanner.cpp		\
    +	nsToken.cpp		\
    +	nsTokenizer.cpp		\
    +	nsDefaultTokenHandler.cpp \
    +	nsHTMLDTD.cpp \
    +	$(NULL)
    +
    +EXPORTS =			\
    +	nshtmlpars.h		\
    +	nsIContentSink.h	\
    +	nsIHTMLContentSink.h	\
    +	nsHTMLTokens.h		\
    +	nsIParserNode.h		\
    +	nsIParser.h		\
    +	nsToken.h		\
    +	$(NULL)
    +
    +MODULE = raptor
    +
    +REQUIRES = xpcom raptor
    +
    +include $(DEPTH)/config/config.mk
    +
    +include $(DEPTH)/config/rules.mk
    diff --git a/mozilla/parser/htmlparser/src/SelfTest.cpp b/mozilla/parser/htmlparser/src/SelfTest.cpp
    new file mode 100644
    index 00000000000..d0c5bcb47ae
    --- /dev/null
    +++ b/mozilla/parser/htmlparser/src/SelfTest.cpp
    @@ -0,0 +1,188 @@
    +/* -*- 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.
    + */
    +
    +
    +//Testing stream crap...
    +
    +#include 
    +#include 
    +#include 
    +
    +#include "nsISupports.h"
    +#include "nsTokenizer.h"
    +#include "nsHTMLDelegate.h"
    +#include "nsIParser.h"
    +#include "nsHTMLContentSink.h"
    +
    +ofstream filelist("filelist.out");
    +
    +PRBool compareFiles(const char* file1,const char* file2,int& failpos) {
    +  PRBool result=PR_TRUE;
    +  PRBool done=PR_FALSE;
    +  char ch1,ch2;
    +  int  eof1,eof2;
    +
    +  ifstream	input1(file1,ios::in && ios::binary,filebuf::openprot);
    +  ifstream	input2(file2,ios::in && ios::binary,filebuf::openprot);
    +  input1.setmode(filebuf::binary);
    +  input2.setmode(filebuf::binary);
    +  failpos=-1;
    +
    +  while(!done) {
    +
    +    while(!(eof1=input1.eof())) {
    +      input1.read(&ch1,1);
    +      if(failpos>4225) {
    +        int x=failpos;
    +      }
    +      failpos++;
    +      char* p=strchr(" \t\r\n\b",ch1);
    +      if(!p)
    +        break;
    +    }
    +
    +    while(!(eof2=input2.eof())) {
    +      input2.read(&ch2,1);
    +      char* p=strchr(" \t\r\n\b",ch2);
    +      if(!p)
    +        break;
    +    }
    +    
    +    if(eof1==eof2) {
    +      if(eof1) 
    +        done=PR_TRUE;
    +      else if(ch1!=ch2) {
    +        done=PR_TRUE;
    +        result=PR_FALSE;
    +        
    +      }
    +    }
    +    else done=PR_TRUE;
    +  }
    +  return result;
    +}
    +
    +
    +/**-------------------------------------------------------
    + * LAST MODS:	gess
    + *  
    + * @param  
    + * @return 
    + *------------------------------------------------------*/
    +void parseFile (const char* aFilename,int size)
    +{
    +  //debug
    +  //aFilename="s:\\ns\\raptor\\parser\\tests\\html\\home01.html";
    +  //aFilename="c:\\temp\\sun\\test00000.html";
    +  //aFilename="c:\\windows\\temp\\test.html";
    +  aFilename="s:\\readHTML-VC\\test.html";
    +  //aFilename="c:\\temp\\sun\\commentbug.html";
    +
    +
    +  char filename[_MAX_PATH];
    +  strcpy(filename,aFilename);
    +  strcat(filename,".tokens");
    +  {
    +    nsIParser* parser;
    +    nsresult rv = NS_NewHTMLParser(&parser);
    +    nsresult r=NS_NewHTMLParser(&parser);
    +    CHTMLContentSink theSink;
    +    parser->setContentSink(&theSink);
    +    parser->parse(aFilename);
    +    parser->Release();
    +  }
    +
    +  int failpos=0;
    +
    +  if(!compareFiles(aFilename,filename,failpos)) {
    +    filelist << "FAILED: " << aFilename << "[" << failpos << "]" << endl;
    +  }
    +}
    +
    +
    +/**-------------------------------------------------------
    + * LAST MODS:	gess
    + *  
    + * @param  
    + * @return 
    + *------------------------------------------------------*/
    +int walkDirectoryTree(char* aPath) {
    +  int     result=0;
    +  char    fullPath[_MAX_PATH];
    +  struct  _finddata_t c_file;    
    +  long    hFile;
    +
    +  strcpy(fullPath,aPath);
    +  strcat(fullPath,"\\*.*");
    +  /* Find first .c file in current directory */
    +  if((hFile = _findfirst( fullPath, &c_file )) == -1L )
    +     printf( "No matching files in current directory!\n" );   
    +  else {
    +
    +    PRBool done=PR_FALSE;
    +    while(!done) {
    +      if(c_file.attrib & _A_SUBDIR) {
    +        if(strlen(c_file.name)>2){
    +          char newPath[_MAX_PATH];
    +          strcpy(newPath,aPath);
    +          strcat(newPath,"\\");
    +          strcat(newPath,c_file.name);
    +          walkDirectoryTree(newPath);
    +        }
    +      }
    +      else {
    +        int len=strlen(c_file.name);
    +        if(len>5) {
    +          if(0==strnicmp(&c_file.name[len-5],".HTML",5)) {
    +            char filepath[_MAX_PATH];            
    +            strcpy(filepath,aPath);
    +            strcat(filepath,"\\");
    +            strcat(filepath,c_file.name);
    +            parseFile(filepath,c_file.size);
    +          }
    +        }
    +      }
    +      if(_findnext( hFile, &c_file )!=0) 
    +        done=PR_TRUE;
    +    }       
    +    _findclose( hFile );   
    +  }
    +  return 0;
    +}
    +
    +
    +/**-------------------------------------------------------
    + * LAST MODS:	gess
    + *  
    + * @param  
    + * @return 
    + *------------------------------------------------------*/
    +int main(int argc, char* argv [])
    +{
    +  int   result=0;
    +  char 	buffer[_MAX_PATH];
    +
    +  if(argc==2) 
    +    strcpy(buffer,argv[1]);
    +  else _getcwd(buffer,_MAX_PATH);
    +  walkDirectoryTree(buffer);
    +  return 0;
    +}
    +
    +
    +
    diff --git a/mozilla/parser/htmlparser/src/makefile.win b/mozilla/parser/htmlparser/src/makefile.win
    new file mode 100644
    index 00000000000..9b7637349c6
    --- /dev/null
    +++ b/mozilla/parser/htmlparser/src/makefile.win
    @@ -0,0 +1,66 @@
    +#!nmake
    +#
    +# 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.
    +
    +DEPTH=..\..
    +IGNORE_MANIFEST=1
    +
    +LIBRARY_NAME=raptorhtmlpars 
    +DEFINES=-D_IMPL_NS_HTMLPARS 
    +MODULE=raptor 
    +REQUIRES=xpcom raptor 
    +
    +CPPSRCS=nsDeque.cpp nsHTMLContentSink.cpp nsHTMLDelegate.cpp nsHTMLDTD.cpp \
    +    nsHTMLParser.cpp nsHTMLTokens.cpp nsParserNode.cpp nsScanner.cpp \
    +    nsToken.cpp nsTokenizer.cpp nsDefaultTokenHandler.cpp 
    +
    +EXPORTS=nshtmlpars.h nsIContentSink.h nsIHTMLContentSink.h \
    +    nsHTMLTokens.h nsIParserNode.h nsIParser.h nsToken.h 
    +
    +CPP_OBJS=.\$(OBJDIR)\nsDeque.obj .\$(OBJDIR)\nsHTMLContentSink.obj \
    +    .\$(OBJDIR)\nsHTMLDelegate.obj .\$(OBJDIR)\nsHTMLParser.obj \
    +    .\$(OBJDIR)\nsHTMLDTD.obj \
    +    .\$(OBJDIR)\nsHTMLTokens.obj .\$(OBJDIR)\nsParserNode.obj \
    +    .\$(OBJDIR)\nsScanner.obj .\$(OBJDIR)\nsToken.obj \
    +    .\$(OBJDIR)\nsTokenizer.obj .\$(OBJDIR)\nsDefaultTokenHandler.obj 
    +
    +LINCS=-I$(XPDIST)\public\xpcom -I$(XPDIST)\public\raptor 
    +
    +MAKE_OBJ_TYPE = DLL
    +DLLNAME = raptorhtmlpars
    +DLL=.\$(OBJDIR)\$(DLLNAME).dll
    +
    +LCFLAGS = \
    +        $(LCFLAGS) \
    +        $(DEFINES) \
    +        $(NULL)
    +
    +# These are the libraries we need to link with to create the dll
    +LLIBS=				\
    + $(DIST)\lib\xpcom32.lib	\
    + $(DIST)\lib\raptorbase.lib	\
    + $(DIST)\lib\libplc21.lib       \
    + $(LIBNSPR)  
    +
    +include <$(DEPTH)\config\rules.mak>
    +
    +libs:: $(DLL)
    +	$(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).dll $(DIST)\bin
    +	$(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).lib $(DIST)\lib
    +
    +clobber::
    +	rm -f $(DIST)\bin\$(DLLNAME).dll
    +	rm -f $(DIST)\lib\$(DLLNAME).lib
    diff --git a/mozilla/parser/htmlparser/src/nsDefaultTokenHandler.cpp b/mozilla/parser/htmlparser/src/nsDefaultTokenHandler.cpp
    new file mode 100644
    index 00000000000..c4460ea1f33
    --- /dev/null
    +++ b/mozilla/parser/htmlparser/src/nsDefaultTokenHandler.cpp
    @@ -0,0 +1,637 @@
    +/* -*- 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.
    + */
    +
    +
    +/**
    + * MODULE NOTES:
    + * @update  gess 4/1/98
    + * 
    + */
    +
    +
    +#include "nsDefaultTokenHandler.h"
    +#include "nsHTMLParser.h"
    +#include "nsHTMLTokens.h"
    +#include "nsDebug.h"
    +
    +static const char* kNullParserGiven = "Error: Null parser given as argument";
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +CDefaultTokenHandler::CDefaultTokenHandler(eHTMLTokenTypes aType) {
    +  mType=aType;
    +}
    +
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +CDefaultTokenHandler::~CDefaultTokenHandler(){
    +}
    +
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +eHTMLTokenTypes CDefaultTokenHandler::GetTokenType(void){
    +  return mType;
    +}
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool CDefaultTokenHandler::CanHandle(eHTMLTokenTypes aType){
    +  PRBool result=PR_FALSE;
    +  return result;
    +}
    +
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool CDefaultTokenHandler::operator()(CToken* aToken,nsHTMLParser* aParser){
    +  NS_ASSERTION(0!=aParser,kNullParserGiven);
    +  PRBool result=PR_FALSE;
    +  if(aParser){
    +    result=PR_TRUE;
    +  }
    +  return result;
    +}
    +
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +CStartTokenHandler::CStartTokenHandler() : CDefaultTokenHandler(eToken_start) {
    +}
    +
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +CStartTokenHandler::~CStartTokenHandler(){
    +}
    +		                      
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool CStartTokenHandler::operator()(CToken* aToken,nsHTMLParser* aParser){
    +  NS_ASSERTION(0!=aParser,kNullParserGiven);
    +  if(aParser){
    +    return aParser->HandleStartToken(aToken);
    +  }
    +  return PR_FALSE;
    +}
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool CStartTokenHandler::CanHandle(eHTMLTokenTypes aType){
    +  PRBool result=PR_FALSE;
    +  return result;
    +}
    +
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +CEndTokenHandler::CEndTokenHandler(): CDefaultTokenHandler(eToken_end) {
    +}
    +
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +CEndTokenHandler::~CEndTokenHandler(){
    +}
    +		                      
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool CEndTokenHandler::operator()(CToken* aToken,nsHTMLParser* aParser){
    +  NS_ASSERTION(0!=aParser,kNullParserGiven);
    +  if(aParser){
    +    return aParser->HandleEndToken(aToken);
    +  }
    +  return PR_FALSE;
    +}
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool CEndTokenHandler::CanHandle(eHTMLTokenTypes aType){
    +  PRBool result=PR_FALSE;
    +  return result;
    +}
    +
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +CCommentTokenHandler::CCommentTokenHandler() : CDefaultTokenHandler(eToken_comment) {
    +}
    +
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +CCommentTokenHandler::~CCommentTokenHandler(){
    +}
    +		                      
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool CCommentTokenHandler::operator()(CToken* aToken,nsHTMLParser* aParser){
    +  NS_ASSERTION(0!=aParser,kNullParserGiven);
    +  if(aParser){
    +    return aParser->HandleCommentToken(aToken);
    +  }
    +  return PR_FALSE;
    +}
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool CCommentTokenHandler::CanHandle(eHTMLTokenTypes aType){
    +  PRBool result=PR_FALSE;
    +  return result;
    +}
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +CEntityTokenHandler::CEntityTokenHandler() : CDefaultTokenHandler(eToken_entity) {
    +}
    +
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +CEntityTokenHandler::~CEntityTokenHandler() {
    +}
    +		                      
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool CEntityTokenHandler::operator()(CToken* aToken,nsHTMLParser* aParser){
    +  NS_ASSERTION(0!=aParser,kNullParserGiven);
    +  if(aParser){
    +    return aParser->HandleEntityToken(aToken);
    +  }
    +  return PR_FALSE;
    +}
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool CEntityTokenHandler::CanHandle(eHTMLTokenTypes aType){
    +  PRBool result=PR_FALSE;
    +  return result;
    +}
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +CWhitespaceTokenHandler::CWhitespaceTokenHandler() : CDefaultTokenHandler(eToken_whitespace) {
    +}
    +
    +  
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +CWhitespaceTokenHandler::~CWhitespaceTokenHandler(){
    +}
    +		                      
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool CWhitespaceTokenHandler::operator()(CToken* aToken,nsHTMLParser* aParser){
    +  NS_ASSERTION(0!=aParser,kNullParserGiven);
    +  if(aParser){
    +    return aParser->HandleWhitespaceToken(aToken);
    +  }
    +  return PR_FALSE;
    +}
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool CWhitespaceTokenHandler::CanHandle(eHTMLTokenTypes aType){
    +  PRBool result=PR_FALSE;
    +  return result;
    +}
    +
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +CNewlineTokenHandler::CNewlineTokenHandler() : CDefaultTokenHandler(eToken_newline) {
    +}
    +
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +CNewlineTokenHandler::~CNewlineTokenHandler(){
    +}
    +		                      
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool CNewlineTokenHandler::operator()(CToken* aToken,nsHTMLParser* aParser){
    +  NS_ASSERTION(0!=aParser,kNullParserGiven);
    +  if(aParser){
    +    return aParser->HandleNewlineToken(aToken);
    +  }
    +  return PR_FALSE;
    +}
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool CNewlineTokenHandler::CanHandle(eHTMLTokenTypes aType){
    +  PRBool result=PR_FALSE;
    +  return result;
    +}
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +CTextTokenHandler::CTextTokenHandler() : CDefaultTokenHandler(eToken_text) {
    +}
    +
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +CTextTokenHandler::~CTextTokenHandler(){
    +}
    +		                      
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool CTextTokenHandler::operator()(CToken* aToken,nsHTMLParser* aParser){
    +  NS_ASSERTION(0!=aParser,kNullParserGiven);
    +  if(aParser){
    +    return aParser->HandleTextToken(aToken);
    +  }
    +  return PR_FALSE;
    +}
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool CTextTokenHandler::CanHandle(eHTMLTokenTypes aType){
    +  PRBool result=PR_FALSE;
    +  return result;
    +}
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +CAttributeTokenHandler::CAttributeTokenHandler() : CDefaultTokenHandler(eToken_attribute) {
    +}
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +CAttributeTokenHandler::~CAttributeTokenHandler(){
    +}
    +		                      
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool CAttributeTokenHandler::operator()(CToken* aToken,nsHTMLParser* aParser){
    +  NS_ASSERTION(0!=aParser,kNullParserGiven);
    +  if(aParser){
    +    return aParser->HandleAttributeToken(aToken);
    +  }
    +  return PR_FALSE;
    +}
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool CAttributeTokenHandler::CanHandle(eHTMLTokenTypes aType){
    +  PRBool result=PR_FALSE;
    +  return result;
    +}
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +CScriptTokenHandler::CScriptTokenHandler() : CDefaultTokenHandler(eToken_script) {
    +}
    +
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +CScriptTokenHandler::~CScriptTokenHandler(){
    +}
    +		                      
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool CScriptTokenHandler::operator()(CToken* aToken,nsHTMLParser* aParser){
    +  NS_ASSERTION(0!=aParser,kNullParserGiven);
    +  if(aParser){
    +    return aParser->HandleScriptToken(aToken);
    +  }
    +  return PR_FALSE;
    +}
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool CScriptTokenHandler::CanHandle(eHTMLTokenTypes aType){
    +  PRBool result=PR_FALSE;
    +  return result;
    +}
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +CStyleTokenHandler::CStyleTokenHandler() : CDefaultTokenHandler(eToken_style) {
    +}
    +
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +CStyleTokenHandler::~CStyleTokenHandler(){
    +}
    +		                      
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool CStyleTokenHandler::operator()(CToken* aToken,nsHTMLParser* aParser){
    +  NS_ASSERTION(0!=aParser,kNullParserGiven);
    +  if(aParser){
    +    return aParser->HandleStyleToken(aToken);
    +  }
    +  return PR_FALSE;
    +}
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool CStyleTokenHandler::CanHandle(eHTMLTokenTypes aType){
    +  PRBool result=PR_FALSE;
    +  return result;
    +}
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +CSkippedContentTokenHandler::CSkippedContentTokenHandler() : CDefaultTokenHandler(eToken_skippedcontent) {
    +}
    +
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +CSkippedContentTokenHandler::~CSkippedContentTokenHandler(){
    +}
    +		                      
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool CSkippedContentTokenHandler::operator()(CToken* aToken,nsHTMLParser* aParser){
    +  NS_ASSERTION(0!=aParser,kNullParserGiven);
    +  if(aParser){
    +    return aParser->HandleSkippedContentToken(aToken);
    +  }
    +  return PR_FALSE;
    +}
    +
    +/**-------------------------------------------------------
    + *  
    + *  
    + *  @update  gess 4/2/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool CSkippedContentTokenHandler::CanHandle(eHTMLTokenTypes aType){
    +  PRBool result=PR_FALSE;
    +  return result;
    +}
    diff --git a/mozilla/parser/htmlparser/src/nsDefaultTokenHandler.h b/mozilla/parser/htmlparser/src/nsDefaultTokenHandler.h
    new file mode 100644
    index 00000000000..71dc3a267d1
    --- /dev/null
    +++ b/mozilla/parser/htmlparser/src/nsDefaultTokenHandler.h
    @@ -0,0 +1,161 @@
    +/* -*- 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.
    + */
    +
    +/**
    + * MODULE NOTES:
    + * @update  gess 4/1/98
    + * 
    + */
    +
    +#ifndef CDEFAULTTOKENHANDLER__
    +#define CDEFAULTTOKENHANDLER__
    +
    +#include "prtypes.h"
    +#include "nsString.h"
    +#include "nsHTMLTokens.h"
    +#include "nsITokenHandler.h"
    +
    +class CToken;
    +class nsHTMLParser;
    +
    +
    +class CDefaultTokenHandler : public CITokenHandler {
    +public:
    +									        CDefaultTokenHandler(eHTMLTokenTypes aType=eToken_unknown);
    +  virtual                 ~CDefaultTokenHandler();
    +		                      
    +  virtual   eHTMLTokenTypes GetTokenType(void);
    +  virtual   PRBool        operator()(CToken* aToken,nsHTMLParser* aParser);
    +  virtual   PRBool        CanHandle(eHTMLTokenTypes aType);
    +
    +protected:
    +          	eHTMLTokenTypes mType;
    +};
    +
    +
    +class CStartTokenHandler : public CDefaultTokenHandler  {
    +public:
    +									        CStartTokenHandler();
    +  virtual                 ~CStartTokenHandler();
    +		                      
    +  virtual   PRBool        operator()(CToken* aToken,nsHTMLParser* aParser);
    +  virtual   PRBool        CanHandle(eHTMLTokenTypes aType);
    +};
    +
    +
    +class CEndTokenHandler : public CDefaultTokenHandler  {
    +public:
    +									        CEndTokenHandler();
    +  virtual                 ~CEndTokenHandler();
    +		                      
    +  virtual   PRBool        operator()(CToken* aToken,nsHTMLParser* aParser);
    +  virtual   PRBool        CanHandle(eHTMLTokenTypes aType);
    +};
    +
    +
    +class CCommentTokenHandler : public CDefaultTokenHandler  {
    +public:
    +									        CCommentTokenHandler();
    +  virtual                 ~CCommentTokenHandler();
    +		                      
    +  virtual   PRBool        operator()(CToken* aToken,nsHTMLParser* aParser);
    +  virtual   PRBool        CanHandle(eHTMLTokenTypes aType);
    +};
    +
    +
    +class CEntityTokenHandler : public CDefaultTokenHandler  {
    +public:
    +									        CEntityTokenHandler();
    +  virtual                 ~CEntityTokenHandler();
    +		                      
    +  virtual   PRBool        operator()(CToken* aToken,nsHTMLParser* aParser);
    +  virtual   PRBool        CanHandle(eHTMLTokenTypes aType);
    +};
    +
    +
    +class CWhitespaceTokenHandler : public CDefaultTokenHandler  {
    +public:
    +									        CWhitespaceTokenHandler();
    +  virtual                 ~CWhitespaceTokenHandler();
    +		                      
    +  virtual   PRBool        operator()(CToken* aToken,nsHTMLParser* aParser);
    +  virtual   PRBool        CanHandle(eHTMLTokenTypes aType);
    +};
    +
    +
    +class CNewlineTokenHandler : public CDefaultTokenHandler  {
    +public:
    +									        CNewlineTokenHandler();
    +  virtual                 ~CNewlineTokenHandler();
    +		                      
    +  virtual   PRBool        operator()(CToken* aToken,nsHTMLParser* aParser);
    +  virtual   PRBool        CanHandle(eHTMLTokenTypes aType);
    +};
    +
    +
    +class CTextTokenHandler : public CDefaultTokenHandler  {
    +public:
    +									        CTextTokenHandler();
    +  virtual                 ~CTextTokenHandler();
    +		                      
    +  virtual   PRBool        operator()(CToken* aToken,nsHTMLParser* aParser);
    +  virtual   PRBool        CanHandle(eHTMLTokenTypes aType);
    +};
    +
    +
    +class CAttributeTokenHandler : public CDefaultTokenHandler  {
    +public:
    +									        CAttributeTokenHandler();
    +  virtual                 ~CAttributeTokenHandler();
    +		                      
    +  virtual   PRBool        operator()(CToken* aToken,nsHTMLParser* aParser);
    +  virtual   PRBool        CanHandle(eHTMLTokenTypes aType);
    +};
    +
    +
    +class CScriptTokenHandler :  public CDefaultTokenHandler  {
    +public:
    +									        CScriptTokenHandler();
    +  virtual                 ~CScriptTokenHandler();
    +		                      
    +  virtual   PRBool        operator()(CToken* aToken,nsHTMLParser* aParser);
    +  virtual   PRBool        CanHandle(eHTMLTokenTypes aType);
    +};
    +
    +
    +class CStyleTokenHandler : public CDefaultTokenHandler  {
    +public:
    +									        CStyleTokenHandler();
    +  virtual                 ~CStyleTokenHandler();
    +		                      
    +  virtual   PRBool        operator()(CToken* aToken,nsHTMLParser* aParser);
    +  virtual   PRBool        CanHandle(eHTMLTokenTypes aType);
    +};
    +
    +
    +class CSkippedContentTokenHandler : public CDefaultTokenHandler  {
    +public:
    +									        CSkippedContentTokenHandler();
    +  virtual                 ~CSkippedContentTokenHandler();
    +		                      
    +  virtual   PRBool        operator()(CToken* aToken,nsHTMLParser* aParser);
    +  virtual   PRBool        CanHandle(eHTMLTokenTypes aType);
    +};
    +
    +
    +#endif
    diff --git a/mozilla/parser/htmlparser/src/nsDeque.cpp b/mozilla/parser/htmlparser/src/nsDeque.cpp
    new file mode 100644
    index 00000000000..22ce66777b2
    --- /dev/null
    +++ b/mozilla/parser/htmlparser/src/nsDeque.cpp
    @@ -0,0 +1,226 @@
    +/* -*- 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 "nsDeque.h"
    +#include "nsToken.h"
    +
    +const PRInt32 kGrowthDelta = 10;
    +
    +/**-------------------------------------------------------
    + *  Standard constructor
    + *
    + *  @updated  	gess 28Feb98
    + *  @param
    + *  @return
    + *------------------------------------------------------*/
    +CDeque::CDeque() {
    +  mCapacity=kGrowthDelta;
    +  mOrigin=mSize=0;
    +  mTokens=new CToken*[mCapacity];
    +}
    +
    +/**-------------------------------------------------------
    + *  Standard destructor
    + *
    + *  @updated  	gess 28Feb98
    + *  @param
    + *  @return
    + *------------------------------------------------------*/
    +CDeque::~CDeque() {
    +  Erase();
    +  delete [] mTokens;
    +}
    +
    +/*-------------------------------------------------------
    + *  Remove all items from the queue without destroying them.
    + *  @updated gess 28Feb98
    + *  @param
    + *  @return
    + *------------------------------------------------------*/
    +void CDeque::Empty() {
    +  for(PRInt32 i=0;i0) {
    +    result=mTokens[mOrigin];
    +    mTokens[mOrigin++]=0;     //zero it out for debugging purposes.
    +    mSize--;
    +    if(0==mSize)
    +      mOrigin=0;
    +  }
    +  return result;
    +}
    +
    +/*-------------------------------------------------------
    + *  Get the ith element (in relative terms) not absolute 
    + *  index pos. Don't forget the origin may be anywhere.
    + *
    + *  @updated gess 28Feb98
    + *  @param   anIndex: 0 relative index
    + *  @return  CToken* or null.
    + *------------------------------------------------------*/
    +CToken* CDeque::ObjectAt(PRInt32 anIndex) {
    +  CToken* result=0;
    +  if((anIndex>=0) && (anIndexSetOrdinal(10);
    +  CToken* b=new CToken(nsAutoString("")); b->SetOrdinal(20);
    +  CToken* c=new CToken(nsAutoString("")); c->SetOrdinal(30);
    +  CToken* d=new CToken(nsAutoString("")); d->SetOrdinal(40);
    +  CToken* e=new CToken(nsAutoString("")); e->SetOrdinal(50);
    +  CToken* f=new CToken(nsAutoString("")); f->SetOrdinal(60);
    +  theDeck->Push(a);
    +  theDeck->Push(b);
    +  theDeck->Push(c);
    +  CToken* temp=theDeck->Pop();  //temp should == a
    +  temp=theDeck->Pop(); //temp should == b
    +  theDeck->Push(d);
    +  theDeck->Push(e);
    +
    +  CDequeIterator iter1=theDeck->Begin();
    +  CDequeIterator iter2=theDeck->End();
    +  while(iter1!=iter2) {
    +    temp=(iter1++);
    +    cout << temp->GetOrdinal();
    +  }
    +
    +  theDeck->Push(f); //should cause queue to resize and resequence.
    +  CDequeIterator iter3=theDeck->Begin();
    +  CDequeIterator iter4=theDeck->End();
    +  while(iter3!=iter4) {
    +    temp=(iter3++);
    +    cout << temp->GetOrdinal();
    +  }
    +  delete a;
    +  delete b;
    +  delete c;
    +  delete d;
    +  delete e;
    +  delete f;
    +  delete theDeck;
    +#endif
    +}
    +
    diff --git a/mozilla/parser/htmlparser/src/nsDeque.h b/mozilla/parser/htmlparser/src/nsDeque.h
    new file mode 100644
    index 00000000000..4c9dc9be628
    --- /dev/null
    +++ b/mozilla/parser/htmlparser/src/nsDeque.h
    @@ -0,0 +1,108 @@
    +/* -*- 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.
    + */
    +
    +/**
    + * MODULE NOTES:
    + * @update  gess 4/1/98
    + * 
    + * The easy queue is a very small, very efficient ring-
    + * buffer than can hold elements of type CToken*, offering
    + * the following features:
    + *    It's interface supports pushing and poping of children.
    + *    It can iterate (via an interator class) it's children.
    + *    When full, it can efficently resize dynamically.
    + *
    + * Note that the only bit of trickery here is that like
    + * all ring buffers, the first element may not be at index[0].
    + * The mOrigin member determines where the first child is.
    + * This point is quietly hidden from customers of this class.
    + *    
    + * If we have an existing general-purpose queue, then it
    + * should be trivial to substitute that implementation for
    + * this one. If not, this can easily be made into a general
    + * purpose container (substitue void* for CToken*).
    + */
    +
    +
    +#ifndef QUEUE
    +#define QUEUE
    +
    +#include "nsParserTypes.h"
    +#include "prtypes.h"
    +
    +class CToken;
    +class CDequeIterator;
    +
    +class CDeque {
    +  public:
    +                       CDeque();
    +                      ~CDeque();
    +            
    +            PRInt32   GetSize() const {return mSize;}
    +            void      Push(CToken* aToken);
    +            CToken*   Pop(void);
    +            CToken*   PopBack(void);
    +            CToken*   ObjectAt(int anIndex);
    +            void      Empty();
    +            void      Erase();
    +
    +            CDequeIterator Begin();
    +            CDequeIterator End();
    +
    +            static void SelfTest();
    +
    +  protected:
    +            PRInt32   mSize;
    +            PRInt32   mCapacity;
    +            PRInt32   mOrigin;
    +            CToken**  mTokens;
    +
    +
    +  private: 
    +            CDeque(const CDeque& other);
    +            CDeque& operator=(const CDeque& other);
    +};
    +
    +class CDequeIterator {
    +  public:
    +                      CDequeIterator(CDeque& aQueue,int anIndex=0) : mDeque(aQueue) {mIndex=anIndex; }
    +                      CDequeIterator(const CDequeIterator& aCopy) : mDeque(aCopy.mDeque), mIndex(aCopy.mIndex) { }
    +
    +      CDequeIterator& operator=(CDequeIterator& aCopy) {
    +                        //queue's are already equal.
    +                        mIndex=aCopy.mIndex;
    +                        return *this;
    +                      }
    +
    +        PRBool        operator!=(CDequeIterator& anIter) {return PRBool(!this->operator==(anIter));}
    +        PRBool        operator==(CDequeIterator& anIter) {return PRBool(((mIndex==anIter.mIndex) && (&mDeque==&anIter.mDeque)));}
    +        CToken*       operator++()    {return mDeque.ObjectAt(++mIndex);}
    +        CToken*       operator++(int) {return mDeque.ObjectAt(mIndex++);}
    +        CToken*       operator--()    {return mDeque.ObjectAt(--mIndex);}
    +        CToken*       operator--(int) {return mDeque.ObjectAt(mIndex--);}
    +        CToken*       operator*()     {return mDeque.ObjectAt(mIndex);}
    +                      operator CToken*() {return mDeque.ObjectAt(mIndex);}
    +
    +
    +  protected:
    +        PRInt32       mIndex;
    +        CDeque&       mDeque;
    +};
    +
    +
    +#endif
    diff --git a/mozilla/parser/htmlparser/src/nsHTMLContentSink.cpp b/mozilla/parser/htmlparser/src/nsHTMLContentSink.cpp
    new file mode 100644
    index 00000000000..d44be23f6c8
    --- /dev/null
    +++ b/mozilla/parser/htmlparser/src/nsHTMLContentSink.cpp
    @@ -0,0 +1,428 @@
    +/* -*- 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 "nsHTMLContentSink.h"
    +#include "nsHTMLTokens.h"
    +#include "prtypes.h" 
    +#include   
    +
    +#define VERBOSE_DEBUG
    +
    +static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);                 
    +static NS_DEFINE_IID(kIContentSinkIID, NS_ICONTENTSINK_IID);
    +static NS_DEFINE_IID(kIHTMLContentSinkIID, NS_IHTMLCONTENTSINK_IID);
    +static NS_DEFINE_IID(kClassIID, NS_HTMLCONTENTSINK_IID); 
    +
    +
    +
    +/**-------------------------------------------------------
    + *  "Fakey" factory method used to create an instance of
    + *  this class.
    + *  
    + *  @updated gess 3/25/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +nsresult NS_NewHTMLContentSink(nsIContentSink** aInstancePtrResult)
    +{
    +  nsHTMLContentSink *it = new nsHTMLContentSink();
    +
    +  if (it == 0) {
    +    return NS_ERROR_OUT_OF_MEMORY;
    +  }
    +
    +  return it->QueryInterface(kClassIID, (void **) aInstancePtrResult);
    +}
    +
    +
    +/**-------------------------------------------------------
    + *  Default constructor
    + *  
    + *  @updated gess 3/25/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +nsHTMLContentSink::nsHTMLContentSink() : nsIHTMLContentSink(), mTitle("") {
    +  mNodeStackPos=0;
    +  memset(mNodeStack,0,sizeof(mNodeStack));
    +}
    +
    +
    +/**-------------------------------------------------------
    + *  Default destructor. Probably not a good idea to call 
    + *  this if you created your instance via the factor method.
    + *  
    + *  @updated gess 3/25/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +nsHTMLContentSink::~nsHTMLContentSink() {
    +}
    +
    +#ifdef VERBOSE_DEBUG
    +static void DebugDump(const char* str1,const nsString& str2,PRInt32 tabs) {
    +  for(PRInt32 i=0;i" << endl;
    +  delete cp;
    +}
    +#endif
    +
    +
    +/**-------------------------------------------------------
    + *  This bit of magic creates the addref and release 
    + *  methods for this class.
    + *
    + *  @updated gess 3/25/98
    + *  @param  
    + *  @return 
    + *------------------------------------------------------*/
    +NS_IMPL_ADDREF(nsHTMLContentSink)
    +NS_IMPL_RELEASE(nsHTMLContentSink)
    +
    +
    +
    +/**-------------------------------------------------------
    + *  Standard XPCOM query interface implementation. I used
    + *  my own version because this class is a subclass of both
    + *  ISupports and IContentSink. Perhaps there's a macro for
    + *  this, but I didn't see it.
    + *  
    + *  @updated gess 3/25/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +nsresult nsHTMLContentSink::QueryInterface(const nsIID& aIID, void** aInstancePtr)  
    +{                                                                        
    +  if (NULL == aInstancePtr) {                                            
    +    return NS_ERROR_NULL_POINTER;                                        
    +  }                                                                      
    +
    +  if(aIID.Equals(kISupportsIID))    {  //do IUnknown...
    +    *aInstancePtr = (nsIContentSink*)(this);                                        
    +  }
    +  else if(aIID.Equals(kIContentSinkIID)) {  //do nsIContentSink base class...
    +    *aInstancePtr = (nsIContentSink*)(this);                                        
    +  }
    +  else if(aIID.Equals(kIHTMLContentSinkIID)) {  //do nsIHTMLContentSink base class...
    +    *aInstancePtr = (nsIHTMLContentSink*)(this);                                        
    +  }
    +  else if(aIID.Equals(kClassIID)) {  //do this class...
    +    *aInstancePtr = (nsHTMLContentSink*)(this);                                        
    +  }                 
    +  else {
    +    *aInstancePtr=0;
    +    return NS_NOINTERFACE;
    +  }
    +  ((nsISupports*) *aInstancePtr)->AddRef();
    +  return NS_OK;                                                        
    +}
    +
    +
    +/**-------------------------------------------------------
    + *  This method gets called by the parser when a  
    + *  tag has been consumed.
    + *  
    + *  @updated gess 3/25/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool nsHTMLContentSink::OpenHTML(const nsIParserNode& aNode) {
    +
    +  PRBool result=PR_TRUE;
    +  mNodeStack[mNodeStackPos++]=(eHTMLTags)aNode.GetNodeType();
    +
    +#ifdef VERBOSE_DEBUG
    +  DebugDump("<",aNode.GetText(),(mNodeStackPos-1)*2);
    +#endif
    +
    +  return result;
    +}
    +
    +/**-------------------------------------------------------
    + *  This method gets called by the parser when a  
    + *  tag has been consumed.
    + *  @updated gess 3/25/98
    + *  @param   
    + *  @return  
    + *------------------------------------------------------*/
    +PRBool nsHTMLContentSink::CloseHTML(const nsIParserNode& aNode){
    +
    +  NS_PRECONDITION(mNodeStackPos > 0, "node stack empty");
    +
    +  PRBool result=PR_TRUE;
    +  mNodeStack[--mNodeStackPos]=eHTMLTag_unknown;
    +
    +#ifdef VERBOSE_DEBUG
    +  DebugDump("any time
    + *  head data gets consumed by the parser. Currently, that
    + *  list includes , , , 
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +Welcome to Netscape - Navigation Banner + + + + + + + + + + +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + September 22, 1997 +
    + + + + + + + + +Publishing Suite Now Available + + + + + + + + +
      + + + + + + + Netscape Publishing Suite - the all-in-one solution for creating and publishing web sites - is now available in retail stores nationwide. + + +
    +
    + ABC News +
    + + + + + +Netscape delivers the new CommerceXpert family of Internet commerce products developed by Actra - including PublishingXpert 2.0, SellerXpert, and ECXpert. + + + +
    + + + + + + +Netscape launches a preview of Industry Watch by Individual, a personalized service providing in-depth business news and information. + + + + +
    + + + + + + + + + +Download Netscape French Communicator 4.03 for Windows 95 and NT - and take advantage of dynamic web content. + + + + +
    + + + + + + + + +Netscape works with leading sales force automation vendors to deliver next-generation tools that will automate and manage sales environments. + + +
    + + + + + More news... + + Go to a non-layers version of this page. + + + +
    +
    +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      +
    + + +Jim Barksdale + +
    +
    Netscape
    Columns

    + +In this week's The Main Thing column, Jim Barksdale talks about directory services. Read all the Netscape Columns to keep up with Internet issues and trends.

    + +
    + + +

    +  + + +Tune Up to Communicator +
    +
    +Netscape
    Products

    + +Tune Up to Communicator
    +Get Any Netscape Product
    +For Subscribers Only

    +

    +And tune up your Internet connection with ISP Select. + +
    +

    +  + + +
    +
    Netscape
    Store Special

    + + + + +Looking for a rich Internet experience? Purchase Netscape Communicator Deluxe Edition and get a $30 rebate. Plus save $10 on the Official Netscape Communicator 4.0 Professional Edition book. + + + +

    +

    +  +
    + + + + + + + +
    +  + +

    + + + +
    + + + + +
    +
    Corporate Sales: 650/937-2555 Personal Sales: 650/937-3777
    +Government Sales: 650/937-3678
    If you have any questions please visit +Customer Service or contact your nearest +sales office. • Copyright © 1997 +Netscape Communications +Corporation. • This site powered by Netscape SuiteSpot servers.
    + +

    +
    +

    + + +
    + + + + + +
    + +New to the Web? + + + + + + + + + + + + +Turn Your In-Box Into a News Center + + +Netcenter + + + + + + + +In-Box Direct Delivers The New York Times + + + + +

    +Get the best information on the Web without searching. Netscape In-Box Direct offers rich HTML content from USA Today, the Wall Street Journal, Sports Illustrated, ELLE International, and dozens more delivered directly to your email in-box. Choose the publications you want, and Netscape In-Box Direct will take care of the rest. +

    + + + + +Win a BMW Z3 1.9 Roadster + +
    + +Sign up for Netcenter today and register to win a BMW Z3 1.9 Roadster, PC workstations from Hewlett-Packard, trips from Travelocity and Continental Airlines, and music from CDnow. +

    + + +Software Store + +
    + +Looking for new collaboration software? Web development tools? Netscape's Software Store has all your business solutions software. + +

    + +Netscape Guide by Yahoo! + +
    + +Want a hot stock tip? Head over to the finance section of Netscape Guide by Yahoo! for a rich assortment of money management and investment resources. + + + + + + + + + +Tune in to Netcenter, the Best of the Net for: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + Community + +
    + + + + + Virtual Office + +

    +

    + +
    + Software +
    +
    + + + + SmartUpdate + +
    + + + + Software Store +

    + +

    + +
    + Content +
    +
    + + + +Industry Watch + +
    + + + Channel Finder + +
    + + + In-Box Direct + +
    + + + + Internet Guide + +
    + + + + Net Search +

    + +

    + +
    + + Available Soon + +
    +
    + + + + Professional Community + +
    + +
    + + + + + +

    Netcenter
    + + + + +
    + + + + + + + + diff --git a/mozilla/parser/htmlparser/tests/html/html001.html b/mozilla/parser/htmlparser/tests/html/html001.html new file mode 100644 index 00000000000..db589d3920b --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/html001.html @@ -0,0 +1,8 @@ + + + HTML-html04 + + +html tag has attributes. + + \ No newline at end of file diff --git a/mozilla/parser/htmlparser/tests/html/imgmap001.html b/mozilla/parser/htmlparser/tests/html/imgmap001.html new file mode 100644 index 00000000000..b826c9a4e96 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/imgmap001.html @@ -0,0 +1,13 @@ + + + + +

    area element with attributes set for circular shape of 80,80,60.

    + image for imagemap + + imagemap + + + diff --git a/mozilla/parser/htmlparser/tests/html/ins001.html b/mozilla/parser/htmlparser/tests/html/ins001.html new file mode 100644 index 00000000000..b7be3a2edd3 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/ins001.html @@ -0,0 +1,14 @@ + + +test INS tag + + +test INS, bi directional override
    +1normal text in body line 1. + +A This text is in INS +
    B line 2 in INS +
    +2normal text in body line 2. + + diff --git a/mozilla/parser/htmlparser/tests/html/ins002.html b/mozilla/parser/htmlparser/tests/html/ins002.html new file mode 100644 index 00000000000..c759228945c --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/ins002.html @@ -0,0 +1,18 @@ + + +test INS tag + + +test INS, bi directional override
    +1normal text in body line 1. + +A This text is in INS + + C This text is in INS2 +
    D line 2 in INS2 +
    +
    B line 2 in INS +
    +2normal text in body line 2. + + diff --git a/mozilla/parser/htmlparser/tests/html/ins003.html b/mozilla/parser/htmlparser/tests/html/ins003.html new file mode 100644 index 00000000000..8574eaef4b5 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/ins003.html @@ -0,0 +1,13 @@ + + + + + + del strikeover text + + +Normal text1 +
    text with underline +
    Normal text2 + + diff --git a/mozilla/parser/htmlparser/tests/html/insdel01.html b/mozilla/parser/htmlparser/tests/html/insdel01.html new file mode 100644 index 00000000000..9aa6ba964ea --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/insdel01.html @@ -0,0 +1,16 @@ + + +test INS tag + + +test INS
    +1normal text in body line 1. + +A This text is in INS + +
    B line 2 in INS +
    +
    +2normal text in body line 2. + + diff --git a/mozilla/parser/htmlparser/tests/html/insdel02.html b/mozilla/parser/htmlparser/tests/html/insdel02.html new file mode 100644 index 00000000000..4e21163812e --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/insdel02.html @@ -0,0 +1,16 @@ + + +INS DEL /INS /DEL crossing scope + + +test INS
    +1normal text in body line 1. + +A This text is in INS + +
    B line 2 in INS +
    +2normal text in body line 2. + + + diff --git a/mozilla/parser/htmlparser/tests/html/layer001.html b/mozilla/parser/htmlparser/tests/html/layer001.html new file mode 100644 index 00000000000..dc9790698fb --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/layer001.html @@ -0,0 +1,20 @@ + + + + +Test Layer + + + + +Layers do NOT imply new paragraph, nor line break. + + +Note, no line break here. Text-2 + + + +After layer, text-3 + + + diff --git a/mozilla/parser/htmlparser/tests/html/layer002.html b/mozilla/parser/htmlparser/tests/html/layer002.html new file mode 100644 index 00000000000..012d84451a9 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/layer002.html @@ -0,0 +1,28 @@ + + + + +Test Layer002 + + + + +In Vav4.0, SPAN tags go thour layers. +
    It remain in effect in its whole scope, including layer. + +Text in color=red SPAN. + + + +Text between 2 LAYERs. + + + + +

    +Text not in layer, but still in SPAN +

    +
    +Text after closing font tag. + + diff --git a/mozilla/parser/htmlparser/tests/html/layer003.html b/mozilla/parser/htmlparser/tests/html/layer003.html new file mode 100644 index 00000000000..846a4def75e --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/layer003.html @@ -0,0 +1,29 @@ + + + + +Test Layer003 + + + + +In Vav4.0, layers are in the same "span space" as their parents. +
    That means spans can be closed inside layer, and affect layers' parents. + + +Text in color=red SPAN. + + + +Text between 2 LAYERs. + + + + +

    +Text not in layer +

    + + + + diff --git a/mozilla/parser/htmlparser/tests/html/layer01.html b/mozilla/parser/htmlparser/tests/html/layer01.html new file mode 100644 index 00000000000..0a503a7eb4c --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/layer01.html @@ -0,0 +1,22 @@ + + + + +Welcome to Netscape + + + + +Text-1 + + + +
    Text-2 + + + +

    +no-layer-text-3 + + + diff --git a/mozilla/parser/htmlparser/tests/html/list001.html b/mozilla/parser/htmlparser/tests/html/list001.html new file mode 100644 index 00000000000..e2d549c797a --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/list001.html @@ -0,0 +1,33 @@ + +Welcome to Hewlett-Packard + + + +This file was created on 9/16/97 for bug #85117, assert in parser +when closing dd tag. + +
    This is from the end of the page www.hp.com +
    Note, an optional closing dd tag is missing. + +

  • + +
    + +
    [Search HP] + +[Top] +[Contact HP] +[Copyright] + + +
    + +
    + + +Note: no line break here. + +
    Now wrapped with a PRE tag. +
    +first line
    +
    invalide tags are ignored by 4.0 +
    + + +Note: no line break here. + \ No newline at end of file diff --git a/mozilla/parser/htmlparser/tests/html/q001.html b/mozilla/parser/htmlparser/tests/html/q001.html new file mode 100644 index 00000000000..e7cd998188b --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/q001.html @@ -0,0 +1,18 @@ + + +test BLOCKQUOTE and Q tag + + +test BLOCKQUOTE and Q tag
    +1normal text in body line 1. +
    +A This text is in blockquote +
    B line 2 +
    +2normal text in body line 2. + +this text is in Q tag + +3normal text in body line 3. + + diff --git a/mozilla/parser/htmlparser/tests/html/quote001.html b/mozilla/parser/htmlparser/tests/html/quote001.html new file mode 100644 index 00000000000..6b591b9193c --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/quote001.html @@ -0,0 +1,51 @@ + + + HTML test for quoted string + + + + This was created on 9/12/97, for Xena bug # 85121 +
    Testing the quoted value string. +
    tag A is used so you can check the string by moving mouse on the link. +
    use view source or text editor to compare with browser display. + +
    The goal is to be compatible with Navigator 4.0 +
    Test results are compared with Nav4.0 display. Relavent Nav4.0 source + files are ns\lib\libparse\pa_parse.c and others. +
    Differences between 4.0 and xena are indecated. Search for XENA60 + to find all the defferences. + +

    comments from ns\xena\lego\src\lego\html\scanner\HTMLScanner.java: +
    // For quoted value string : +
    // Double/single quote only take effect as the first char +
    // of the value string, +
    // Quoted string is terminated by the second double/single quote +
    // respectively. +
    // In other places, double/single quote is treated literally. +
    // Entity & quot; is always treated literally, enven it is the +
    // first char. +
    // +
    // Unquoted value string is terminated by while space, or '>' sign. +

    + + Test lines: + +
    10(quote / quote ) good syntax: both quotes striped from string +
    20( / ) value not quoted, not recommented, but still good syntax. +
    30 + Navigator 4.0 value string trunketed at 82 characters XENA60 limit is MAX_STRING_LENGTH = 2000. + +
    40 The following are illegal HTML, but handled by Nav4.0 in different ways. +
    50( / ) string not quoted, whight space terminates the value +
    60( / ) string not quoted, CR terminates the string +
    70(escaped-quote / quote ) both quotes remain in string +
    80(quote / ) + move mouse on this. If we didn't have a quote in the text, the value string would + run through the end of the A tag. +
    90(quote / escaped-quote ) same as above, escaped quote does NOT terminate quote +
    100( / quote) if no opening quote, quotes are included in string +
    110( / quote) no opening quote, value terminated at right brack + + + diff --git a/mozilla/parser/htmlparser/tests/html/quote002.html b/mozilla/parser/htmlparser/tests/html/quote002.html new file mode 100644 index 00000000000..2873a8c8fe8 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/quote002.html @@ -0,0 +1,33 @@ + + + HTML test for quoted string + + + + This was created on 9/15/97, for Xena bug # 85121 +
    Testing the quoted value string. +
    tag A is used so you can check the string by moving mouse on the link. +
    use view source or text editor to compare with browser display. +
    10 2 quoted string stick together +
    20 2 quoted string seperated by space +
    30 Navigator doesn't support nested quote. +
    40 quoted string can have escaped quote. +
    50 unquoted string can have escaped quote. +
    60 unquoted string can have other entities. +
    70 entity missing ';', ended by > +
    80 entity missing ';', not treated as entity inside a value word. +
    90 ending entity with a space, missing ';', value terminated. +
    100 ending entity with a '=', missing ';', value not terminated. +
    110 unquoted script is treated as text. +
    120 Navigator 4.0 does not support script + entity in quoted string. + + +
    130 this is fisrt quote " and second quote " in text area. +
    140 this is fisrt escaped-quote " and second escaped-quote " in text area. + +
    +
    In the following test line, quote is the last char in the html file. +
    Navigator 4.0 displace the line as text. +
    XENA60 appends a closing quote and display it as link with empty href="". +
    150 + + + +Test SPAN001 + + + + +

    +In HTML standard, SPANs are not allowed to cross Paragraphs. +
    In Vav4.0, SPAN tags go thour paragraphs and other block-level elements, +except tbles. +
    It be compatable with Nav4.0 and HTML standard, HTMLParser +close all SPANs before open a new paragraph, and reopen SPANs +inside the new paragraph +
    + + + Text ater the color=red SPAN is opend. +

    + Text in a new paragraph. +

    +

    + Text after the new paragrapg is closed, still in color=red SPAN. + +
    +Text ater the color=red SPAN is closed. + + diff --git a/mozilla/parser/htmlparser/tests/html/span002.html b/mozilla/parser/htmlparser/tests/html/span002.html new file mode 100644 index 00000000000..5f3c497ff84 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/span002.html @@ -0,0 +1,21 @@ + + + + +Test SPAN001 + + + + +Normal text + +Text after the color=red SPAN is opend. +

    + Text in a new paragraph. +

    + Text after the new paragrapg is closed, still in color=red SPAN. + +Text ater the color=red SPAN is closed. +
    another line. + + diff --git a/mozilla/parser/htmlparser/tests/html/span003.html b/mozilla/parser/htmlparser/tests/html/span003.html new file mode 100644 index 00000000000..c4ea303d8c9 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/span003.html @@ -0,0 +1,17 @@ + + + + +Test SPAN001 + + + + +

    + + bold + italic + B closed(but actualy it closed the last span tag, which is I tag. + I closed + + diff --git a/mozilla/parser/htmlparser/tests/html/strike002.html b/mozilla/parser/htmlparser/tests/html/strike002.html new file mode 100644 index 00000000000..65d505d595a --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/strike002.html @@ -0,0 +1,17 @@ + + +Nested STRIKE + + +nested STRIKE
    +1normal text in body line 1. + +A This text is in STRIKE + +
    B line 2 in STRIKE +
    +C line 3 in STRIKE +
    +2normal text in body line 2. + + diff --git a/mozilla/parser/htmlparser/tests/html/strike005.html b/mozilla/parser/htmlparser/tests/html/strike005.html new file mode 100644 index 00000000000..4040627aca8 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/strike005.html @@ -0,0 +1,22 @@ + + +strikeover a whole TABLE + + +strikeover a whole TABLE, no visual effect, no strikeover on text in table
    +1normal text in body line 1. + +text with strikeover +

    + + +
    This is the first cell in the table + This is the second cell in the table +
    This is the third cell in the table + This is the fourth cell in the table +
    +text still inside strikeover. + +2normal text in body line 2. + + diff --git a/mozilla/parser/htmlparser/tests/html/strike006.html b/mozilla/parser/htmlparser/tests/html/strike006.html new file mode 100644 index 00000000000..979198c12b3 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/strike006.html @@ -0,0 +1,18 @@ + + +strikeover in a table cell TD + + +strikeover in a table cell TD
    +1normal text in body line 1. + + + +
    This is the first cell in the table + This is strikeover +
    This is the third cell in the table + This is the fourth cell in the table +
    +2normal text in body line 2. + + diff --git a/mozilla/parser/htmlparser/tests/html/strike007.html b/mozilla/parser/htmlparser/tests/html/strike007.html new file mode 100644 index 00000000000..eaa80db9961 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/strike007.html @@ -0,0 +1,20 @@ + + +strikeover a whole table cell TD + + +strikeover a whole table cell TD +1normal text in body line 1. + + + + + +
    This is the first cell in the table + + This cell is in strikeover
    This is the third cell in the table + This is the fourth cell in the table +
    +2normal text in body line 2. + + diff --git a/mozilla/parser/htmlparser/tests/html/strike008.html b/mozilla/parser/htmlparser/tests/html/strike008.html new file mode 100644 index 00000000000..cc95b6ebf47 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/strike008.html @@ -0,0 +1,26 @@ + + +strikeover cross scope with a table + + +

    strikeover cross scope with a table
    +It starts before table, but ends inside table. +
    It does not effect the table, but the strikeover is terminated after the table. +
    1normal text in body line 1. + +text in strikeover. + + + + + +
    This is the first cell in the table + This cell 2
    This is the third cell in the table + This is the fourth cell in the table +
    +

    +text not in strikeover + +
    2normal text in body line 2. + + diff --git a/mozilla/parser/htmlparser/tests/html/table05a.html b/mozilla/parser/htmlparser/tests/html/table05a.html new file mode 100644 index 00000000000..a6df8ca395e --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/table05a.html @@ -0,0 +1,14 @@ +Caption before end of table +
    Nav 4.0: caption is accepted. (terminate tr) +
    Xena6.0: ignore misplaced caption tag. + + + + + +
    cell 1-1 + cell 1-2 +
    cell 2-1 + cell 2-2
    caption1
    + +last text diff --git a/mozilla/parser/htmlparser/tests/html/table05b.html b/mozilla/parser/htmlparser/tests/html/table05b.html new file mode 100644 index 00000000000..e05836f3ee2 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/table05b.html @@ -0,0 +1,14 @@ +Caption after tr. +
    Nav 4.0: caption is accepted, terminate an empty tr, +
    Xena6.0: ignore misplaced caption tag. + + + taxeA + +
    caption1
    cell 1-1 + cell 1-2 +
    cell 2-1 + cell 2-2 +
    + +last text diff --git a/mozilla/parser/htmlparser/tests/html/table05c.html b/mozilla/parser/htmlparser/tests/html/table05c.html new file mode 100644 index 00000000000..1b55afcc3a5 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/table05c.html @@ -0,0 +1,14 @@ +Caption between table cell +
    Nav 4.0: caption is accepted, terminate tr, +
    Xena6.0: ignore misplaced caption tag. + + + + textA + +
    cell 1-1
    caption1
    cell 1-2 +
    cell 2-1 + cell2-2 +
    + +last text diff --git a/mozilla/parser/htmlparser/tests/html/table05d.html b/mozilla/parser/htmlparser/tests/html/table05d.html new file mode 100644 index 00000000000..3144e70f146 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/table05d.html @@ -0,0 +1,13 @@ +Caption inside cell +
    Nav 4.0: caption is accepted, terminates both td and tr. +
    Xena6.0: ignore misplaced caption tag. + + + textA + +
    cell 1-1
    caption1
    cell 1-2 +
    cell 2-1 + cell 2-2 +
    + +last text diff --git a/mozilla/parser/htmlparser/tests/html/table05k.html b/mozilla/parser/htmlparser/tests/html/table05k.html new file mode 100644 index 00000000000..d05228d0811 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/table05k.html @@ -0,0 +1,19 @@ +Table in caption works. + + + +
    caption1
    text1 text2 + + + +
    cell 1-1 + cell 1-2 +
    still in + caption +
    +
    cell 2-1-1 + cell 2-1-2 +
    cell 2-2-1 +
    + +last text diff --git a/mozilla/parser/htmlparser/tests/html/table05l.html b/mozilla/parser/htmlparser/tests/html/table05l.html new file mode 100644 index 00000000000..c7dbd30c4e9 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/table05l.html @@ -0,0 +1,14 @@ +Table in caption, and Nav4.0 show blank page if the window is wide. +Table in caption is part of the caption, leave the table body empty. + + + +
    caption1
    text1 text2 + + + +
    cell 1-1 + cell 1-2 +
    cell 2-1 + cell 2-2 +
    + +Nev. 4.0 ignore empty tables. \ No newline at end of file diff --git a/mozilla/parser/htmlparser/tests/html/table05m.html b/mozilla/parser/htmlparser/tests/html/table05m.html new file mode 100644 index 00000000000..18c01e22dfa --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/table05m.html @@ -0,0 +1,5 @@ +Start table tag alone is ignored. + + + +last text diff --git a/mozilla/parser/htmlparser/tests/html/table05n.html b/mozilla/parser/htmlparser/tests/html/table05n.html new file mode 100644 index 00000000000..83aede59060 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/table05n.html @@ -0,0 +1,11 @@ +End table tag terminates caption and table. +
    +
    caption1
    text1 text2 +
    +
    cell1 +
    cell2 +
    + +last text diff --git a/mozilla/parser/htmlparser/tests/html/table05o.html b/mozilla/parser/htmlparser/tests/html/table05o.html new file mode 100644 index 00000000000..34fa22e5fd1 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/table05o.html @@ -0,0 +1,6 @@ +caption is not shown for empty table. + + +
    caption1
    text1 text2
    + +last text diff --git a/mozilla/parser/htmlparser/tests/html/table07.html b/mozilla/parser/htmlparser/tests/html/table07.html new file mode 100644 index 00000000000..64a0edfbe9c --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/table07.html @@ -0,0 +1,13 @@ +text1 + text2 + + + +
    cell 1-1 + cell 1-2 +
    still in + caption +
    +text3 +
    +last text diff --git a/mozilla/parser/htmlparser/tests/html/table200.html b/mozilla/parser/htmlparser/tests/html/table200.html new file mode 100644 index 00000000000..e43c788bf7b --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/table200.html @@ -0,0 +1,21 @@ +Table in table, but not in tr-td. +
    the outter table is ignored. + + +
    + + + +
    caption of table1.
    first cell in table1 + second cell in table1 +
    third cell in table1 + fourth cell in table1 +
    +

    This is the first cell in table2. +
    + +NOTE, even no line break here! +
    +Caption of outer table is ignored. +Data of outer table is treated as text. \ No newline at end of file diff --git a/mozilla/parser/htmlparser/tests/html/table201.html b/mozilla/parser/htmlparser/tests/html/table201.html new file mode 100644 index 00000000000..62e9665d5e8 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/table201.html @@ -0,0 +1,22 @@ +Table in table, but not in tr-td. +
    the outter table is ignored. + + + +
    caption of table2.
    + + + +
    caption of table1.
    first cell in table1 + second cell in table1 +
    third cell in table1 + fourth cell in table1 +
    + +This is the first cell in table2. + + +NOTE, even no line break here! +
    +Caption of outer table is ignored. +Data of outer table is treated as text. \ No newline at end of file diff --git a/mozilla/parser/htmlparser/tests/html/table202.html b/mozilla/parser/htmlparser/tests/html/table202.html new file mode 100644 index 00000000000..5f5c81afdcf --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/table202.html @@ -0,0 +1,23 @@ +Table in table, after tr, but not td. +
    the outter table and tr are ignored. + + + + +
    caption of table2.
    + + + +
    caption of table1.
    first cell in table1 + second cell in table1 +
    third cell in table1 + fourth cell in table1 +
    + +This is the first cell in table2. + + +NOTE, even no line break here! +
    +Caption of outer table is ignored. +Data of outer table is treated as text. \ No newline at end of file diff --git a/mozilla/parser/htmlparser/tests/html/table203.html b/mozilla/parser/htmlparser/tests/html/table203.html new file mode 100644 index 00000000000..8d0075d53ef --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/table203.html @@ -0,0 +1,29 @@ +Table nested 3 levels, table3 be the out most. +
    Table 1 is not in table2's tr-td. That makes table2 invalid. +
    Table3 is still valid, and table2's tr and td are used for +table3. + + + + + +
    caption of table3.
    + + + Text after table2, not in tr-td, but in table3's tr-td. +
    caption of table2.
    + + + +
    caption of table1.
    first cell in table1 + second cell in table1 +
    third cell in the table1 + fourth cell in the table1 +
    +
    first cell in table2, but displayed in table 3. +
    + + second cell in table3. but table2's end tag closed table3. + So, this will be displayed out of table3. + + diff --git a/mozilla/parser/htmlparser/tests/html/table204.html b/mozilla/parser/htmlparser/tests/html/table204.html new file mode 100644 index 00000000000..0842245cc02 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/table204.html @@ -0,0 +1,23 @@ +nested table missing end td. +
    Nav. 4.0(bug): For inner table td does NOT terminate previous td. +
    Xena 6.0: end td is always optional. + + + + + +
    caption of table1.
    cell 1-1 + cell 1-2 +
    cell 1-3 + cell 1-4 + + + + +
    caption of table2.
    cell1 in table2 + cell2 in table2 +
    cell3 in table2 + cell4 in table2 +
    +
    +
    Last text. \ No newline at end of file diff --git a/mozilla/parser/htmlparser/tests/html/table205.html b/mozilla/parser/htmlparser/tests/html/table205.html new file mode 100644 index 00000000000..905659196c3 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/table205.html @@ -0,0 +1,28 @@ +Table in table, but not in tr-td. +
    The only thing missing is the end tag of the +first table! +Nav. 4.0: the outter table is ignored. +Xena 6.0: second table start tag is ignored. Contents put in 1 table. + + + + + + + + +
    caption of table1.
    first cell in table1 + second cell in table1 +
    third cell in table1 + fourth cell in table1 +
    + + + +
    caption of table2.
    cell1 in table2 + cell2 in table2 +
    cell3 in table2 + cell4 in table2 +
    + +
    Last text. \ No newline at end of file diff --git a/mozilla/parser/htmlparser/tests/html/tableall.html b/mozilla/parser/htmlparser/tests/html/tableall.html new file mode 100644 index 00000000000..0381ca289ca --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/tableall.html @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    table test cases
    Test case description +
    good syntax
    +
    table01.html <table> <tr> <td> +
    table02.html <table> <tr> <td> <table> nested +
    table03.html <table border align=left> +
    table04.html <table> mixed with list. + +
    table05 The correct position for Caption is after table start tag. + + +
    bad syntax
    +
    *table05a Caption before </table>. 4.0: Accepted, 6.0: ignored. +
    *table05b Caption after tr. 4.0: Accepted, 6.0: ignored. +
    *table05c Caption between table cell. 4.0: Accepted, 6.0: ignored. +
    *table05d Caption inside cell. 4.0: terminates both td and tr. 6.0: Ignored. +
    table05e Multiple caption outside cells. 4.0 takes first as Caption, others as text. +
    *table05f Captions inside cells, 4.0 takes last one, terminate td tr, 6.0 Ignore misplaced tag. +
    table05g Captions outside of table are treated as text. +
    table05h tr terminates caption +
    table05i tr terminates Caption, and close open(font) tags in caption. +
    table05j TD does NOT terminate Caption. TD's contents are used in caption. +
    table05k Table in caption works. +
    table05l Table in caption, table empty. 4.0(bug): shows blank page. +
    table05m <table> alone is ignored. +
    table05n </table> terminates caption and table. +
    table05o caption is not shown for empty table.
    table110.htm <tr> <td> missing <table> +
    table115.htm <table> text1 <tr> test2 <td> test3 +
    table120.htm <table> </table> table totally empty . +
    table125.htm <table> text </table>, no tr, td +
    table130.htm <table> <td> , missing tr +
    table135.htm <table> <tr> <tr> <td> , empty tr. +
    table140.htm <table> <tr> text <tr> <td> , empty tr. +
    table150.htm <table> <tr> <td> <td> , empty td. + +
    table201.html <table> <table> +
    table202.html <table> <tr> <table> +
    table203.html Table nested 3 levels, T1 not in T2's td +
    *table204.htm nested table missing end td. 4.0(bug) inner table need </td> +
    *table205.htm table in table. 4.0: discard outer, 6.0: put into 1 table. +
    + + diff --git a/mozilla/parser/htmlparser/tests/html/tag001.html b/mozilla/parser/htmlparser/tests/html/tag001.html new file mode 100644 index 00000000000..dd2b5698dca --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/tag001.html @@ -0,0 +1,3 @@ +first line +second line +third line < \ No newline at end of file diff --git a/mozilla/parser/htmlparser/tests/html/tag002.html b/mozilla/parser/htmlparser/tests/html/tag002.html new file mode 100644 index 00000000000..5083bee2948 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/tag002.html @@ -0,0 +1,23 @@ +Broken tags are shown, only if no gt sign can be found. + + +aaaaaaaaaaaa + + +bbbbbbbb + +< + +open tag without name, stat with space, treated as text. +
    +KKKKKKKKKK + +< open tag has no tag name, stat with space, treated as text. +
    +ccccccc + +second line +

    Here is next paragraph. +
    +They ignored by 4,0. +Everything between the brakets is consummed. \ No newline at end of file diff --git a/mozilla/parser/htmlparser/tests/html/tag004.html b/mozilla/parser/htmlparser/tests/html/tag004.html new file mode 100644 index 00000000000..00b6cc77073 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/tag004.html @@ -0,0 +1,4 @@ +first line +
    empty brakets are displayed as text +<> +more text. diff --git a/mozilla/parser/htmlparser/tests/html/tag005.html b/mozilla/parser/htmlparser/tests/html/tag005.html new file mode 100644 index 00000000000..cb46e427796 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/tag005.html @@ -0,0 +1,7 @@ +first line +
    empty brakets are displayed as text +This +and this eat next br tag. +and another one. +Last text. diff --git a/mozilla/parser/htmlparser/tests/html/tag006.html b/mozilla/parser/htmlparser/tests/html/tag006.html new file mode 100644 index 00000000000..36d3dcc0d02 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/tag006.html @@ -0,0 +1,6 @@ +first line +
    invalide tags are ignored by 4.0 + + + +Note: no line break here. diff --git a/mozilla/parser/htmlparser/tests/html/tag007.html b/mozilla/parser/htmlparser/tests/html/tag007.html new file mode 100644 index 00000000000..596b5484dc5 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/tag007.html @@ -0,0 +1,5 @@ +first line +
    Unmacthed opening tag in next line is ignored by 4.0 + +
    +Note: no line break inserted here. diff --git a/mozilla/parser/htmlparser/tests/html/tag008.html b/mozilla/parser/htmlparser/tests/html/tag008.html new file mode 100644 index 00000000000..6b67931e732 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/tag008.html @@ -0,0 +1,4 @@ +first line +
    Unmacthed end tag in next line is ignored by 4.0 +
    +Note: no line break inserted here. diff --git a/mozilla/parser/htmlparser/tests/html/target01.html b/mozilla/parser/htmlparser/tests/html/target01.html new file mode 100644 index 00000000000..44c34fdbb29 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/target01.html @@ -0,0 +1,7 @@ + +Target outside of quoted HREF. +
    example: +
    +two days + + \ No newline at end of file diff --git a/mozilla/parser/htmlparser/tests/html/tbody001.html b/mozilla/parser/htmlparser/tests/html/tbody001.html new file mode 100644 index 00000000000..d639a01c606 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/tbody001.html @@ -0,0 +1,17 @@ + + +Welcome to Netscape + + +
    + + + + + +
    + table element with no attributes. The required embedded + elements are used - TBODY-TR-TD. +
    + + diff --git a/mozilla/parser/htmlparser/tests/html/text001.html b/mozilla/parser/htmlparser/tests/html/text001.html new file mode 100644 index 00000000000..55c4e5ee38e --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/text001.html @@ -0,0 +1,8 @@ + + +Welcome to Netscape + + +Text-001 + + diff --git a/mozilla/parser/htmlparser/tests/html/text002.html b/mozilla/parser/htmlparser/tests/html/text002.html new file mode 100644 index 00000000000..68b070ca308 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/text002.html @@ -0,0 +1,8 @@ + + +Welcome to Netscape + + +Text-002 + + diff --git a/mozilla/parser/htmlparser/tests/html/text003.html b/mozilla/parser/htmlparser/tests/html/text003.html new file mode 100644 index 00000000000..aa1f7ae9ccc --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/text003.html @@ -0,0 +1,12 @@ + + + +Welcome to Netscape + + +Text-001 + +
    +Text after closing font tag. + + diff --git a/mozilla/parser/htmlparser/tests/html/thead001.html b/mozilla/parser/htmlparser/tests/html/thead001.html new file mode 100644 index 00000000000..b517ea769be --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/thead001.html @@ -0,0 +1,25 @@ +Normal case for thead, tfoot, tbody + + + + + + + + + + + + + + + + + +
    caption of table2.
    text in thead
    text in tfoot
    first cell in table1 + second cell in table1 +
    third cell in table1 + fourth cell in table1 +
    + +last text. \ No newline at end of file diff --git a/mozilla/parser/htmlparser/tests/html/title01.html b/mozilla/parser/htmlparser/tests/html/title01.html new file mode 100644 index 00000000000..c6404098244 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/title01.html @@ -0,0 +1,6 @@ + + +<!-- still in comment --> + +some text + diff --git a/mozilla/parser/htmlparser/tests/html/usascii.html b/mozilla/parser/htmlparser/tests/html/usascii.html new file mode 100644 index 00000000000..834856339d0 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/usascii.html @@ -0,0 +1,26 @@ + + + + Juan Gotoh's Visual Workshop + + + + + + + + + + + + +<BODY> + +<P>If your brouser can not display frame, please click +<A HREF="home_E.html">here.</A> it has same contents as frame +version.</P> + +</BODY> + + diff --git a/mozilla/parser/htmlparser/tests/html/utf8001.html b/mozilla/parser/htmlparser/tests/html/utf8001.html new file mode 100644 index 00000000000..017a3d7c652 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/utf8001.html @@ -0,0 +1,9 @@ + + + +Welcome to Netscape + + +Text-001 + + diff --git a/mozilla/parser/htmlparser/tests/html/value001.html b/mozilla/parser/htmlparser/tests/html/value001.html new file mode 100644 index 00000000000..55c926e7eb7 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/value001.html @@ -0,0 +1,14 @@ + + + + +Welcome to Netscape + + + + + + + + + diff --git a/mozilla/parser/htmlparser/tests/html/xmp005.html b/mozilla/parser/htmlparser/tests/html/xmp005.html new file mode 100644 index 00000000000..ac952f5b849 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/html/xmp005.html @@ -0,0 +1,48 @@ + + +use a XMP tag for C or JAVA source code. +
    The lt and gt signes are problematic. + + + + cc = 123; + // test lt + if( cc < hhh ) { + if(cc<xxx || as > gh) { + //do womthing here; + } + } + if( cc <= iii ) { + if(cc<=yyy) { + //do womthing here; + } + } + // test gt + if( cc > rrr ) { + if(cc>eee) { + //do womthing here; + } + } + if( cc >= www ) { + if(cc>=qqq) { + //do womthing here; + } + } + // what if the variable name is a valid tag name. + if( cc < B && cc > kk ) { + if(cc<B && cc > gg) { + //do womthing here; + } + } + cc = aa<<I; + cc = B>>3; + gt = true; + for(a=0,gt=true; (a>0)&&gt; a++) { + } + a = 0x0004; + lt = 0x0002; + for(; a&lt; ) { + } + + + \ No newline at end of file diff --git a/mozilla/parser/htmlparser/tests/windows/Selftest.cpp b/mozilla/parser/htmlparser/tests/windows/Selftest.cpp new file mode 100644 index 00000000000..0660fc576ba --- /dev/null +++ b/mozilla/parser/htmlparser/tests/windows/Selftest.cpp @@ -0,0 +1,148 @@ +/* -*- Mode: C++; tab-width: 4; 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 +#include +#include +#include +#include +#include + +#include "nsScanner.h" +#include "nsTokenizer.h" +#include "nsHTMLDelegate.h" + + +bool compareFiles(const char* file1,const char* file2) { + bool result=true; + bool done=false; + char ch1,ch2; + int eof1,eof2; + + ifstream input1(file1,ios::in && ios::binary,filebuf::openprot); + ifstream input2(file2,ios::in && ios::binary,filebuf::openprot); + + while(!done) { + + while(!(eof1=input1.eof())) { + input1.read(&ch1,1); + if(('\n'!=ch1) && (' '!=ch1)) + break; + } + + while(!(eof2=input2.eof())) { + input2.read(&ch2,1); + if(('\n'!=ch2) && (' '!=ch2)) + break; + } + + if(eof1==eof2) { + if(eof1) + done=true; + else if(ch1!=ch2) { + done=true; + result=false; + } + } + else done=true; + } + return result; +} + +void parseFile (const char* aFilename,int size) +{ + //debug + aFilename="s:\\ns\\raptor\\parser\\tests\\html\\tag001.html"; + //aFilename="c:\\temp\\temp.html"; + + char filename[_MAX_PATH]; + strcpy(filename,aFilename); + strcat(filename,".tokens"); + { + ofstream out(filename); + ifstream input(aFilename); + CScanner scanner(input); + CHTMLTokenizerDelegate delegate; + CTokenizer tokenizer(scanner,delegate); + tokenizer.tokenize(); + tokenizer.debugDumpSource(out); + } + cout << aFilename; + if(compareFiles(aFilename,filename)) + cout << " PASS " << endl; + else cout << " FAIL" << endl; +} + +int walkDirectoryTree(char* aPath) { + int result=0; + char fullPath[_MAX_PATH]; + struct _finddata_t c_file; + long hFile; + + strcpy(fullPath,aPath); + strcat(fullPath,"\\*.*"); + /* Find first .c file in current directory */ + if((hFile = _findfirst( fullPath, &c_file )) == -1L ) + printf( "No matching files in current directory!\n" ); + else { + + bool done=false; + while(!done) { + if(c_file.attrib & _A_SUBDIR) { + if(strlen(c_file.name)>2){ + char newPath[_MAX_PATH]; + strcpy(newPath,aPath); + strcat(newPath,"\\"); + strcat(newPath,c_file.name); + walkDirectoryTree(newPath); + } + } + else { + int len=strlen(c_file.name); + if(len>5) { + if(0==strnicmp(&c_file.name[len-5],".HTML",5)) { + char filepath[_MAX_PATH]; + strcpy(filepath,aPath); + strcat(filepath,"\\"); + strcat(filepath,c_file.name); + parseFile(filepath,c_file.size); + } + } + } + if(_findnext( hFile, &c_file )!=0) + done=true; + } + _findclose( hFile ); + } + return 0; +} + +int main(int argc, char* argv []) +{ + int result=0; + char buffer[_MAX_PATH]; + + if(argc==2) + strcpy(buffer,argv[1]); + else _getcwd(buffer,_MAX_PATH); + walkDirectoryTree(buffer); + return 0; +} + + + diff --git a/mozilla/raptor.mak b/mozilla/raptor.mak new file mode 100644 index 00000000000..8de54d433c2 --- /dev/null +++ b/mozilla/raptor.mak @@ -0,0 +1,162 @@ +# 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. + +DEPTH=. +IGNORE_MANIFEST=1 + +# +# Command macro defines +# + +CVSCO = cvs -q co -P + +# Branch tags we use +IMGLIB_BRANCH = MODULAR_IMGLIB_BRANCH +NETLIB_BRANCH = MODULAR_NETLIB_BRANCH +XPCOM_BRANCH = XPCOM_BRANCH +RAPTOR_BRANCH = RAPTOR_BRANCH + +# CVS commands to pull the appropriate branch versions +CVSCO_XPCOM = $(CVSCO) -r $(XPCOM_BRANCH) +CVSCO_IMGLIB = $(CVSCO) -r $(IMGLIB_BRANCH) +CVSCO_NETLIB = $(CVSCO) -r $(NETLIB_BRANCH) +CVSCO_RAPTOR = $(CVSCO) -r $(RAPTOR_BRANCH) +CVSCO_LIZARD = $(CVSCO) + +# The list of directories that need to be built to build the standalone +# raptor test program. The order is important. +!ifndef RAPTOR_PASS2 +DIRS = \ + nsprpub \ + include \ + jpeg \ + modules\libreg \ + xpcom \ + modules\zlib \ + modules\libutil \ + sun-java \ + nav-java \ + js \ + modules\security\freenav \ + modules\libpref \ + modules\libimg \ + lib\xp \ + lib\libnet +!else +DIRS = \ + base \ + htmlparser \ + dom \ + gfx \ + view \ + widget \ + layout \ + webshell +!endif + +include <$(DEPTH)\config\config.mak> + +# +# NOTE: Don't use make all with this makefile; it won't work! +# NOTE: Don't use make export with this makefile; it won't work! +# NOTE: Don't use make libs with this makefile; it won't work! +# NOTE: Don't use make clobber with this makefile; it won't work! +# + +THIS_MAKEFILE = raptor.mak + +real_all: pass1_all pass2_all + +pass1_all: + $(NMAKE) -f $(THIS_MAKEFILE) export + $(NMAKE) -f $(THIS_MAKEFILE) libs + $(NMAKE) -f $(THIS_MAKEFILE) install + +pass2_all: + $(NMAKE) -f $(THIS_MAKEFILE) RAPTOR_PASS2=pass2 export + $(NMAKE) -f $(THIS_MAKEFILE) RAPTOR_PASS2=pass2 libs + $(NMAKE) -f $(THIS_MAKEFILE) RAPTOR_PASS2=pass2 install + +real_export: + $(NMAKE) -f $(THIS_MAKEFILE) export + $(NMAKE) -f $(THIS_MAKEFILE) RAPTOR_PASS2=pass2 export + +real_libs: + $(NMAKE) -f $(THIS_MAKEFILE) libs + $(NMAKE) -f $(THIS_MAKEFILE) RAPTOR_PASS2=pass2 libs + +real_install: + $(NMAKE) -f $(THIS_MAKEFILE) install + $(NMAKE) -f $(THIS_MAKEFILE) RAPTOR_PASS2=pass2 install + +real_clobber: + $(NMAKE) -f $(THIS_MAKEFILE) clobber + $(NMAKE) -f $(THIS_MAKEFILE) RAPTOR_PASS2=pass2 clobber + $(NMAKE) -f $(THIS_MAKEFILE) final_clobber + +final_clobber: + cd $(MOZ_SRC)\ns + -rd /s /q dist + +real_depend: + $(NMAKE) -f $(THIS_MAKEFILE) depend + $(NMAKE) -f $(THIS_MAKEFILE) RAPTOR_PASS2=pass2 depend + +include <$(DEPTH)\config\rules.mak> + +# +# Rules for pulling the source from the cvs repository +# + +pull_all: pull_lizard pull_xpcom pull_imglib pull_netlib pull_raptor + +pull_lizard: + @cd $(MOZ_SRC)\. + $(CVSCO_LIZARD) ns/modules/zlib + $(CVSCO_LIZARD) ns/modules/libutil + $(CVSCO_LIZARD) ns/nsprpub + $(CVSCO_LIZARD) ns/sun-java + $(CVSCO_LIZARD) ns/nav-java + $(CVSCO_LIZARD) ns/js + $(CVSCO_LIZARD) ns/modules/security/freenav + $(CVSCO_LIZARD) ns/modules/libpref + +pull_xpcom: + @cd $(MOZ_SRC)\. + $(CVSCO_XPCOM) ns/modules/libreg + $(CVSCO_XPCOM) ns/xpcom + +pull_imglib: + @cd $(MOZ_SRC)\. + $(CVSCO_IMGLIB) ns/jpeg + $(CVSCO_IMGLIB) ns/modules/libutil + $(CVSCO_IMGLIB) ns/modules/libimg + +pull_netlib: + @cd $(MOZ_SRC)\. + $(CVSCO_NETLIB) ns/lib/xp + $(CVSCO_NETLIB) ns/lib/libnet + $(CVSCO_NETLIB) ns/include + +pull_raptor: + @cd $(MOZ_SRC)\. + $(CVSCO_RAPTOR) ns/base + $(CVSCO_RAPTOR) ns/dom + $(CVSCO_RAPTOR) ns/gfx + $(CVSCO_RAPTOR) ns/htmlparser + $(CVSCO_RAPTOR) ns/layout + $(CVSCO_RAPTOR) ns/view + $(CVSCO_RAPTOR) ns/webshell + $(CVSCO_RAPTOR) ns/widget diff --git a/mozilla/string/obsolete/nsString.cpp b/mozilla/string/obsolete/nsString.cpp new file mode 100644 index 00000000000..9f5ada26569 --- /dev/null +++ b/mozilla/string/obsolete/nsString.cpp @@ -0,0 +1,1979 @@ +/* -*- 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 +#include +#include +#include +#include "nsString.h" +#include "nsCRT.h" +#include "nsDebug.h" +#include "prprf.h" +#include "prdtoa.h" + + +const PRInt32 kGrowthDelta = 8; +const PRInt32 kNotFound = -1; +PRUnichar gBadChar = 0; +const char* kOutOfBoundsError = "Error: out of bounds"; +const char* kNullPointerError = "Error: unexpected null ptr"; + +//********************************************** +//NOTE: Our buffer always hold capacity+1 bytes. +//********************************************** + + +PRInt32 nsString::mInstanceCount=0; + +/**------------------------------------------------------- + * Default constructor + * + * @update gess 3/31/98 + * @param + * @return + *------------------------------------------------------*/ +nsString::nsString(const char* anISOLatin1/*=""*/) { + mLength=mCapacity=0; + mStr=0; + PRInt32 len=strlen(anISOLatin1); + EnsureCapacityFor(len); + this->SetString(anISOLatin1,len); + if(++mInstanceCount==1) + SelfTest(); +} + +/*------------------------------------------------------- + * constructor from string + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsString::nsString(const nsString &aString) { + mLength=mCapacity=0; + mStr=0; + EnsureCapacityFor(aString.mLength); + this->SetString(aString.mStr,aString.mLength); + if(++mInstanceCount==1) + SelfTest(); +} + +/*------------------------------------------------------- + * constructor from unicode string + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsString::nsString(const PRUnichar* aUnicodeStr){ + mLength=mCapacity=0; + mStr=0; + PRInt32 len=(aUnicodeStr) ? nsCRT::strlen(aUnicodeStr) : 0; + EnsureCapacityFor(len); + this->SetString(aUnicodeStr,len); + if(++mInstanceCount==1) + SelfTest(); +} + +/*------------------------------------------------------- + * standard destructor + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsString::~nsString() +{ + delete [] mStr; + mStr=0; + mCapacity=mLength=0; +} + +/*------------------------------------------------------- + * This method gets called when the internal buffer needs + * to grow to a given size. + * @update gess 3/30/98 + * @param aNewLength -- new capacity of string + * @return void + *------------------------------------------------------*/ +void nsString::EnsureCapacityFor(PRInt32 aNewLength) +{ + PRInt32 newCapacity; + + if (mCapacity > 64) { + // When the string starts getting large, double the capacity as we + // grow. + newCapacity = mCapacity * 2; + if (newCapacity < aNewLength) { + newCapacity = mCapacity + aNewLength; + } + } else { + // When the string is small, keep it's capacity a multiple of + // kGrowthDelta + PRInt32 size =aNewLength+kGrowthDelta; + newCapacity=size-(size % kGrowthDelta); + } + + if(mCapacity 0) { + nsCRT::memcpy(temp, mStr, mLength * sizeof(chartype)); + } + if(mStr) + delete [] mStr; + mStr = temp; + mStr[mLength]=0; + } +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +void nsString::SetLength(PRInt32 aLength) { +// NS_WARNING("Depricated method -- not longer required with dynamic strings. Use Truncate() instead."); + EnsureCapacityFor(aLength); + if (aLength > mLength) { + nsCRT::zero(mStr + mLength, (aLength - mLength) * sizeof(chartype)); + } + mLength=aLength; +} + +/*------------------------------------------------------- + * This method truncates this string to given length. + * + * @update gess 3/27/98 + * @param anIndex -- new length of string + * @return nada + *------------------------------------------------------*/ +void nsString::Truncate(PRInt32 anIndex) { + if((anIndex>-1) && (anIndex= 'A') && (ch <= 'Z')) { + *cp = 'a' + (ch - 'A'); + } + cp++; + } +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +void nsString::ToUpperCase() +{ + chartype* cp = mStr; + chartype* end = cp + mLength; + while (cp < end) { + chartype ch = *cp; + if ((ch >= 'a') && (ch <= 'z')) { + *cp = 'A' + (ch - 'a'); + } + cp++; + } +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +void nsString::ToLowerCase(nsString& aOut) const +{ + aOut.SetLength(mLength); + chartype* to = aOut.mStr; + chartype* from = mStr; + chartype* end = from + mLength; + while (from < end) { + chartype ch = *from++; + if ((ch >= 'A') && (ch <= 'Z')) { + ch = 'a' + (ch - 'A'); + } + *to++ = ch; + } + *to = 0; +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +void nsString::ToUpperCase(nsString& aOut) const +{ + aOut.SetLength(mLength); + chartype* to = aOut.mStr; + chartype* from = mStr; + chartype* end = from + mLength; + while (from < end) { + chartype ch = *from++; + if ((ch >= 'a') && (ch <= 'z')) { + ch = 'A' + (ch - 'a'); + } + *to++ = ch; + } + *to = 0; +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsString* nsString::ToNewString() const { + return new nsString(mStr); +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +char* nsString::ToNewCString() const +{ + char* rv = new char[mLength + 1]; + return ToCString(rv,mLength+1); +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRUnichar* nsString::ToNewUnicode() const +{ + PRInt32 len = mLength; + chartype* rv = new chartype[len + 1]; + chartype* to = rv; + chartype* from = mStr; + while (--len >= 0) { + *to++ = *from++; + } + *to++ = 0; + return rv; +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +void nsString::ToString(nsString& aString) const +{ + aString.SetLength(0); + aString.Append(mStr, mLength); +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +char* nsString::ToCString(char* aBuf, PRInt32 aBufLength) const +{ + aBufLength--; // leave room for the \0 + PRInt32 len = mLength; + if (len > aBufLength) { + len = aBufLength; + } + char* to = aBuf; + chartype* from = mStr; + while (--len >= 0) { + *to++ = char(*from++); + } + *to++ = '\0'; + return aBuf; +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +float nsString::ToFloat(PRInt32* aErrorCode) const +{ + char buf[40]; + if (mLength > sizeof(buf)-1) { + *aErrorCode = NS_ERROR_ILLEGAL_VALUE; + return 0.0f; + } + char* cp = ToCString(buf, sizeof(buf)); + float f = (float) PR_strtod(cp, &cp); + if (*cp != 0) { + *aErrorCode = NS_ERROR_ILLEGAL_VALUE; + } + return f; +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::ToInteger(PRInt32* aErrorCode) const { + PRInt32 rv = 0; + PRUnichar* cp = mStr; + PRUnichar* end = mStr + mLength; + + // Skip leading whitespace + while (cp < end) { + PRUnichar ch = *cp; + if (!IsSpace(ch)) { + break; + } + cp++; + } + if (cp == end) { + *aErrorCode = NS_ERROR_ILLEGAL_VALUE; + return rv; + } + + // Check for sign + PRUnichar sign = '+'; + if ((*cp == '+') || (*cp == '-')) { + sign = *cp++; + } + if (cp == end) { + *aErrorCode = NS_ERROR_ILLEGAL_VALUE; + return rv; + } + + // Convert the number + while (cp < end) { + PRUnichar ch = *cp++; + if ((ch < '0') || (ch > '9')) { + *aErrorCode = NS_ERROR_ILLEGAL_VALUE; + break; + } + rv = rv * 10 + (ch - '0'); + } + + if (sign == '-') { + rv = -rv; + } + return rv; +} + + +/*------------------------------------------------------- + * assign given string to this one + * @update gess 3/27/98 + * @param aString: string to be added to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator=(const nsString& aString) { + return this->SetString(aString.mStr,aString.mLength); +} + + +/*------------------------------------------------------- + * assign given char* to this string + * @update gess 3/27/98 + * @param anISOLatin1: buffer to be assigned to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator=(const char* anISOLatin1) { + return SetString(anISOLatin1); +} + + +/*------------------------------------------------------- + * assign given char to this string + * @update gess 3/27/98 + * @param aChar: char to be assignd to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator=(char aChar) { + return Append(PRUnichar(aChar)); +} + +/*------------------------------------------------------- + * assign given PRUnichar* to this string + * @update gess 3/27/98 + * @param anISOLatin1: buffer to be assigned to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::SetString(const PRUnichar* aStr,PRInt32 aLength) { + if(aStr!=0) { + PRInt32 len=(kNotFound==aLength) ? nsCRT::strlen(aStr) : aLength; + if(mCapacity< len ) + EnsureCapacityFor(len); + nsCRT::memcpy(mStr,aStr,len*sizeof(chartype)); + mLength=len; + mStr[mLength]=0; + } + else { + mLength=0; //This little bit of code handles the case + mStr[0]=0; //where some blockhead hands us a null string + } + return *this; +} + + +/*------------------------------------------------------- + * assign given char* to this string + * @update gess 3/27/98 + * @param anISOLatin1: buffer to be assigned to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::SetString(const char* anISOLatin1,PRInt32 aLength) { + if(anISOLatin1!=0) { + PRInt32 len=(kNotFound==aLength) ? nsCRT::strlen(anISOLatin1) : aLength; + if(mCapacitySetString(aStr); +} + + +/*------------------------------------------------------- + * assign given char to this string + * @update gess 3/27/98 + * @param aChar: char to be assignd to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator=(PRUnichar aChar) { + mLength=1; + if(mCapacity<1) + EnsureCapacityFor(kGrowthDelta); + mStr[0]=aChar; + mStr[1]=0; + return *this; +} + +/*------------------------------------------------------- + * append given string to this string + * @update gess 3/27/98 + * @param aString : string to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::Append(const nsString& aString,PRInt32 aLength) { + return Append(aString.mStr,aString.mLength); +} + +/*------------------------------------------------------- + * append given string to this string + * @update gess 3/27/98 + * @param aString : string to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::Append(const char* anISOLatin1,PRInt32 aLength) { + if(anISOLatin1!=0) { + PRInt32 len=(kNotFound==aLength) ? strlen(anISOLatin1) : aLength; + if(mLength+len > mCapacity) { + EnsureCapacityFor(mLength+len); + } + for(int i=0;i mCapacity) { + EnsureCapacityFor(mLength+len); + } + if(len>0) + nsCRT::memcpy(&mStr[mLength],aString,len*sizeof(chartype)); + mLength+=len; + mStr[mLength]=0; + } + return *this; +} + +/*------------------------------------------------------- + * append given string to this string + * @update gess 3/27/98 + * @param aString : string to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::Append(PRUnichar aChar) { + if(mLength < mCapacity) { + mStr[mLength++]=aChar; // the new string len < capacity, so just copy + mStr[mLength]=0; + } + else { // The new string exceeds our capacity + EnsureCapacityFor(mLength+1); + mStr[mLength++]=aChar; + mStr[mLength]=0; + } + return *this; +} + + +/*------------------------------------------------------- + * append given string to this string + * @update gess 3/27/98 + * @param aString : string to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator+=(const nsString &aString) { + return this->Append(aString.mStr,aString.mLength); +} + + +/*------------------------------------------------------- + * append given buffer to this string + * @update gess 3/27/98 + * @param anISOLatin1: buffer to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator+=(const char* anISOLatin1) { + return Append(anISOLatin1); +} + + +/*------------------------------------------------------- + * append given buffer to this string + * @update gess 3/27/98 + * @param aBuffer: buffer to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator+=(const PRUnichar* aBuffer) { + return Append(aBuffer); +} + + +/*------------------------------------------------------- + * append given char to this string + * @update gess 3/27/98 + * @param aChar: char to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator+=(PRUnichar aChar) { + return Append(aChar); +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsString& nsString::Append(PRInt32 aInteger,PRInt32 aRadix) { + char* fmt = "%d"; + if (8 == aRadix) { + fmt = "%o"; + } else if (16 == aRadix) { + fmt = "%x"; + } + char buf[40]; + PR_snprintf(buf, sizeof(buf), fmt, aInteger); + Append(buf); + return *this; +} + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsString& nsString::Append(float aFloat){ + char buf[40]; + PR_snprintf(buf, sizeof(buf), "%g", aFloat); + Append(buf); + return *this; +} + + + +/**------------------------------------------------------- + * Copies n characters from this string to given string, + * starting at the leftmost offset. + * + * + * @update gess 4/1/98 + * @param aCopy -- Receiving string + * @param aCount -- number of chars to copy + * @return number of chars copied + *------------------------------------------------------*/ +PRInt32 nsString::Left(nsString& aCopy,PRInt32 aCount) { + return Mid(aCopy,0,aCount); +} + +/**------------------------------------------------------- + * Copies n characters from this string to given string, + * starting at the given offset. + * + * + * @update gess 4/1/98 + * @param aCopy -- Receiving string + * @param aCount -- number of chars to copy + * @param anOffset -- position where copying begins + * @return number of chars copied + *------------------------------------------------------*/ +PRInt32 nsString::Mid(nsString& aCopy,PRInt32 anOffset,PRInt32 aCount) { + if(anOffsetaCopy.mLength) ? aCopy.mLength : aCount; //don't try to copy more than you are given + if(aCount>0) { + + //1st optimization: If you're inserting at end, then simply append! + if(anOffset>=mLength){ + Append(aCopy,aCopy.mLength); + return aCopy.mLength; + } + + if(mLength+aCount > mCapacity) { + EnsureCapacityFor(mLength+aCount); + } + + PRUnichar* last = mStr + mLength; + PRUnichar* first = mStr + anOffset-1; + PRUnichar* next = mStr + mLength + aCount; + + //Copy rightmost chars, up to offset+aCount... + while(first=0) && (anOffset= 'A') && (ch <= 'Z')) || ((ch >= 'a') && (ch <= 'z'))) { + return PR_TRUE; + } + return PR_FALSE; +} + +/**------------------------------------------------------- + * + * + * @update gess 3/31/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool nsString::IsSpace(PRUnichar ch) { + // XXX i18n + if ((ch == ' ') || (ch == '\r') || (ch == '\n') || (ch == '\t')) { + return PR_TRUE; + } + return PR_FALSE; +} + +/**------------------------------------------------------- + * This method trims characters found in aTrimSet from + * either end of the underlying string. + * + * @update gess 3/31/98 + * @param aTrimSet -- contains chars to be trimmed from + * both ends + * @return this + *------------------------------------------------------*/ +nsString& nsString::Trim(const char* aTrimSet, + PRBool aEliminateLeading, + PRBool aEliminateTrailing) +{ + PRUnichar* from = mStr; + PRUnichar* end = mStr + mLength-1; + PRUnichar* to = mStr; + + //begin by find the first char not in aTrimSet + if(aEliminateLeading) { + while (from < end) { + PRUnichar ch = *from; + if(!strchr(aTrimSet,char(ch))) { + break; + } + from++; + } + } + + //Now, find last char not in aTrimSet + if(aEliminateTrailing) { + while(end> from) { + PRUnichar ch = *end; + if(!strchr(aTrimSet,char(ch))) { + break; + } + end--; + } + } + + //now rewrite your string without unwanted + //leading or trailing characters. + while (from <= end) { + *to++ = *from++; + } + + *to = '\0'; + mLength = to - mStr; + return *this; +} + +/**------------------------------------------------------- + * + * + * @update gess 3/31/98 + * @param + * @return + *------------------------------------------------------*/ +nsString& nsString::CompressWhitespace( PRBool aEliminateLeading, + PRBool aEliminateTrailing) +{ + PRUnichar* from = mStr; + PRUnichar* end = mStr + mLength; + PRUnichar* to = from; + + Trim(" \r\n\t",aEliminateLeading,aEliminateTrailing); + + //this code converts /n, /t, /r into normal space ' '; + //it also eliminates runs of whitespace... + while (from < end) { + PRUnichar ch = *from++; + if (IsSpace(ch)) { + *to++ = ' '; + while (from < end) { + ch = *from++; + if (!IsSpace(ch)) { + *to++ = ch; + break; + } + } + } else { + *to++ = ch; + } + } + + *to = '\0'; + mLength = to - mStr; + return *this; +} + +/**------------------------------------------------------- + * XXX This is used by bina all over the place; not sure + * it belongs here though + * + * @update gess 3/31/98 + * @param + * @return + *------------------------------------------------------*/ +nsString& nsString::StripWhitespace() +{ + Trim(" \r\n\t"); + return StripChars("\r\t\n"); +} + + +/**------------------------------------------------------- + * Search for given buffer within this string + * + * @update gess 3/25/98 + * @param anISOLatin1Buf - charstr to be found + * @return offset in string, or -1 (kNotFound) + *------------------------------------------------------*/ +PRInt32 nsString::Find(const char* anISOLatin1Buf) const{ + NS_ASSERTION(0!=anISOLatin1Buf,kNullPointerError); + PRInt32 result=-1; + if(anISOLatin1Buf) { + PRInt32 len=strlen(anISOLatin1Buf); + if(len<=mLength) { //only enter if abuffer length is <= mStr length. + for(PRInt32 offset=0;offset0;i--){ + char* pos=strchr(anISOLatin1Set,char(mStr[i])); + if(pos) + return i; + } + } + return kNotFound; +} + +/**------------------------------------------------------- + * + * + * @update gess 3/25/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::FindLastCharInSet(nsString& aSet,PRInt32 anOffset) const{ + if(aSet.Length()) { + for(PRInt32 i=mLength-1;i>0;i--){ + PRInt32 pos=aSet.Find(mStr[i]); + if(kNotFound!=pos) + return i; + } + } + return kNotFound; +} + +/**------------------------------------------------------- + * + * + * @update gess 3/25/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::RFind(const PRUnichar* aString,PRBool aIgnoreCase) const{ + NS_ASSERTION(0!=aString,kNullPointerError); + + if(aString) { + PRInt32 len=nsCRT::strlen(aString); + if((len) && (len<=mLength)) { //only enter if abuffer length is <= mStr length. + for(PRInt32 offset=mLength-len;offset>=0;offset--) { + PRInt32 result=0; + if(aIgnoreCase) + result=nsCRT::strncasecmp(&mStr[offset],aString,len); + else result=nsCRT::strncmp(&mStr[offset],aString,len); + if(0==result) + return offset; //in this case, 0 means they match + } + } + } + return kNotFound; +} + +/**------------------------------------------------------- + * + * + * @update gess 3/25/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::RFind(const nsString& aString,PRBool aIgnoreCase) const{ + PRInt32 len=aString.mLength; + if((len) && (len<=mLength)) { //only enter if abuffer length is <= mStr length. + for(PRInt32 offset=mLength-len;offset>=0;offset--) { + PRInt32 result=0; + if(aIgnoreCase) + result=nsCRT::strncasecmp(&mStr[offset],aString.mStr,len); + else result=nsCRT::strncmp(&mStr[offset],aString.mStr,len); + if(0==result) + return offset; //in this case, 0 means they match + } + } + return kNotFound; +} + +/**------------------------------------------------------- + * + * + * @update gess 3/25/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::RFind(const char* anISOLatin1Set,PRBool aIgnoreCase) const{ + NS_ASSERTION(0!=anISOLatin1Set,kNullPointerError); + + if(anISOLatin1Set) { + PRInt32 len=strlen(anISOLatin1Set); + if((len) && (len<=mLength)) { //only enter if abuffer length is <= mStr length. + for(PRInt32 offset=mLength-len;offset>=0;offset--) { + PRInt32 result=0; + if(aIgnoreCase) + result=nsCRT::strncasecmp(&mStr[offset],anISOLatin1Set,len); + else result=nsCRT::strncmp(&mStr[offset],anISOLatin1Set,len); + if(0==result) + return offset; //in this case, 0 means they match + } + } + } + return kNotFound; +} + + +/**------------------------------------------------------- + * Scans this string backwards for first occurance of + * the given char. + * + * @update gess 3/25/98 + * @param + * @return offset of char in string, or -1 (kNotFound) + *------------------------------------------------------*/ +PRInt32 nsString::RFind(PRUnichar aChar,PRBool aIgnoreCase) const{ + chartype uc=nsCRT::ToUpper(aChar); + for(PRInt32 offset=mLength-1;offset>0;offset--) + if(aIgnoreCase) { + if(nsCRT::ToUpper(mStr[offset])==uc) + return offset; + } + else if(mStr[offset]==aChar) + return offset; //in this case, 0 means they match + return kNotFound; + +} + + //****** comparision methods... ******* + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::Compare(const char *anISOLatin1,PRBool aIgnoreCase) const { + if (aIgnoreCase) { + return nsCRT::strcasecmp(mStr,anISOLatin1); + } + return nsCRT::strcmp(mStr,anISOLatin1); +} + +/*------------------------------------------------------- + * LAST MODS: gess + * + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::Compare(const nsString &S,PRBool aIgnoreCase) const { + if (aIgnoreCase) { + return nsCRT::strcasecmp(mStr,S.mStr); + } + return nsCRT::strcmp(mStr,S.mStr); +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::Compare(const PRUnichar* aString,PRBool aIgnoreCase) const { + if (aIgnoreCase) { + return nsCRT::strcasecmp(mStr,aString); + } + return nsCRT::strcmp(mStr,aString); +} + + +PRInt32 nsString::operator==(const nsString &S) const {return Compare(S)==0;} +PRInt32 nsString::operator==(const char *s) const {return Compare(s)==0;} +PRInt32 nsString::operator==(const PRUnichar *s) const {return Compare(s)==0;} +PRInt32 nsString::operator!=(const nsString &S) const {return Compare(S)!=0;} +PRInt32 nsString::operator!=(const char *s ) const {return Compare(s)!=0;} +PRInt32 nsString::operator!=(const PRUnichar *s) const {return Compare(s)==0;} +PRInt32 nsString::operator<(const nsString &S) const {return Compare(S)<0;} +PRInt32 nsString::operator<(const char *s) const {return Compare(s)<0;} +PRInt32 nsString::operator<(const PRUnichar *s) const {return Compare(s)==0;} +PRInt32 nsString::operator>(const nsString &S) const {return Compare(S)>0;} +PRInt32 nsString::operator>(const char *s) const {return Compare(s)>0;} +PRInt32 nsString::operator>(const PRUnichar *s) const {return Compare(s)==0;} +PRInt32 nsString::operator<=(const nsString &S) const {return Compare(S)<=0;} +PRInt32 nsString::operator<=(const char *s) const {return Compare(s)<=0;} +PRInt32 nsString::operator<=(const PRUnichar *s) const {return Compare(s)==0;} +PRInt32 nsString::operator>=(const nsString &S) const {return Compare(S)>=0;} +PRInt32 nsString::operator>=(const char *s) const {return Compare(s)>=0;} +PRInt32 nsString::operator>=(const PRUnichar *s) const {return Compare(s)==0;} + + + +/*------------------------------------------------------- + * Compare this to given string + * @update gess 3/27/98 + * @param aString -- string to compare to this + * @return TRUE if equal + *------------------------------------------------------*/ +PRBool nsString::Equals(const nsString& aString) const { + PRInt32 result=nsCRT::strcmp(mStr,aString.mStr); + return PRBool(0==result); +} + + +/*------------------------------------------------------- + * Compare this to given string + * @update gess 3/27/98 + * @param aCString -- Cstr to compare to this + * @return TRUE if equal + *------------------------------------------------------*/ +PRBool nsString::Equals(const char* aCString) const{ + NS_ASSERTION(0!=aCString,kNullPointerError); + PRInt32 result=nsCRT::strcmp(mStr,aCString); + return PRBool(0==result); +} + + +/*------------------------------------------------------- + * Compare this to given atom + * @update gess 3/27/98 + * @param aAtom -- atom to compare to this + * @return TRUE if equal + *------------------------------------------------------*/ +PRBool nsString::Equals(const nsIAtom* aAtom) const +{ + NS_ASSERTION(0!=aAtom,kNullPointerError); + PRInt32 result=nsCRT::strcmp(mStr,aAtom->GetUnicode()); + return PRBool(0==result); +} + + +/*------------------------------------------------------- + * Compare given strings + * @update gess 3/27/98 + * @param s1 -- first string to be compared + * @param s2 -- second string to be compared + * @return TRUE if equal + *------------------------------------------------------*/ +PRBool nsString::Equals(const PRUnichar* s1, const PRUnichar* s2) const { + NS_ASSERTION(0!=s1,kNullPointerError); + NS_ASSERTION(0!=s2,kNullPointerError); + PRBool result=PR_FALSE; + if((s1) && (s2)){ + PRInt32 cmp=nsCRT::strcmp(s1,s2); + result=PRBool(0==cmp); + } + return result; +} + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool nsString::EqualsIgnoreCase(const nsString& aString) const{ + PRInt32 result=nsCRT::strcasecmp(mStr,aString.mStr); + return PRBool(0==result); +} + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool nsString::EqualsIgnoreCase(const nsIAtom *aAtom) const{ + NS_ASSERTION(0!=aAtom,kNullPointerError); + PRBool result=PR_FALSE; + if(aAtom){ + PRInt32 cmp=nsCRT::strcasecmp(mStr,aAtom->GetUnicode()); + result=PRBool(0==cmp); + } + return result; +} + + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool nsString::EqualsIgnoreCase(const PRUnichar* s1, const PRUnichar* s2) const { + NS_ASSERTION(0!=s1,kNullPointerError); + NS_ASSERTION(0!=s2,kNullPointerError); + PRBool result=PR_FALSE; + if((s1) && (s2)){ + PRInt32 cmp=nsCRT::strcasecmp(s1,s2); + result=PRBool(0==cmp); + } + return result; +} + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool nsString::EqualsIgnoreCase(const char* aCString) const { + NS_ASSERTION(0!=aCString,kNullPointerError); + PRBool result=PR_FALSE; + if(aCString){ + PRInt32 cmp=nsCRT::strcasecmp(mStr,aCString); + result=PRBool(0==cmp); + } + return result; +} + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +void nsString::DebugDump(ostream& aStream) const { + for(int i=0;itemp3.Length(),"constructor error!"); //should be char longer + + nsString* es1=temp2.ToNewString(); //this should make us a new string + char* es2=temp2.ToNewCString(); + for(i=0;itemp8,"Error: Comparision (>) routine"); + NS_ASSERTION(temp9>aaaa,"Error: Comparision (>) routine"); + + NS_ASSERTION(temp8<=temp8,"Error: Comparision (<=) routine"); + NS_ASSERTION(temp8<=temp9,"Error: Comparision (<=) routine"); + NS_ASSERTION(temp8<=bbbb,"Error: Comparision (<=) routine"); + + NS_ASSERTION(temp9>=temp9,"Error: Comparision (<=) routine"); + NS_ASSERTION(temp9>=temp8,"Error: Comparision (<=) routine"); + NS_ASSERTION(temp9>=aaaa,"Error: Comparision (<=) routine"); + + NS_ASSERTION(temp8.Equals(temp8),"Equals error"); + NS_ASSERTION(temp8.Equals(aaaa),"Equals error"); + + nsString temp10(temp8); + temp10.ToUpperCase(); + NS_ASSERTION(temp8.EqualsIgnoreCase(temp10),"Equals error"); + NS_ASSERTION(temp8.EqualsIgnoreCase("AAAA"),"Equals error"); + + + //********************************************** + //Now let's test a few string MANIPULATORS... + //********************************************** + + nsAutoString ab("ab"); + nsString abcde("cde"); + abcde.Insert(ab,0,2); + nsAutoString xxx("xxx"); + abcde.Insert(xxx,2,3); + + temp2.ToUpperCase(); + for(i=0;i mCapacity) { + PRInt32 size = mCapacity * 2; + if (size < aNewLength) { + size = mCapacity + aNewLength; + } + mCapacity=size; + chartype* temp = new chartype[mCapacity+1]; + if (mLength > 0) { + nsCRT::memcpy(temp, mStr, mLength * sizeof(chartype)); + } + mStr = temp; + } +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsAutoString::nsAutoString(const PRUnichar* unicode, PRInt32 uslen) { + mStr = mBuf; + mCapacity = sizeof(mBuf) / sizeof(chartype); + if (0 == uslen) { + uslen = nsCRT::strlen(unicode); + } + Append(unicode, uslen); +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsAutoString::~nsAutoString() +{ + if (mStr == mBuf) { + // Force to null so that baseclass dtor doesn't do damage + mStr = nsnull; + } +} + + +/**------------------------------------------------------- + * + * + * @update gess 3/31/98 + * @param + * @return + *------------------------------------------------------*/ +void nsAutoString::SelfTest(){ + nsAutoString xas("Hello there"); + xas.Append("this string exceeds the max size"); + xas.DebugDump(cout); +} + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +NS_BASE int fputs(const nsString& aString, FILE* out) +{ + char buf[100]; + char* cp = buf; + PRInt32 len = aString.Length(); + if (len >= sizeof(buf)) { + cp = aString.ToNewCString(); + } else { + aString.ToCString(cp, len + 1); + } + ::fwrite(cp, 1, len, out); + if (cp != buf) { + delete cp; + } + return (int) len; +} + diff --git a/mozilla/string/obsolete/nsString.h b/mozilla/string/obsolete/nsString.h new file mode 100644 index 00000000000..dc26545c53b --- /dev/null +++ b/mozilla/string/obsolete/nsString.h @@ -0,0 +1,233 @@ +/* -*- 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. + */ + +/** + * MODULE NOTES: + * LAST MODS: gess 28Feb98 + * + * This very simple string class that knows how to do + * efficient (dynamic) resizing. It offers almost no + * i18n support, and will undoubtedly have to be replaced. + * + */ + +#ifndef _NSSTRING +#define _NSSTRING + + +#include "prtypes.h" +#include "nscore.h" +#include "nsIAtom.h" +#include +#include + + +class NS_BASE nsString { + public: + + nsString(const char* anISOLatin1=""); + nsString(const nsString&); + nsString(const PRUnichar* aUnicode); + virtual ~nsString(); + + PRInt32 Length() const { return mLength; } + + void SetLength(PRInt32 aLength); + void Truncate(PRInt32 anIndex=0); + virtual void EnsureCapacityFor(PRInt32 aNewLength); + + ///accessor methods + //@{ + PRUnichar* GetUnicode(void) const; + operator PRUnichar*() const; + +#if 0 + // This is NOT allowed because it has to do a malloc to + // create the iso-latin-1 version of the unicode string + operator char*() const; +#endif + + PRUnichar* operator()() const; + PRUnichar operator()(PRInt32 i) const; + PRUnichar& operator[](PRInt32 i) const; + PRUnichar& CharAt(PRInt32 anIndex) const; + PRUnichar& First() const; + PRUnichar& Last() const; + + //string creation methods... + nsString operator+(const nsString& aString); + nsString operator+(const char* anISOLatin1); + nsString operator+(char aChar); + nsString operator+(const PRUnichar* aBuffer); + nsString operator+(PRUnichar aChar); + + void ToLowerCase(); + void ToLowerCase(nsString& aString) const; + void ToUpperCase(); + void ToUpperCase(nsString& aString) const; + + nsString* ToNewString() const; + char* ToNewCString() const; + + char* ToCString(char* aBuf,PRInt32 aBufLength) const; + void ToString(nsString& aString) const; + + PRUnichar* ToNewUnicode() const; + float ToFloat(PRInt32* aErrorCode) const; + PRInt32 ToInteger(PRInt32* aErrorCode) const; + //@} + + ///string manipulation methods... + //@{ + nsString& operator=(const nsString& aString); + nsString& operator=(const char* anISOLatin1); + nsString& operator=(char aChar); + nsString& operator=(const PRUnichar* aBuffer); + nsString& operator=(PRUnichar aChar); + nsString& SetString(const PRUnichar* aStr,PRInt32 aLength=-1); + nsString& SetString(const char* anISOLatin1,PRInt32 aLength=-1); + + nsString& operator+=(const nsString& aString); + nsString& operator+=(const char* anISOLatin1); + nsString& operator+=(const PRUnichar* aBuffer); + nsString& operator+=(PRUnichar aChar); + nsString& Append(const nsString& aString,PRInt32 aLength=-1); + nsString& Append(const char* anISOLatin1,PRInt32 aLength=-1); + nsString& Append(char aChar); + nsString& Append(const PRUnichar* aBuffer,PRInt32 aLength=-1); + nsString& Append(PRUnichar aChar); + nsString& Append(PRInt32 aInteger,PRInt32 aRadix); //radix=8,10 or 16 + nsString& Append(float aFloat); + + PRInt32 Left(nsString& aCopy,PRInt32 aCount); + PRInt32 Mid(nsString& aCopy,PRInt32 anOffset,PRInt32 aCount); + PRInt32 Right(nsString& aCopy,PRInt32 aCount); + PRInt32 Insert(nsString& aCopy,PRInt32 anOffset,PRInt32 aCount=-1); + + nsString& Cut(PRInt32 anOffset,PRInt32 aCount); + nsString& StripChars(const char* aSet); + nsString& StripWhitespace(); + nsString& Trim( const char* aSet, + PRBool aEliminateLeading=PR_TRUE, + PRBool aEliminateTrailing=PR_TRUE); + nsString& CompressWhitespace( PRBool aEliminateLeading=PR_TRUE, + PRBool aEliminateTrailing=PR_TRUE); + static PRBool IsSpace(PRUnichar ch); + static PRBool IsAlpha(PRUnichar ch); + //@} + + ///searching methods... + //@{ + PRInt32 Find(const char* anISOLatin1) const; + PRInt32 Find(const PRUnichar* aString) const; + PRInt32 Find(PRUnichar aChar,PRInt32 offset=0) const; + PRInt32 Find(const nsString& aString) const; + PRInt32 FindFirstCharInSet(const char* anISOLatin1Set,PRInt32 offset=0) const; + PRInt32 FindFirstCharInSet(nsString& aString,PRInt32 offset=0) const; + PRInt32 FindLastCharInSet(const char* anISOLatin1Set,PRInt32 offset=0) const; + PRInt32 FindLastCharInSet(nsString& aString,PRInt32 offset=0) const; + PRInt32 RFind(const char* anISOLatin1,PRBool aIgnoreCase=PR_FALSE) const; + PRInt32 RFind(const PRUnichar* aString,PRBool aIgnoreCase=PR_FALSE) const; + PRInt32 RFind(const nsString& aString,PRBool aIgnoreCase=PR_FALSE) const; + PRInt32 RFind(PRUnichar aChar,PRBool aIgnoreCase=PR_FALSE) const; + //@} + + ///comparision methods... + //@{ + virtual PRInt32 Compare(const nsString &S,PRBool aIgnoreCase=PR_FALSE) const; + virtual PRInt32 Compare(const char *anISOLatin1,PRBool aIgnoreCase=PR_FALSE) const; + virtual PRInt32 Compare(const PRUnichar *aString,PRBool aIgnoreCase=PR_FALSE) const; + + PRInt32 operator==(const nsString &S) const; + PRInt32 operator==(const char *anISOLatin1) const; + PRInt32 operator==(const PRUnichar* aString) const; + PRInt32 operator!=(const nsString &S) const; + PRInt32 operator!=(const char *anISOLatin1) const; + PRInt32 operator!=(const PRUnichar* aString) const; + PRInt32 operator<(const nsString &S) const; + PRInt32 operator<(const char *anISOLatin1) const; + PRInt32 operator<(const PRUnichar* aString) const; + PRInt32 operator>(const nsString &S) const; + PRInt32 operator>(const char *anISOLatin1) const; + PRInt32 operator>(const PRUnichar* aString) const; + PRInt32 operator<=(const nsString &S) const; + PRInt32 operator<=(const char *anISOLatin1) const; + PRInt32 operator<=(const PRUnichar* aString) const; + PRInt32 operator>=(const nsString &S) const; + PRInt32 operator>=(const char *anISOLatin1) const; + PRInt32 operator>=(const PRUnichar* aString) const; + + PRBool Equals(const nsString& aString) const; + PRBool Equals(const char* anISOLatin1) const; + PRBool Equals(const nsIAtom *aAtom) const; + PRBool Equals(const PRUnichar* s1, const PRUnichar* s2) const; + + PRBool EqualsIgnoreCase(const nsString& aString) const; + PRBool EqualsIgnoreCase(const char* anISOLatin1) const; + PRBool EqualsIgnoreCase(const nsIAtom *aAtom) const; + PRBool EqualsIgnoreCase(const PRUnichar* s1, const PRUnichar* s2) const; + //@} + + static void SelfTest(); + virtual void DebugDump(ostream& aStream) const; + + protected: + +typedef PRUnichar chartype; + + chartype* mStr; + PRInt32 mLength; + PRInt32 mCapacity; + static PRInt32 mInstanceCount; +}; + +extern NS_BASE int fputs(const nsString& aString, FILE* out); + +//---------------------------------------------------------------------- + +/** + * A version of nsString which is designed to be used as an automatic + * variable. It attempts to operate out of a fixed size internal + * buffer until too much data is added; then a dynamic buffer is + * allocated and grown as necessary. + */ +// XXX template this with a parameter for the size of the buffer? +class NS_BASE nsAutoString : public nsString { +public: + nsAutoString(); + nsAutoString(const nsString& other); + nsAutoString(const nsAutoString& other); + nsAutoString(PRUnichar aChar); + nsAutoString(const char* isolatin1); + nsAutoString(const PRUnichar* us, PRInt32 uslen = -1); + virtual ~nsAutoString(); + + static void SelfTest(); + +protected: + virtual void EnsureCapacityFor(PRInt32 aNewLength); + + PRUnichar mBuf[32]; + +private: + // XXX these need writing I suppose + nsAutoString& operator=(const nsAutoString& other); +}; + +#endif + diff --git a/mozilla/view/Makefile b/mozilla/view/Makefile new file mode 100644 index 00000000000..4d3b4d1d871 --- /dev/null +++ b/mozilla/view/Makefile @@ -0,0 +1,24 @@ +#!gmake +# +# 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. + +DEPTH = .. + +include $(DEPTH)/config/config.mk + +DIRS = public src + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/view/makefile.win b/mozilla/view/makefile.win new file mode 100644 index 00000000000..f1e7ad71a77 --- /dev/null +++ b/mozilla/view/makefile.win @@ -0,0 +1,23 @@ +#!nmake +# +# 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. + +DEPTH=.. +IGNORE_MANIFEST=1 + +DIRS=public src + +include <$(DEPTH)\config\rules.mak> diff --git a/mozilla/view/public/Makefile b/mozilla/view/public/Makefile new file mode 100644 index 00000000000..1392e07964a --- /dev/null +++ b/mozilla/view/public/Makefile @@ -0,0 +1,33 @@ +#!gmake +# +# 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. + +DEPTH=../.. + +DEFINES = -D_IMPL_NS_UI + +EXPORTS = \ + nsIView.h \ + nsIViewManager.h \ + nsIScrollableView.h \ + nsViewsCID.h \ + $(NULL) + +MODULE = raptor + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/view/public/makefile.win b/mozilla/view/public/makefile.win new file mode 100644 index 00000000000..0e95c6a478f --- /dev/null +++ b/mozilla/view/public/makefile.win @@ -0,0 +1,26 @@ +#!nmake +# +# 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. + +DEPTH=..\.. +IGNORE_MANIFEST=1 + +DEFINES=-D_IMPL_NS_UI +EXPORTS=nsIView.h nsIViewManager.h nsIScrollableView.h nsViewsCID.h +MODULE=raptor + +include <$(DEPTH)\config\rules.mak> + diff --git a/mozilla/view/public/nsIScrollableView.h b/mozilla/view/public/nsIScrollableView.h new file mode 100644 index 00000000000..f797c570e04 --- /dev/null +++ b/mozilla/view/public/nsIScrollableView.h @@ -0,0 +1,41 @@ +/* -*- 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. + */ + +#ifndef nsIScrollableView_h___ +#define nsIScrollableView_h___ + +#include "nsISupports.h" + +// IID for the nsIView interface +#define NS_ISCROLLABLEVIEW_IID \ +{ 0xc95f1830, 0xc376, 0x11d1, \ +{ 0xb7, 0x21, 0x0, 0x60, 0x8, 0x91, 0xd8, 0xc9 } } + +class nsIScrollableView : public nsISupports +{ +public: + + virtual void SetContainerSize(PRInt32 aSize) = 0; + virtual PRInt32 GetContainerSize(void) = 0; + + virtual void SetVisibleOffset(PRInt32 aOffset) = 0; + virtual PRInt32 GetVisibleOffset(void) = 0; + +}; + +#endif diff --git a/mozilla/view/public/nsIView.h b/mozilla/view/public/nsIView.h new file mode 100644 index 00000000000..3b28f34ae46 --- /dev/null +++ b/mozilla/view/public/nsIView.h @@ -0,0 +1,175 @@ +/* -*- 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. + */ + +#ifndef nsIView_h___ +#define nsIView_h___ + +#include +#include "nsISupports.h" +#include "nsCoord.h" +#include "nsIWidget.h" +#include "nsGUIEvent.h" + +class nsIViewManager; +class nsRegion; +class nsIRenderingContext; +class nsTransform2D; +class nsIFrame; +struct nsRect; + +// Enumerated type to indicate the visibility of a layer. +// hide - the layer is not shown. +// show - the layer is shown irrespective of the visibility of +// the layer's parent. +// inherit - the layer inherits its visibility from its parent. +typedef enum +{ + nsViewVisibility_kHide = 0, + nsViewVisibility_kShow = 1, + nsViewVisibility_kInherit = 2 +} nsViewVisibility; + +// IID for the nsIView interface +#define NS_IVIEW_IID \ +{ 0xf0a21c40, 0xa7e1, 0x11d1, \ +{ 0xa8, 0x24, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9 } } + +//---------------------------------------------------------------------- + +// View interface + +// Note that nsIView does not support reference counting; view object +// have their lifetime bound to the view manager that contains them. +class nsIView : public nsISupports +{ +public: + virtual nsresult Init(nsIViewManager* aManager, + const nsRect &aBounds, + nsIView *aParent, + const nsIID *aWindowIID = nsnull, + nsNativeWindow aNative = nsnull, + PRInt32 aZIndex = 0, + const nsRect *aClipRect = nsnull, + float aOpacity = 1.0f, + nsViewVisibility aVisibilityFlag = nsViewVisibility_kShow) = 0; + + virtual void Destroy() = 0; + + virtual nsIViewManager * GetViewManager() = 0; + + // In 4.0, the "cutout" nature of a layer is queryable. + // If we believe that all cutout layers have a native widget, this + // could be a replacement. + virtual nsIWidget * GetWidget() = 0; + + // Called to indicate that the specified region of the layer + // needs to be drawn via the rendering context. The region + // is specified in layer coordinates. + virtual void Paint(nsIRenderingContext& rc, const nsRect& rect) = 0; + virtual void Paint(nsIRenderingContext& rc, const nsRegion& region) = 0; + + // Called to indicate that the specified event should be handled + // by the layer. This method should return nsEventStatus_eConsumeDoDefault or nsEventStatus_eConsumeNoDefault if the event has been + // handled. + virtual nsEventStatus HandleEvent(nsGUIEvent *event, PRBool aCheckParent = PR_TRUE, PRBool aCheckChildren = PR_TRUE) = 0; + + // Called to indicate that the position of the layer has been changed. + // The specified coordinates are in the parent layer's coordinate space. + virtual void SetPosition(nscoord x, nscoord y) = 0; + virtual void GetPosition(nscoord *x, nscoord *y) = 0; + + // Called to indicate that the dimensions of the layer (actually the + // width and height of the clip) have been changed. + virtual void SetDimensions(nscoord width, nscoord height) = 0; + virtual void GetDimensions(nscoord *width, nscoord *height) = 0; + + // Called to indicate that the dimensions of the layer (actually the + // width and height of the clip) have been changed. + virtual void SetBounds(const nsRect &aBounds) = 0; + virtual void SetBounds(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) = 0; + virtual void GetBounds(nsRect &aBounds) = 0; + + // Called to indicate that the clip of the layer has been changed. + // The clip is relative to the origin of the layer. + virtual void SetClip(const nsRect &aClip) = 0; + virtual void SetClip(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) = 0; + virtual PRBool GetClip(nsRect *aClip) = 0; + + // Called to indicate that the visibility of a layer has been + // changed. + virtual void SetVisibility(nsViewVisibility visibility) = 0; + virtual nsViewVisibility GetVisibility() = 0; + + // Called to indicate that the z-index of a layer has been changed. + // The z-index is relative to all siblings of the layer. + virtual void SetZIndex(PRInt32 zindex) = 0; + virtual PRInt32 GetZIndex() = 0; + + // Called to set the parent of the layer. + virtual void SetParent(nsIView *aParent) = 0; + virtual nsIView *GetParent() = 0; + + // Sibling pointer used to link together views + virtual nsIView* GetNextSibling() const = 0; + virtual void SetNextSibling(nsIView* aNextSibling) = 0; + + // Used to insert a child after the specified sibling. In general, + // child insertion will happen through the layer manager and it + // will determine the ordering of children in the child list. + virtual void InsertChild(nsIView *child, nsIView *sibling) = 0; + + // Remove a child from the child list. Again, the removal will driven + // through the layer manager. + virtual void RemoveChild(nsIView *child) = 0; + + // Get the number of children for this layer. + virtual PRInt32 GetChildCount() = 0; + + // Get a child at a specific index. Could be replaced by some sort of + // enumeration API. + virtual nsIView * GetChild(PRInt32 index) = 0; + + // Note: This didn't exist in 4.0. This transform might include scaling + // but probably not rotation for the first pass. + virtual void SetTransform(nsTransform2D *transform) = 0; + virtual nsTransform2D * GetTransform() = 0; + + // Note: This didn't exist in 4.0. Called to set the opacity of a layer. + // A value of 0.0 means completely transparent. A value of 1.0 means + // completely opaque. + virtual void SetOpacity(float opacity) = 0; + virtual float GetOpacity() = 0; + + // Used to ask a layer if it has any areas within its bounding box + // that are transparent. This is not the same as opacity - opacity can + // be set externally, transparency is a quality of the layer itself. + // Returns true if there are transparent areas, false otherwise. + virtual PRBool HasTransparency() = 0; + + //this is the link to the content world for this view + virtual void SetFrame(nsIFrame *aFrame) = 0; + virtual nsIFrame * GetFrame() = 0; + + //move child widgets around by (dx, dy). deltas are in widget + //coordinate space. + virtual void AdjustChildWidgets(nscoord aDx, nscoord aDy) = 0; + + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const = 0; +}; + +#endif diff --git a/mozilla/view/public/nsIViewManager.h b/mozilla/view/public/nsIViewManager.h new file mode 100644 index 00000000000..8d034634f3c --- /dev/null +++ b/mozilla/view/public/nsIViewManager.h @@ -0,0 +1,176 @@ +/* -*- 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. + */ + +#ifndef nsIViewManager_h___ +#define nsIViewManager_h___ + +#include "nscore.h" +#include "nsISupports.h" +#include "nsCoord.h" +#include "nsIView.h" +class nsRegion; +class nsIEvent; +class nsIPresContext; +class nsIView; +class nsIWidget; +struct nsRect; + +#define NS_IVIEWMANAGER_IID \ +{ 0x3a8863d0, 0xa7f3, 0x11d1, \ + { 0xa8, 0x24, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9 } } + +class nsIViewManager : public nsISupports +{ +public: + // Note: this instance does not hold a reference to the presentation + // context because it holds a reference to this instance. + virtual nsresult Init(nsIPresContext* aPresContext) = 0; + + // Get the window for which the manager is responsible. + virtual void SetRootWindow(nsIWidget *aRootWindow) = 0; + virtual nsIWidget *GetRootWindow() = 0; + + // Get and set the root of the layer tree. + virtual nsIView *GetRootView() = 0; + virtual void SetRootView(nsIView *aView) = 0; + + // Get and set the current framerate i.e. the rate at which timed + // refreshes occur. A framerate of 0 indicates that timed refreshes + // should not occur. framerate is in terms of frames per second + virtual PRUint32 GetFrameRate() = 0; + virtual nsresult SetFrameRate(PRUint32 frameRate) = 0; + + // Get and set the dimensions of the root window. The latter should + // be called if the root window is resized.. The dimensions are in + // twips + virtual void GetWindowDimensions(nscoord *width, nscoord *height) = 0; + virtual void SetWindowDimensions(nscoord width, nscoord height) = 0; + + // Get and set the position of the root window relative to the + // composited area. The latter should be called if the root window + // is scrolled. + virtual void GetWindowOffsets(nscoord *xoffset, nscoord *yoffset) = 0; + virtual void SetWindowOffsets(nscoord xoffset, nscoord yoffset) = 0; + + // Called to refresh an area of the root window. The coordinates of + // the region or rectangle passed in should be in the window's + // coordinate space (pixels). Often called in response to a + // paint/redraw event from the native windowing system. + virtual void Refresh(nsIRenderingContext *aContext, nsRegion *region, + PRUint32 aUpdateFlags) = 0; + virtual void Refresh(nsIView* aView, nsIRenderingContext *aContext, + nsRect *rect, PRUint32 aUpdateFlags) = 0; + + // Called to force a redrawing of any dirty areas. + virtual void Composite() = 0; + + // Called to inform the layer manager that some portion of a layer + // is dirty and needs to be redrawn. The region or rect passed in + // should be in the layer's coordinate space. + virtual void UpdateView(nsIView *aView, nsRegion *region, + PRUint32 aUpdateFlags) = 0; + virtual void UpdateView(nsIView *aView, nsRect *rect, PRUint32 aUpdateFlags) = 0; + + // Called to dispatch an event to the appropriate layer. Often called + // as a result of receiving a mouse or keyboard event from the native + // event system. + virtual PRBool DispatchEvent(nsIEvent *event) = 0; + + // Used to grab/capture all events of the type (mouse or keyboard) for + // a specific layer, irrespective of the cursor position at which the + // event occurred. + virtual PRBool GrabMouseEvents(nsIView *aView) = 0; + virtual PRBool GrabKeyEvents(nsIView *aView) = 0; + + // Get the current layer, if any, that's capturing a specific type of + // event. + virtual nsIView* GetMouseEventGrabber() = 0; + virtual nsIView* GetKeyEventGrabber() = 0; + + // Given a parent layer, insert another layer as its child. If above + // is nstrue, the layer is inserted above (in z-order) the sibling. If + // it is nsfalse, the layer is inserted below. + // The layer manager generates the appopriate dirty regions. + virtual void InsertChild(nsIView *parent, nsIView *child, nsIView *sibling, + PRBool above) = 0; + + // Given a parent layer, insert another layer as its child. The zindex + // indicates where the child should be inserted relative to other + // children of the parent. + // The layer manager generates the appopriate dirty regions. + virtual void InsertChild(nsIView *parent, nsIView *child, + PRInt32 zindex) = 0; + + // Remove a specific child of a layer. + // The layer manager generates the appopriate dirty regions. + virtual void RemoveChild(nsIView *parent, nsIView *child) = 0; + + // Move a layer's position by the specified amount. + // The layer manager generates the appopriate dirty regions. + virtual void MoveViewBy(nsIView *aView, nscoord x, nscoord y) = 0; + + // Move a layer to the specified position, provided in parent coordinates. + // The layer manager generates the appopriate dirty regions. + virtual void MoveViewTo(nsIView *aView, nscoord x, nscoord y) = 0; + + // Resize a layer to the specified width and height. + // The layer manager generates the appopriate dirty regions. + virtual void ResizeView(nsIView *aView, nscoord width, nscoord height) = 0; + + // Set the clip of a layer. + // The layer manager generates the appopriate dirty regions. + virtual void SetViewClip(nsIView *aView, nsRect *rect) = 0; + + // Set the visibility of a layer. + // The layer manager generates the appopriate dirty regions. + virtual void SetViewVisibility(nsIView *aView, nsViewVisibility visible) = 0; + + // Set the z-index of a layer. Positive z-indices mean that a layer + // is above its parent in z-order. Negative z-indices mean that a + // layer is below its parent. + // The layer manager generates the appopriate dirty regions. + virtual void SetViewZindex(nsIView *aView, PRInt32 zindex) = 0; + + // Used to move a layer above or below another in z-order. + // The layer manager generates the appopriate dirty regions. + virtual void MoveViewAbove(nsIView *aView, nsIView *other) = 0; + virtual void MoveViewBelow(nsIView *aView, nsIView *other) = 0; + + // Returns whether a layer is actually shown (based on its visibility + // and that of its ancestors). + virtual PRBool IsViewShown(nsIView *aView) = 0; + + // Returns the clipping area of layer in absolute coordinates. + virtual PRBool GetViewClipAbsolute(nsIView *aView, nsRect *rect) = 0; + + // Get the presentation context associated with this manager + virtual nsIPresContext* GetPresContext() = 0; + + // Set the area that the view manager considers to be "dirty" + // to an empty state + virtual void ClearDirtyRegion() = 0; +}; + +//when the refresh happens, should it be double buffered? +#define NS_VMREFRESH_DOUBLE_BUFFER 0x0001 +//is the damagerect in top-level window space? +#define NS_VMREFRESH_SCREEN_RECT 0x0002 +//update view now? +#define NS_VMREFRESH_IMMEDIATE 0x0004 + +#endif // nsIViewManager_h___ diff --git a/mozilla/view/public/nsViewsCID.h b/mozilla/view/public/nsViewsCID.h new file mode 100644 index 00000000000..99c792a5990 --- /dev/null +++ b/mozilla/view/public/nsViewsCID.h @@ -0,0 +1,38 @@ +/* -*- 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. + */ + +#ifndef nsViewsCID_h__ +#define nsViewsCID_h__ + +#include "nsISupports.h" +#include "nsIFactory.h" +#include "nsRepository.h" + +#define NS_VIEW_MANAGER_CID \ +{ 0xc95f1831, 0xc376, 0x11d1, \ + {0xb7, 0x21, 0x0, 0x60, 0x8, 0x91, 0xd8, 0xc9}} + +#define NS_VIEW_CID \ +{ 0xc95f1832, 0xc376, 0x11d1, \ + {0xb7, 0x21, 0x0, 0x60, 0x8, 0x91, 0xd8, 0xc9}} + +#define NS_SCROLLING_VIEW_CID \ +{ 0xc95f1833, 0xc376, 0x11d1, \ + {0xb7, 0x21, 0x0, 0x60, 0x8, 0x91, 0xd8, 0xc9}} + +#endif // nsViewsCID_h__ \ No newline at end of file diff --git a/mozilla/view/src/Makefile b/mozilla/view/src/Makefile new file mode 100644 index 00000000000..2fd4b5a8504 --- /dev/null +++ b/mozilla/view/src/Makefile @@ -0,0 +1,41 @@ +#!gmake +# +# 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. + +DEPTH = ../.. + +include $(DEPTH)/config/config.mk + +MODULE=raptor + +LIBRARY_NAME=raptorview + +CPPSRCS = \ + nsView.cpp \ + nsScrollingView.cpp \ + nsViewManager.cpp \ + nsViewFactory.cpp \ + $(NULL) + +REQUIRES = raptor xpcom + +LCFLAGS = -D_IMPL_NS_VIEW + +TARGETS = $(LIBRARY) + +include $(DEPTH)/config/rules.mk + + diff --git a/mozilla/view/src/makefile.win b/mozilla/view/src/makefile.win new file mode 100644 index 00000000000..7a2fb2f388a --- /dev/null +++ b/mozilla/view/src/makefile.win @@ -0,0 +1,60 @@ +#!nmake +# +# 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. + +DEPTH=..\.. +IGNORE_MANIFEST=1 + +MAKE_OBJ_TYPE = DLL +DLLNAME = raptorview +DLL=.\$(OBJDIR)\$(DLLNAME).dll +MISCDEP = $(LLIBS) + +MODULE=raptor + +DEFINES =-D_IMPL_NS_VIEW + +OBJS = \ + .\$(OBJDIR)\nsView.obj \ + .\$(OBJDIR)\nsScrollingView.obj \ + .\$(OBJDIR)\nsViewManager.obj \ + .\$(OBJDIR)\nsViewFactory.obj \ + $(NULL) + +LINCS= \ + -I$(PUBLIC)\raptor \ + -I$(PUBLIC)\xpcom \ + $(NULL) + + +LCFLAGS = \ + $(LCFLAGS) \ + -D_IMPL_NS_VIEW \ + $(NULL) + +LLIBS= \ + $(DIST)\lib\xpcom32.lib \ + $(DIST)\lib\raptorbase.lib \ + $(DIST)\lib\raptorgfx.lib \ + $(LIBNSPR) + +include <$(DEPTH)\config\rules.mak> + +install:: $(DLL) + $(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).dll $(DIST)\bin + +clobber:: + rm -f $(DIST)\bin\$(DLLNAME).dll diff --git a/mozilla/view/src/nsScrollingView.cpp b/mozilla/view/src/nsScrollingView.cpp new file mode 100644 index 00000000000..3036b954a44 --- /dev/null +++ b/mozilla/view/src/nsScrollingView.cpp @@ -0,0 +1,350 @@ +/* -*- 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 "nsScrollingView.h" +#include "nsIWidget.h" +#include "nsUnitConversion.h" +#include "nsIViewManager.h" +#include "nsIPresContext.h" +#include "nsIScrollbar.h" +#include "nsIDeviceContext.h" +#include "nsGUIEvent.h" +#include "nsWidgetsCID.h" +#include "nsViewsCID.h" +#include "nsIScrollableView.h" + +class ScrollBarView : public nsView +{ +public: + ScrollBarView(); + ~ScrollBarView(); + void SetDimensions(nscoord width, nscoord height); +}; + +ScrollBarView :: ScrollBarView() +{ +} + +ScrollBarView :: ~ScrollBarView() +{ +} + +void ScrollBarView :: SetDimensions(nscoord width, nscoord height) +{ + mBounds.SizeTo(width, height); +} + +static NS_DEFINE_IID(kIViewIID, NS_IVIEW_IID); + +nsScrollingView :: nsScrollingView() +{ +} + +nsScrollingView :: ~nsScrollingView() +{ +} + +nsresult nsScrollingView :: QueryInterface(const nsIID& aIID, void** aInstancePtr) +{ + if (nsnull == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + + static NS_DEFINE_IID(kClassIID, NS_ISCROLLABLEVIEW_IID); + + if (aIID.Equals(kClassIID)) { + *aInstancePtr = (void*)(nsIScrollableView*)this; + AddRef(); + return NS_OK; + } + + return nsView::QueryInterface(aIID, aInstancePtr); +} + +nsrefcnt nsScrollingView :: AddRef() +{ + return nsView::AddRef(); +} + +nsrefcnt nsScrollingView :: Release() +{ + return nsView::Release(); +} + +nsresult nsScrollingView :: Init(nsIViewManager* aManager, + const nsRect &aBounds, + nsIView *aParent, + const nsIID *aWindowIID, + nsNativeWindow aNative, + PRInt32 aZIndex, + const nsRect *aClipRect, + float aOpacity, + nsViewVisibility aVisibilityFlag) +{ + nsresult rv; + + rv = nsView :: Init(aManager, aBounds, aParent, aWindowIID, aNative, aZIndex, aClipRect, aOpacity, aVisibilityFlag); + + if (rv == NS_OK) + { + nsIPresContext *cx = mViewManager->GetPresContext(); + nsIDeviceContext *dx = cx->GetDeviceContext(); + + // Create a view + + mScrollBarView = new ScrollBarView(); + + NS_IF_ADDREF(mScrollBarView); + + if (nsnull != mScrollBarView) + { + nsRect trect = aBounds; + + trect.width = NS_TO_INT_ROUND(dx->GetScrollBarWidth()); + trect.x = aBounds.XMost() - trect.width; + + static NS_DEFINE_IID(kCScrollbarIID, NS_VERTSCROLLBAR_CID); + + rv = mScrollBarView->Init(mViewManager, trect, this, &kCScrollbarIID); + + mViewManager->InsertChild(this, mScrollBarView, 0); + } + + NS_RELEASE(dx); + NS_RELEASE(cx); + } + + return rv; +} + + +void nsScrollingView :: SetPosition(nscoord x, nscoord y) +{ + nsView :: SetPosition(x, y); +} + +void nsScrollingView :: SetDimensions(nscoord width, nscoord height) +{ + PRInt32 owidth, oheight; + nsIWidget *win; + nsRect trect; + nsIPresContext *cx; + nsIDeviceContext *dx; + + nsView :: SetDimensions(width, height); + + if (nsnull != mScrollBarView) + { + cx = mViewManager->GetPresContext(); + dx = cx->GetDeviceContext(); + + mScrollBarView->GetDimensions(&owidth, &oheight); + mScrollBarView->SetDimensions(owidth, height); + + mScrollBarView->SetPosition(width - NS_TO_INT_ROUND(dx->GetScrollBarWidth()), 0); + + win = mScrollBarView->GetWidget(); + + if (nsnull != win) + { + nsRect trect; + win->GetBounds(trect); + + //compute new bounds + + trect.x = NS_TO_INT_ROUND((width - NS_TO_INT_ROUND(dx->GetScrollBarWidth())) * cx->GetTwipsToPixels()); + trect.y = 0; + trect.height = NS_TO_INT_ROUND(height * cx->GetTwipsToPixels()); + + win->Resize(trect.x, trect.y, trect.width, trect.height); + + NS_RELEASE(win); + } + + //this will fix the size of the thumb when we resize the root window + + SetContainerSize(mSize); + + NS_RELEASE(dx); + NS_RELEASE(cx); + } +} + +nsEventStatus nsScrollingView :: HandleEvent(nsGUIEvent *aEvent, PRBool aCheckParent, PRBool aCheckChildren) +{ + nsEventStatus retval = nsEventStatus_eIgnore; + + switch (aEvent->message) + { + case NS_SCROLLBAR_POS: + case NS_SCROLLBAR_PAGE_NEXT: + case NS_SCROLLBAR_PAGE_PREV: + case NS_SCROLLBAR_LINE_NEXT: + case NS_SCROLLBAR_LINE_PREV: + { + nscoord ox, oy, ny; + nsIPresContext *px = mViewManager->GetPresContext(); + nscoord dy; + float scale = px->GetTwipsToPixels(); + + mViewManager->GetWindowOffsets(&ox, &oy); + + //now, this horrible thing makes sure that as we scroll + //the document a pixel at a time, we keep the logical position of + //our scroll bar at the top edge of the same pixel that + //is displayed. + + ny = NS_TO_INT_ROUND(NS_TO_INT_ROUND(((nsScrollbarEvent *)aEvent)->position * scale) * px->GetPixelsToTwips()); + + mViewManager->SetWindowOffsets(ox, ny); + + dy = NS_TO_INT_ROUND(scale * (oy - ny)); + + if (dy != 0) + { + nsRect clip; + nscoord sx, sy; + + mScrollBarView->GetDimensions(&sx, &sy); + + clip.x = 0; + clip.y = 0; + clip.width = NS_TO_INT_ROUND(scale * (mBounds.width - sx)); + clip.height = NS_TO_INT_ROUND(scale * mBounds.height); + + mViewManager->ClearDirtyRegion(); + mWindow->Scroll(0, dy, &clip); + + //and now we make sure that the scrollbar thumb is in sync with the + //numbers we came up with here, but only if we actually moved at least + //a full pixel. if didn't adjust the thumb only if the delta is non-zero, + //very slow scrolling would never actually work. + + ((nsScrollbarEvent *)aEvent)->position = ny; + + AdjustChildWidgets(0, dy); + } + + retval = nsEventStatus_eConsumeNoDefault; + + NS_RELEASE(px); + + break; + } + + default: + retval = nsView::HandleEvent(aEvent, aCheckParent, aCheckChildren); + break; + } + + return retval; +} + +void nsScrollingView :: SetContainerSize(nscoord aSize) +{ + PRUint32 oldsize = aSize; + + mSize = aSize; + + if (nsnull != mScrollBarView) + { + nscoord width, height; + nsIScrollbar *scroll; + nsIWidget *win; + + mScrollBarView->GetDimensions(&width, &height); + + win = mScrollBarView->GetWidget(); + + static NS_DEFINE_IID(kscroller, NS_ISCROLLBAR_IID); + + if (NS_OK == win->QueryInterface(kscroller, (void **)&scroll)) + { + if (mSize > height) + { + nsIPresContext *px = mViewManager->GetPresContext(); + + //we need to be able to scroll + + scroll->Enable(PR_TRUE); + + //now update the scroller position for the new size + + PRUint32 newpos, oldpos = scroll->GetPosition(); + PRInt32 offx, offy; + + newpos = NS_TO_INT_ROUND(NS_TO_INT_ROUND((((float)oldpos * mSize) / oldsize) * px->GetTwipsToPixels()) * px->GetPixelsToTwips()); + + mViewManager->GetWindowOffsets(&offx, &offy); + mViewManager->SetWindowOffsets(offx, newpos); + + scroll->SetParameters(mSize, mBounds.height, newpos, NS_POINTS_TO_TWIPS_INT(12)); + + NS_RELEASE(px); + } + else + scroll->Enable(PR_FALSE); + + scroll->Release(); + } + + NS_RELEASE(win); + } +} + +PRInt32 nsScrollingView :: GetContainerSize() +{ + return mSize; +} + +void nsScrollingView :: SetVisibleOffset(PRInt32 aOffset) +{ + mOffset = aOffset; +} + +PRInt32 nsScrollingView :: GetVisibleOffset() +{ + return mOffset; +} + +void nsScrollingView :: AdjustChildWidgets(nscoord aDx, nscoord aDy) +{ + PRInt32 numkids = GetChildCount(); + + for (PRInt32 cnt = 0; cnt < numkids; cnt++) + { + nsIView *kid = GetChild(cnt); + + if (kid != mScrollBarView) + { + nsIWidget *win = kid->GetWidget(); + + if (nsnull != win) + { + nsRect bounds; + + win->GetBounds(bounds); + win->Move(bounds.x + aDx, bounds.y + aDy); + + NS_RELEASE(win); + } + + kid->AdjustChildWidgets(aDx, aDy); + } + } +} diff --git a/mozilla/view/src/nsScrollingView.h b/mozilla/view/src/nsScrollingView.h new file mode 100644 index 00000000000..fdc4263d6fd --- /dev/null +++ b/mozilla/view/src/nsScrollingView.h @@ -0,0 +1,65 @@ +/* -*- 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. + */ + +#ifndef nsScrollingView_h___ +#define nsScrollingView_h___ + +#include "nsView.h" +#include "nsIScrollableView.h" + +class nsScrollingView : public nsView, public nsIScrollableView +{ +public: + nsScrollingView(); + ~nsScrollingView(); + + NS_IMETHOD QueryInterface(REFNSIID aIID, + void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(void); + NS_IMETHOD_(nsrefcnt) Release(void); + + virtual nsresult Init(nsIViewManager* aManager, + const nsRect &aBounds, + nsIView *aParent, + const nsIID *aWindowIID = nsnull, + nsNativeWindow aNative = nsnull, + PRInt32 aZIndex = 0, + const nsRect *aClipRect = nsnull, + float aOpacity = 1.0f, + nsViewVisibility aVisibilityFlag = nsViewVisibility_kShow); + + //overrides + virtual void SetPosition(nscoord x, nscoord y); + virtual void SetDimensions(nscoord width, nscoord height); + virtual nsEventStatus HandleEvent(nsGUIEvent *aEvent, PRBool aCheckParent = PR_TRUE, PRBool aCheckChildren = PR_TRUE); + virtual void AdjustChildWidgets(nscoord aDx, nscoord aDy); + + //nsIScrollableView interface + virtual void SetContainerSize(PRInt32 aSize); + virtual PRInt32 GetContainerSize(); + + virtual void SetVisibleOffset(PRInt32 aOffset); + virtual PRInt32 GetVisibleOffset(); + +protected: + PRInt32 mSize; + PRInt32 mOffset; + nsIView *mScrollBarView; +}; + +#endif diff --git a/mozilla/view/src/nsView.cpp b/mozilla/view/src/nsView.cpp new file mode 100644 index 00000000000..f9afc48e65b --- /dev/null +++ b/mozilla/view/src/nsView.cpp @@ -0,0 +1,768 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file arhandlee 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 "nsView.h" +#include "nsIWidget.h" +#include "nsIViewManager.h" +#include "nsIFrame.h" +#include "nsIPresContext.h" +#include "nsIPresShell.h" +#include "nsIWidget.h" +#include "nsIButton.h" +#include "nsIScrollbar.h" +#include "nsGUIEvent.h" +#include "nsIDeviceContext.h" +#include "nsRepository.h" +#include "nsIRenderingContext.h" +#include "nsTransform2D.h" + +static NS_DEFINE_IID(kIViewIID, NS_IVIEW_IID); + +// +// Main events handler +// +nsEventStatus PR_CALLBACK HandleEvent(nsGUIEvent *aEvent) +{ + nsIView *view; + nsEventStatus result = nsEventStatus_eIgnore; + + if (NS_OK == aEvent->widget->QueryInterface(kIViewIID, (void**)&view)) + { + switch(aEvent->message) + { + case NS_SIZE: + { + nscoord width = ((nsSizeEvent*)aEvent)->windowSize->width; + nscoord height = ((nsSizeEvent*)aEvent)->windowSize->height; + + // Inform the view manager that the root window has been resized + nsIViewManager* vm = view->GetViewManager(); + nsIPresContext* presContext = vm->GetPresContext(); + + // The root view may not be set if this is the resize associated with + // window creation + + nsIView* rootView = vm->GetRootView(); + + if (view == rootView) + { + // Convert from pixels to twips + float p2t = presContext->GetPixelsToTwips(); + vm->SetWindowDimensions(NS_TO_INT_ROUND(width * p2t), + NS_TO_INT_ROUND(height * p2t)); + result = nsEventStatus_eConsumeNoDefault; + } + + NS_RELEASE(rootView); + NS_RELEASE(presContext); + NS_RELEASE(vm); + + break; + } + + case NS_PAINT: + { + nsIViewManager *vm = view->GetViewManager(); + nsIPresContext *px = vm->GetPresContext(); + float convert = px->GetPixelsToTwips(); + nsRect vrect, trect = *((nsPaintEvent*)aEvent)->rect; + nsIDeviceContext *dx = px->GetDeviceContext(); + + trect.x = NS_TO_INT_ROUND(trect.x * convert); + trect.y = NS_TO_INT_ROUND(trect.y * convert); + trect.width = NS_TO_INT_ROUND(trect.width * convert); + trect.height = NS_TO_INT_ROUND(trect.height * convert); + + //see if the paint region is greater than .75 the area of our root view. + //if so, enable double buffered painting. + + view->GetBounds(vrect); + + PRBool db = PR_FALSE; + + if ((((float)trect.width * trect.height) / ((float)vrect.width * vrect.height)) > 0.75f) + db = PR_TRUE; + + vm->Refresh(view, ((nsPaintEvent *)aEvent)->renderingContext, &trect, + ((db == PR_TRUE) ? NS_VMREFRESH_DOUBLE_BUFFER : 0) | NS_VMREFRESH_SCREEN_RECT); + + NS_RELEASE(dx); + NS_RELEASE(px); + NS_RELEASE(vm); + + result = nsEventStatus_eConsumeNoDefault; + + break; + } + + case NS_DESTROY: + result = nsEventStatus_eConsumeNoDefault; + break; + + default: + nsIViewManager *vm = view->GetViewManager(); + nsIPresContext *cx = vm->GetPresContext(); + + // pass on to view somewhere else to deal with + + aEvent->point.x = NS_TO_INT_ROUND(aEvent->point.x * cx->GetPixelsToTwips()); + aEvent->point.y = NS_TO_INT_ROUND(aEvent->point.y * cx->GetPixelsToTwips()); + + result = view->HandleEvent(aEvent); + + aEvent->point.x = NS_TO_INT_ROUND(aEvent->point.x * cx->GetTwipsToPixels()); + aEvent->point.y = NS_TO_INT_ROUND(aEvent->point.y * cx->GetTwipsToPixels()); + + NS_RELEASE(cx); + NS_RELEASE(vm); + + break; + } + + NS_RELEASE(view); + } + + return result; +} + +nsView :: nsView() +{ + mVis = nsViewVisibility_kShow; +} + +nsView :: ~nsView() +{ + if (GetChildCount() > 0) + { + nsIView *kid; + + //nuke the kids + + while (kid = GetChild(0)) + kid->Destroy(); + } + + if (nsnull != mViewManager) + { + nsIView *rootView = mViewManager->GetRootView(); + if (rootView == this) { + //This code should never be reached since there is a circular ref between nsView and nsViewManager\n"); + mViewManager->SetRootView(nsnull); // this resets our ref count to 0 + } + else + { + if (nsnull != mParent) { + mViewManager->RemoveChild(mParent, this); + } + NS_RELEASE(rootView); + } + NS_RELEASE(mViewManager); + mViewManager = nsnull; + } + if (nsnull != mFrame) { + // Temporarily raise our refcnt because the frame is going to + // Release us. + mRefCnt = 99; + mFrame->SetView(nsnull); + mRefCnt = 0; + } + if (nsnull != mInnerWindow) { + //if (nsnull != mWindow) { + // mWindow->Destroy(); + // mWindow = nsnull; + //} + NS_RELEASE(mInnerWindow); // this should destroy the widget and its native windows + } +} + +nsresult nsView :: QueryInterface(const nsIID& aIID, void** aInstancePtr) +{ + if (nsnull == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + static NS_DEFINE_IID(kClassIID, kIViewIID); + + if (aIID.Equals(kClassIID) || (aIID.Equals(kISupportsIID))) { + *aInstancePtr = (void*)(nsIView*)this; + AddRef(); + return NS_OK; + } + + if (nsnull != mInnerWindow) + return mInnerWindow->QueryInterface(aIID, aInstancePtr); + + return NS_NOINTERFACE; +} + +// this should be added to nsView +nsIWidget* +GetWindowTemp(nsIView *aView) +{ + nsIWidget *window = nsnull; + + nsIView *ancestor = aView; + while (nsnull != ancestor) { + if (nsnull != (window = ancestor->GetWidget())) { + return window; + } + ancestor = ancestor->GetParent(); + } + return nsnull; +} + +nsrefcnt nsView::AddRef() +{ + return ++mRefCnt; +} + +nsrefcnt nsView::Release() +{ + if (--mRefCnt == 0) + { + delete this; + return 0; + } + return mRefCnt; +} + +nsresult nsView :: Init(nsIViewManager* aManager, + const nsRect &aBounds, + nsIView *aParent, + const nsCID *aWindowCIID, + nsNativeWindow aNative, + PRInt32 aZIndex, + const nsRect *aClipRect, + float aOpacity, + nsViewVisibility aVisibilityFlag) +{ + NS_PRECONDITION(nsnull != aManager, "null ptr"); + if (nsnull == aManager) { + return NS_ERROR_NULL_POINTER; + } + if (nsnull != mViewManager) { + return NS_ERROR_ALREADY_INITIALIZED; + } + mViewManager = aManager; + + NS_ADDREF(aManager); + + mBounds = aBounds; + + // assign the parent view + SetParent(aParent); + + // check if a real window has to be created + if (aWindowCIID) + { + nsIPresContext *cx = mViewManager->GetPresContext(); + nsIDeviceContext *dx = cx->GetDeviceContext(); + nsRect trect = aBounds; + + trect *= cx->GetTwipsToPixels(); + + if (NS_OK == LoadWidget(*aWindowCIID)) + { + if (aNative) + mWindow->Create(aNative, trect, ::HandleEvent, dx); + else + { + nsIWidget *parent = GetWindowTemp(aParent); + mWindow->Create(parent, trect, ::HandleEvent, dx); + NS_IF_RELEASE(parent); + } + } + + NS_RELEASE(dx); + NS_RELEASE(cx); + } + + SetVisibility(aVisibilityFlag); + + return NS_OK; +} + +void nsView :: Destroy() +{ + delete this; +} + +nsIViewManager * nsView :: GetViewManager() +{ + NS_IF_ADDREF(mViewManager); + return mViewManager; +} + +nsIWidget * nsView :: GetWidget() +{ + NS_IF_ADDREF(mWindow); + return mWindow; +} + +void nsView :: Paint(nsIRenderingContext& rc, const nsRect& rect) +{ + if (nsnull != mFrame) + { + nsIPresContext *cx = mViewManager->GetPresContext(); + + mFrame->Paint(*cx, rc, rect); + + NS_RELEASE(cx); + } +} + +void nsView :: Paint(nsIRenderingContext& rc, const nsRegion& region) +{ + // XXX apply region to rc + // XXX get bounding rect from region + //if (nsnull != mFrame) + // mFrame->Paint(rc, rect); +} + +nsEventStatus nsView :: HandleEvent(nsGUIEvent *event, PRBool aCheckParent, PRBool aCheckChildren) +{ + nsIScrollbar *scroll; + nsEventStatus retval = nsEventStatus_eIgnore; + + if (nsnull != mWindow) + { + //if this is a scrollbar window that sent + //us the event, do special processing + + static NS_DEFINE_IID(kscroller, NS_ISCROLLBAR_IID); + + if (NS_OK == mWindow->QueryInterface(kscroller, (void **)&scroll)) + { + if (nsnull != mParent) + retval = mParent->HandleEvent(event, PR_FALSE, PR_FALSE); + + NS_RELEASE(scroll); + } + } + + if ((retval == nsEventStatus_eIgnore) && (nsnull != mFrame)) + { + nsIPresContext *cx = mViewManager->GetPresContext(); + nscoord xoff, yoff; + + mViewManager->GetWindowOffsets(&xoff, &yoff); + + event->point.x += xoff; + event->point.y += yoff; + + retval = mFrame->HandleEvent(*cx, event); + + event->point.x -= xoff; + event->point.y -= yoff; + + NS_RELEASE(cx); + } + + //see if any of this view's children can process the event + + if ((PR_TRUE == aCheckChildren) && (retval == nsEventStatus_eIgnore)) + { + PRInt32 numkids = GetChildCount(); + nsRect trect; + nscoord x, y; + + x = event->point.x; + y = event->point.y; + + for (PRInt32 cnt = 0; cnt < numkids; cnt++) + { + nsIView *pKid = GetChild(cnt); + nscoord lx, ly; + + pKid->GetBounds(trect); + + lx = x - trect.x; + ly = y - trect.y; + + if (trect.Contains(lx, ly)) + { + //the x, y position of the event in question + //is inside this child view, so give it the + //opportunity to handle the event + + event->point.x -= trect.x; + event->point.y -= trect.y; + + retval = pKid->HandleEvent(event, PR_FALSE, PR_TRUE); + + event->point.x += trect.x; + event->point.y += trect.y; + + if (retval != nsEventStatus_eIgnore) + break; + } + } + } + + //see if any of this views siblings can process this event + //we only go from the next sibling since this is a z-ordered + //list + + if (retval == nsEventStatus_eIgnore) + { + nsIView *pNext = GetNextSibling(); + + while (pNext) + { + retval = pNext->HandleEvent(event, PR_FALSE, PR_TRUE); + + if (retval != PR_FALSE) + break; + + pNext = pNext->GetNextSibling(); + } + } + + //no-one has a clue what to do with this... so ask the + //parents. kind of mimics life, huh? + + if ((PR_TRUE == aCheckParent) && (retval == PR_FALSE)) + { + nsIView *pParent = GetParent(); + + while (pParent) + { + retval = pParent->HandleEvent(event, PR_FALSE, PR_FALSE); + + if (retval != PR_FALSE) + break; + + pParent = pParent->GetParent(); + } + } + + return retval; +} + +void nsView :: SetPosition(nscoord x, nscoord y) +{ + mBounds.MoveTo(x, y); + + if (nsnull != mWindow) + { + nsIPresContext *px = mViewManager->GetPresContext(); + nscoord offx, offy; + float scale = px->GetTwipsToPixels(); + + mViewManager->GetWindowOffsets(&offx, &offy); + + mWindow->Move(NS_TO_INT_ROUND((x + offx) * scale), NS_TO_INT_ROUND((y + offy) * scale)); + + NS_RELEASE(px); + } +} + +void nsView :: GetPosition(nscoord *x, nscoord *y) +{ + *x = mBounds.x; + *y = mBounds.y; +} + +#include "nsScrollingView.h" + +void nsView :: SetDimensions(nscoord width, nscoord height) +{ + mBounds.SizeTo(width, height); + + //XXX this is a hack. pretend you don't see it. + //it will go away soon, i promise. MMP + + if (nsnull != mParent) + { + nsScrollingView *root = (nsScrollingView *)mViewManager->GetRootView(); + + if (mParent == root) + { + root->SetContainerSize(mBounds.height); + } + + if (nsnull != mWindow) + { + nsIPresContext *px = mViewManager->GetPresContext(); + float t2p = px->GetTwipsToPixels(); + + mWindow->Resize(NS_TO_INT_ROUND(t2p * width), NS_TO_INT_ROUND(t2p * height)); + + NS_RELEASE(px); + } + + NS_RELEASE(root); + } +} + +void nsView :: GetDimensions(nscoord *width, nscoord *height) +{ + *width = mBounds.width; + *height = mBounds.height; +} + +void nsView :: SetBounds(const nsRect &aBounds) +{ + mBounds = aBounds; + + SetPosition(aBounds.x, aBounds.y); + SetDimensions(aBounds.width, aBounds.height); +} + +void nsView :: SetBounds(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) +{ + mBounds.x = aX; + mBounds.y = aY; + + SetPosition(aX, aY); + SetDimensions(aWidth, aHeight); +} + +void nsView :: GetBounds(nsRect &aBounds) +{ + aBounds = mBounds; +} + +void nsView :: SetClip(const nsRect &aClip) +{ +} + +void nsView :: SetClip(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) +{ +} + +PRBool nsView :: GetClip(nsRect *aClip) +{ + return PR_FALSE; +} + +void nsView :: SetVisibility(nsViewVisibility aVisibility) +{ + mVis = aVisibility; + + if (nsnull != mWindow) + { + if (mVis == nsViewVisibility_kShow) + mWindow->Show(PR_TRUE); + else + mWindow->Show(PR_FALSE); + } +} + +nsViewVisibility nsView :: GetVisibility() +{ + return mVis; +} + +void nsView :: SetZIndex(PRInt32 zindex) +{ + mZindex = zindex; +} + +PRInt32 nsView :: GetZIndex() +{ + return mZindex; +} + +void nsView :: SetParent(nsIView *aParent) +{ + mParent = aParent; +} + +nsIView * nsView :: GetParent() +{ + return mParent; +} + +nsIView * nsView :: GetNextSibling() const +{ + return mNextSibling; +} + +void nsView::SetNextSibling(nsIView* aView) +{ + mNextSibling = aView; +} + +void nsView :: InsertChild(nsIView *child, nsIView *sibling) +{ + NS_PRECONDITION(nsnull != child, "null ptr"); + if (nsnull != child) + { + if (nsnull != sibling) + { + NS_ASSERTION(sibling->GetParent() != this, "tried to insert view with invalid sibling"); + //insert after sibling + child->SetNextSibling(sibling->GetNextSibling()); + sibling->SetNextSibling(child); + } + else + { + child->SetNextSibling(mFirstChild); + mFirstChild = child; + } + child->SetParent(this); + mNumKids++; + } +} + +void nsView :: RemoveChild(nsIView *child) +{ + NS_PRECONDITION(nsnull != child, "null ptr"); + + if (nsnull != child) + { + nsIView* prevKid = nsnull; + nsIView* kid = mFirstChild; + PRBool found = PR_FALSE; + while (nsnull != kid) { + if (kid == child) { + if (nsnull != prevKid) { + prevKid->SetNextSibling(kid->GetNextSibling()); + } else { + mFirstChild = kid->GetNextSibling(); + } + child->SetParent(nsnull); + mNumKids--; + found = PR_TRUE; + break; + } + kid = kid->GetNextSibling(); + } + NS_ASSERTION(found, "tried to remove non child"); + } +} + +PRInt32 nsView :: GetChildCount() +{ + return mNumKids; +} + +nsIView * nsView :: GetChild(PRInt32 index) +{ + NS_PRECONDITION(!(index > mNumKids), "bad index"); + + if (index < mNumKids) + { + nsIView *kid = mFirstChild; + for (PRInt32 cnt = 0; (cnt < index) && (nsnull != kid); cnt++) { + kid = kid->GetNextSibling(); + } + return kid; + } + return nsnull; +} + +void nsView :: SetTransform(nsTransform2D *transform) +{ +} + +nsTransform2D * nsView :: GetTransform() +{ + return nsnull; +} + +void nsView :: SetOpacity(float opacity) +{ +} + +float nsView :: GetOpacity() +{ + return 1.0f; +} + +PRBool nsView :: HasTransparency() +{ + return PR_FALSE; +} + +// Frames have a pointer to the view, so don't AddRef the frame. +void nsView :: SetFrame(nsIFrame *aFrame) +{ + mFrame = aFrame; +} + +nsIFrame * nsView :: GetFrame() +{ + return mFrame; +} + +// +// internal window creation functions +// +nsresult nsView :: LoadWidget(const nsCID &aClassIID) +{ + nsresult rv; + + static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + rv = NSRepository::CreateInstance(aClassIID, this, kISupportsIID, (void**)&mInnerWindow); + + if (NS_OK == rv) { + // load the convenience nsIWidget pointer. + // NOTE: mWindow is released so not to create a circulare refcount + static NS_DEFINE_IID(kIWidgetIID, NS_IWIDGET_IID); + rv = mInnerWindow->QueryInterface(kIWidgetIID, (void**)&mWindow); + if (NS_OK != rv) { + mInnerWindow->Release(); + mInnerWindow = NULL; + } + else { + mWindow->Release(); + } + } + + return rv; +} + +void nsView :: List(FILE* out, PRInt32 aIndent) const +{ + for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out); + fprintf(out, "%p win=%p ", this, mWindow); + out << mBounds; + fputs("<\n", out); + nsIView* kid = mFirstChild; + while (nsnull != kid) { + kid->List(out, aIndent + 1); + kid = kid->GetNextSibling(); + } + for (i = aIndent; --i >= 0; ) fputs(" ", out); + fputs(">\n", out); +} + +void nsView :: AdjustChildWidgets(nscoord aDx, nscoord aDy) +{ + PRInt32 numkids = GetChildCount(); + + for (PRInt32 cnt = 0; cnt < numkids; cnt++) + { + nsIView *kid = GetChild(cnt); + nsIWidget *win = kid->GetWidget(); + + if (nsnull != win) + { + nsRect bounds; + + win->GetBounds(bounds); + win->Move(bounds.x + aDx, bounds.y + aDy); + + NS_RELEASE(win); + } + + kid->AdjustChildWidgets(aDx, aDy); + } +} diff --git a/mozilla/view/src/nsView.h b/mozilla/view/src/nsView.h new file mode 100644 index 00000000000..365052a7978 --- /dev/null +++ b/mozilla/view/src/nsView.h @@ -0,0 +1,120 @@ +/* -*- 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. + */ + +#ifndef nsView_h___ +#define nsView_h___ + +#include "nsViewManager.h" +#include "nsIView.h" +#include "nsRect.h" +#include "nsCRT.h" +#include "nsIWidget.h" +#include "nsIFactory.h" + +class nsIPresContext; + +class nsView : public nsIView +{ +public: + nsView(); + ~nsView(); + + void* operator new(size_t sz) { + void* rv = new char[sz]; + nsCRT::zero(rv, sz); + return rv; + } + + NS_DECL_ISUPPORTS + + virtual nsresult Init(nsIViewManager* aManager, + const nsRect &aBounds, + nsIView *aParent, + const nsCID *aWindowIID = nsnull, + nsNativeWindow aNative = nsnull, + PRInt32 aZIndex = 0, + const nsRect *aClipRect = nsnull, + float aOpacity = 1.0f, + nsViewVisibility aVisibilityFlag = nsViewVisibility_kShow); + virtual void Destroy(); + virtual nsIViewManager * GetViewManager(); + virtual nsIWidget * GetWidget(); + virtual void Paint(nsIRenderingContext& rc, const nsRect& rect); + virtual void Paint(nsIRenderingContext& rc, const nsRegion& region); + virtual nsEventStatus HandleEvent(nsGUIEvent *event, PRBool aCheckParent = PR_TRUE, PRBool aCheckChildren = PR_TRUE); + virtual void SetPosition(nscoord x, nscoord y); + virtual void GetPosition(nscoord *x, nscoord *y); + virtual void SetDimensions(nscoord width, nscoord height); + virtual void GetDimensions(nscoord *width, nscoord *height); + virtual void SetBounds(const nsRect &aBounds); + virtual void SetBounds(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight); + virtual void GetBounds(nsRect &aBounds); + virtual void SetClip(const nsRect &aClip); + virtual void SetClip(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight); + virtual PRBool GetClip(nsRect *aClip); + virtual void SetVisibility(nsViewVisibility visibility); + virtual nsViewVisibility GetVisibility(); + virtual void SetZIndex(PRInt32 zindex); + virtual PRInt32 GetZIndex(); + virtual void SetParent(nsIView *aParent); + virtual nsIView *GetParent(); + virtual nsIView* GetNextSibling() const; + virtual void SetNextSibling(nsIView* aNextSibling); + virtual void InsertChild(nsIView *child, nsIView *sibling); + virtual void RemoveChild(nsIView *child); + virtual PRInt32 GetChildCount(); + virtual nsIView * GetChild(PRInt32 index); + virtual void SetTransform(nsTransform2D *transform); + virtual nsTransform2D * GetTransform(); + virtual void SetOpacity(float opacity); + virtual float GetOpacity(); + virtual PRBool HasTransparency(); + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const; + virtual void SetFrame(nsIFrame *aFrame); + virtual nsIFrame * GetFrame(); + virtual void AdjustChildWidgets(nscoord aDx, nscoord aDy); + +protected: + // + virtual nsresult LoadWidget(const nsCID &aClassIID); + +protected: + nsIViewManager *mViewManager; + nsIView *mParent; + + // a View aggregates an nsIWidget, if any. + // mInnerWindow is the pointer to the widget real nsISupports. QueryInterace + // should be called on mInnerWindow if any of the widget interface wants to + // be exposed, + // mWindow is a convenience pointer to the widget functionalities. + // mWindow is not AddRef'ed or Released otherwise we'll create a circulare + // refcount and the view will never go away + nsISupports *mInnerWindow; + nsIWidget *mWindow; + + //XXX should there be pointers to last child so backward walking is fast? + nsIView *mNextSibling; + nsIView *mFirstChild; + nsIFrame *mFrame; + PRInt32 mZindex; + nsViewVisibility mVis; + PRInt32 mNumKids; + nsRect mBounds; +}; + +#endif diff --git a/mozilla/view/src/nsViewFactory.cpp b/mozilla/view/src/nsViewFactory.cpp new file mode 100644 index 00000000000..9abfb03596f --- /dev/null +++ b/mozilla/view/src/nsViewFactory.cpp @@ -0,0 +1,164 @@ +/* -*- 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 "nscore.h" +#include "nsIFactory.h" +#include "nsISupports.h" + +#include "nsViewsCID.h" +#include "nsView.h" +#include "nsViewManager.h" +#include "nsScrollingView.h" + +static NS_DEFINE_IID(kCViewManager, NS_VIEW_MANAGER_CID); +static NS_DEFINE_IID(kCView, NS_VIEW_CID); +static NS_DEFINE_IID(kCScrollingView, NS_SCROLLING_VIEW_CID); + +static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); +static NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID); + +class nsViewFactory : public nsIFactory +{ + public: + // nsISupports methods + NS_IMETHOD QueryInterface(const nsIID &aIID, + void **aResult); + NS_IMETHOD_(nsrefcnt) AddRef(void); + NS_IMETHOD_(nsrefcnt) Release(void); + + // nsIFactory methods + NS_IMETHOD CreateInstance(nsISupports *aOuter, + const nsIID &aIID, + void **aResult); + + NS_IMETHOD LockFactory(PRBool aLock); + + nsViewFactory(const nsCID &aClass); + ~nsViewFactory(); + + private: + nsrefcnt mRefCnt; + nsCID mClassID; +}; + +nsViewFactory::nsViewFactory(const nsCID &aClass) +{ + mRefCnt = 0; + mClassID = aClass; +} + +nsViewFactory::~nsViewFactory() +{ + NS_ASSERTION(mRefCnt == 0, "non-zero refcnt at destruction"); +} + +nsresult nsViewFactory::QueryInterface(const nsIID &aIID, + void **aResult) +{ + if (aResult == NULL) { + return NS_ERROR_NULL_POINTER; + } + + // Always NULL result, in case of failure + *aResult = NULL; + + if (aIID.Equals(kISupportsIID)) { + *aResult = (void *)(nsISupports*)this; + } else if (aIID.Equals(kIFactoryIID)) { + *aResult = (void *)(nsIFactory*)this; + } + + if (*aResult == NULL) { + return NS_NOINTERFACE; + } + + AddRef(); // Increase reference count for caller + return NS_OK; +} + +nsrefcnt nsViewFactory::AddRef() +{ + return ++mRefCnt; +} + +nsrefcnt nsViewFactory::Release() +{ + if (--mRefCnt == 0) { + delete this; + return 0; // Don't access mRefCnt after deleting! + } + return mRefCnt; +} + +nsresult nsViewFactory::CreateInstance(nsISupports *aOuter, + const nsIID &aIID, + void **aResult) +{ + if (aResult == NULL) { + return NS_ERROR_NULL_POINTER; + } + + *aResult = NULL; + + nsISupports *inst = nsnull; + + if (mClassID.Equals(kCViewManager)) { + inst = (nsISupports *)new nsViewManager(); + } + else if (mClassID.Equals(kCView)) { + inst = (nsISupports *)new nsView(); + } + else if (mClassID.Equals(kCScrollingView)) { + inst = (nsISupports *)(nsView*)new nsScrollingView(); + } + + if (inst == NULL) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsresult res = inst->QueryInterface(aIID, aResult); + + if (res != NS_OK) { + // We didn't get the right interface, so clean up + delete inst; + } + + return res; +} + +nsresult nsViewFactory::LockFactory(PRBool aLock) +{ + // Not implemented in simplest case. + return NS_OK; +} + +// return the proper factory to the caller +extern "C" NS_VIEW nsresult NSGetFactory(const nsCID &aClass, nsIFactory **aFactory) +{ + if (nsnull == aFactory) { + return NS_ERROR_NULL_POINTER; + } + + *aFactory = new nsViewFactory(aClass); + + if (nsnull == aFactory) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return (*aFactory)->QueryInterface(kIFactoryIID, (void**)aFactory); +} diff --git a/mozilla/view/src/nsViewManager.cpp b/mozilla/view/src/nsViewManager.cpp new file mode 100644 index 00000000000..82b9841cc53 --- /dev/null +++ b/mozilla/view/src/nsViewManager.cpp @@ -0,0 +1,579 @@ +/* -*- 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 "nsViewManager.h" +#include "nsUnitConversion.h" +#include "nsIPresShell.h" +#include "nsIPresShell.h" +#include "nsIRenderingContext.h" +#include "nsIDeviceContext.h" +#include "nsGfxCIID.h" + +static const PRBool gsDebug = PR_FALSE; + +#define UPDATE_QUANTUM 1000 / 40 + +static void vm_timer_callback(nsITimer *aTimer, void *aClosure) +{ + nsViewManager *vm = (nsViewManager *)aClosure; + + //restart the timer + + PRInt32 fr = vm->GetFrameRate(); + + vm->mFrameRate = 0; + + vm->SetFrameRate(fr); + + if (vm->mDirtyRect.IsEmpty() == PR_FALSE) + { + nsIRenderingContext *cx; + nsIPresContext *px = vm->GetPresContext(); + nsIDeviceContext *dx = px->GetDeviceContext(); + + cx = dx->CreateRenderingContext(vm->mRootView); + + if (nsnull != cx) + { + vm->Refresh(vm->mRootView, cx, &vm->mDirtyRect, NS_VMREFRESH_DOUBLE_BUFFER); + NS_RELEASE(cx); + } + + NS_RELEASE(dx); + NS_RELEASE(px); + } +} + +static NS_DEFINE_IID(knsViewManagerIID, NS_IVIEWMANAGER_IID); + +nsViewManager :: nsViewManager() +{ +} + +nsViewManager :: ~nsViewManager() +{ + NS_IF_RELEASE(mTimer); + NS_IF_RELEASE(mRootWindow); + NS_IF_RELEASE(mRootView); + + if (nsnull != mDrawingSurface) + { + nsIRenderingContext *rc; + + //interesting way of killing things + + static NS_DEFINE_IID(kRenderingContextCID, NS_RENDERING_CONTEXT_CID); + static NS_DEFINE_IID(kIRenderingContextIID, NS_IRENDERING_CONTEXT_IID); + + nsresult rv = NSRepository::CreateInstance(kRenderingContextCID, + nsnull, + kIRenderingContextIID, + (void **)&rc); + + if (NS_OK == rv) + { + rc->DestroyDrawingSurface(mDrawingSurface); + rc->Release(); + } + + mDrawingSurface = nsnull; + } +} + +NS_IMPL_QUERY_INTERFACE(nsViewManager, knsViewManagerIID) + +nsrefcnt nsViewManager::AddRef(void) +{ + return ++mRefCnt; +} + +nsrefcnt nsViewManager::Release(void) +{ + if (--mRefCnt == 0) { + delete this; + return 0; + } + return mRefCnt; +} + +// We don't hold a reference to the presentation context because it +// holds a reference to us. +nsresult nsViewManager::Init(nsIPresContext* aPresContext) +{ + nsresult rv; + + NS_PRECONDITION(nsnull != aPresContext, "null ptr"); + if (nsnull == aPresContext) { + return NS_ERROR_NULL_POINTER; + } + if (nsnull != mContext) { + return NS_ERROR_ALREADY_INITIALIZED; + } + mContext = aPresContext; + + mOffset.x = mOffset.y = 0; + + mDSBounds.Empty(); + mDrawingSurface = nsnull; + mTimer = nsnull; + mFrameRate = 0; + + rv = SetFrameRate(UPDATE_QUANTUM); + + return rv; +} + +nsIWidget * nsViewManager :: GetRootWindow() +{ + NS_IF_ADDREF(mRootWindow); + return mRootWindow; +} + +void nsViewManager :: SetRootWindow(nsIWidget *aRootWindow) +{ + NS_IF_RELEASE(mRootWindow); + mRootWindow = aRootWindow; + NS_IF_ADDREF(mRootWindow); +} + +nsIView * nsViewManager :: GetRootView() +{ + NS_IF_ADDREF(mRootView); + return mRootView; +} + +void nsViewManager :: SetRootView(nsIView *aView) +{ + NS_IF_RELEASE(mRootView); + mRootView = aView; + NS_IF_ADDREF(mRootView); +} + +PRUint32 nsViewManager :: GetFrameRate() +{ + return mFrameRate; +} + +nsresult nsViewManager :: SetFrameRate(PRUint32 aFrameRate) +{ + nsresult rv; + + if (aFrameRate != mFrameRate) + { + NS_IF_RELEASE(mTimer); + + mFrameRate = aFrameRate; + + if (mFrameRate != 0) + { + rv = NS_NewTimer(&mTimer); + + if (NS_OK == rv) + mTimer->Init(vm_timer_callback, this, 1000 / mFrameRate); + } + else + rv = NS_OK; + } + else + rv = NS_OK; + + return rv; +} + +void nsViewManager :: GetWindowDimensions(nscoord *width, nscoord *height) +{ + *width = 0; + *height = 0; +} + +void nsViewManager :: SetWindowDimensions(nscoord width, nscoord height) +{ + nsIPresShell* presShell = mContext->GetShell(); + + // Resize the root view + mRootView->SetDimensions(width, height); + + // Inform the presentation shell that we've been resized + if (nsnull != presShell) { + presShell->ResizeReflow(width, height); + NS_RELEASE(presShell); + } +} + +void nsViewManager :: GetWindowOffsets(nscoord *xoffset, nscoord *yoffset) +{ + *xoffset = mOffset.x; + *yoffset = mOffset.y; +} + +void nsViewManager :: SetWindowOffsets(nscoord xoffset, nscoord yoffset) +{ + mOffset.x = xoffset; + mOffset.y = yoffset; +} + +void nsViewManager :: Refresh(nsIRenderingContext *aContext, nsRegion *region, PRUint32 aUpdateFlags) +{ +} + +static void paint_all_kids(nsIRenderingContext *context, nsIView *par, nsRect *rect) +{ + nsIView *kid; + + if (gsDebug) + { + printf("ViewManager::Refresh: view=%p painting twips=(%d, %d, %d, %d) pixels: ", + par, rect->x, rect->y, rect->XMost(), rect->YMost()); + stdout << *rect; + printf("\n"); + } + + nsRect parbounds; + + par->GetBounds(parbounds); + + context->PushState(); + context->Translate(parbounds.x, parbounds.y); + + par->Paint(*context, *rect); + + if (par->GetChildCount() > 0) + { + kid = par->GetChild(0); + + while (nsnull != kid) + { + paint_all_kids(context, kid, rect); + kid = kid->GetNextSibling(); + } + } + + context->PopState(); +} + +void nsViewManager :: Refresh(nsIView *aView, nsIRenderingContext *aContext, nsRect *rect, PRUint32 aUpdateFlags) +{ + nsRect wrect; + nsIRenderingContext *localcx = nsnull; + + if (nsnull == aContext) + { + localcx = CreateRenderingContext(*aView); + + //couldn't get rendering context. ack. + + if (nsnull == localcx) + return; + } + else + localcx = aContext; + + if (aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER) + { + mRootWindow->GetBounds(wrect); + nsDrawingSurface ds = GetDrawingSurface(*localcx, wrect); + localcx->SelectOffScreenDrawingSurface(ds); + } + + if (aUpdateFlags & NS_VMREFRESH_SCREEN_RECT) + localcx->SetClipRect(*rect, PR_FALSE); + + localcx->Translate(-mOffset.x, -mOffset.y); + + nsRect trect = *rect; + + if (aUpdateFlags & NS_VMREFRESH_SCREEN_RECT) + trect.MoveBy(mOffset.x, mOffset.y); + else + localcx->SetClipRect(trect, PR_FALSE); + + paint_all_kids(localcx, aView, &trect); + + if (aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER) + localcx->CopyOffScreenBits(wrect); + + if (localcx != aContext) + NS_RELEASE(localcx); + + nsRect updaterect = *rect; + + //does our dirty rect intersect the rect we just painted? + + if (updaterect.IntersectRect(updaterect, mDirtyRect)) + { + //does the update rect fully contain the dirty rect? + //if so, then clear the dirty rect. + + if (updaterect.Contains(mDirtyRect)) + ClearDirtyRegion(); + } +} + +void nsViewManager :: Composite() +{ +} + +void nsViewManager :: UpdateView(nsIView *aView, nsRegion *region, PRUint32 aUpdateFlags) +{ +} + +void nsViewManager :: UpdateView(nsIView *aView, nsRect *rect, PRUint32 aUpdateFlags) +{ + nsRect trect = *rect; + nsIView *par = aView; + nscoord x, y; + + if (gsDebug) + { + printf("ViewManager::UpdateView: %x, rect ", aView); + stdout << *rect; + printf("\n"); + } + + do + { + //get absolute coordinates of view + + par->GetPosition(&x, &y); + + trect.x += x; + trect.y += y; + } + while (par = par->GetParent()); + + if (mDirtyRect.IsEmpty()) + mDirtyRect = trect; + else + mDirtyRect.UnionRect(mDirtyRect, trect); + + if ((aUpdateFlags & NS_VMREFRESH_IMMEDIATE) && (nsnull != mContext)) + { + nsIRenderingContext *cx; + nsIDeviceContext *dx = mContext->GetDeviceContext(); + + cx = dx->CreateRenderingContext(mRootView); + + if (nsnull != cx) + { + Refresh(aView, cx, &mDirtyRect, aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER); + NS_RELEASE(cx); + } + + NS_RELEASE(dx); + } +} + +PRBool nsViewManager :: DispatchEvent(nsIEvent *event) +{ + return PR_TRUE; +} + +PRBool nsViewManager :: GrabMouseEvents(nsIView *aView) +{ + return PR_TRUE; +} + +PRBool nsViewManager :: GrabKeyEvents(nsIView *aView) +{ + return PR_TRUE; +} + +nsIView * nsViewManager :: GetMouseEventGrabber() +{ + return nsnull; +} + +nsIView * nsViewManager :: GetKeyEventGrabber() +{ + return nsnull; +} + +void nsViewManager :: InsertChild(nsIView *parent, nsIView *child, nsIView *sibling, + PRBool above) +{ + NS_PRECONDITION(nsnull != parent, "null ptr"); + NS_PRECONDITION(nsnull != child, "null ptr"); + + if ((nsnull != parent) && (nsnull != child)) + { + //XXX this is really dumb but it will at least do something + + parent->InsertChild(child, nsnull); + } +} + +void nsViewManager :: InsertChild(nsIView *parent, nsIView *child, PRInt32 zindex) +{ + NS_PRECONDITION(nsnull != parent, "null ptr"); + NS_PRECONDITION(nsnull != child, "null ptr"); + + if ((nsnull != parent) && (nsnull != child)) + { + //XXX this is really dumb but it will at least do something + + parent->InsertChild(child, nsnull); + } +} + +void nsViewManager :: RemoveChild(nsIView *parent, nsIView *child) +{ + parent->RemoveChild(child); +} + +void nsViewManager :: MoveViewBy(nsIView *aView, nscoord aX, nscoord aY) +{ + nscoord x, y; + + aView->GetPosition(&x, &y); + MoveViewTo(aView, aX + x, aY + y); +} + +void nsViewManager :: MoveViewTo(nsIView *aView, nscoord aX, nscoord aY) +{ + nscoord oldX; + nscoord oldY; + + aView->GetPosition(&oldX, &oldY); + aView->SetPosition(aX, aY); + + // only do damage control if the view is visible + + if (nsViewVisibility_kHide != aView->GetVisibility()) + { + nsRect bounds; + aView->GetBounds(bounds); + nsRect oldArea(oldX, oldY, bounds.width, bounds.height); + nsIView* parent = aView->GetParent(); // no addref + UpdateView(parent, &oldArea, 0); + nsRect newArea(aX, aY, bounds.width, bounds.height); + UpdateView(parent, &newArea, 0); + } +} + +void nsViewManager :: ResizeView(nsIView *aView, nscoord width, nscoord height) +{ +} + +void nsViewManager :: SetViewClip(nsIView *aView, nsRect *rect) +{ +} + +void nsViewManager :: SetViewVisibility(nsIView *aView, nsViewVisibility visible) +{ +} + +void nsViewManager :: SetViewZindex(nsIView *aView, PRInt32 zindex) +{ +} + +void nsViewManager :: MoveViewAbove(nsIView *aView, nsIView *other) +{ +} + +void nsViewManager :: MoveViewBelow(nsIView *aView, nsIView *other) +{ +} + +PRBool nsViewManager :: IsViewShown(nsIView *aView) +{ + return PR_TRUE; +} + +PRBool nsViewManager :: GetViewClipAbsolute(nsIView *aView, nsRect *rect) +{ + return PR_TRUE; +} + +nsIPresContext * nsViewManager :: GetPresContext() +{ + NS_IF_ADDREF(mContext); + return mContext; +} + +nsDrawingSurface nsViewManager :: GetDrawingSurface(nsIRenderingContext &aContext, nsRect& aBounds) +{ + + //if ((nsnull == mDrawingSurface) || (mDSBounds != aBounds)) + if((nsnull==mDrawingSurface) || ((mDSBounds.width < aBounds.width)||(mDSBounds.heightGetWidget(); + + if (nsnull != win) + break; + + //get absolute coordinates of view, but don't + //add in view pos since the first thing you ever + //need to do when painting a view is to translate + //the rendering context by the views pos and other parts + //of the code do this for us... + + if (par != &aView) + { + par->GetPosition(&x, &y); + + ax += x; + ay += y; + } + } + while (par = par->GetParent()); + + if (nsnull != win) + { + dx = mContext->GetDeviceContext(); + + cx = dx->CreateRenderingContext(&aView); + + cx->Translate(ax, ay); + + NS_RELEASE(dx); + NS_RELEASE(win); + } + + return cx; +} diff --git a/mozilla/view/src/nsViewManager.h b/mozilla/view/src/nsViewManager.h new file mode 100644 index 00000000000..88f96d1aa23 --- /dev/null +++ b/mozilla/view/src/nsViewManager.h @@ -0,0 +1,186 @@ +/* -*- 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. + */ + +#ifndef nsViewManager_h___ +#define nsViewManager_h___ + +#include "nsIViewManager.h" +#include "nsCRT.h" +#include "nsIPresContext.h" +#include "nsIWidget.h" +#include "nsITimer.h" + +class nsViewManager : public nsIViewManager +{ +public: + nsViewManager(); + + void* operator new(size_t sz) { + void* rv = new char[sz]; + nsCRT::zero(rv, sz); + return rv; + } + + NS_DECL_ISUPPORTS + + virtual nsresult Init(nsIPresContext* aPresContext); + + // Get the window for which the manager is responsible. + virtual void SetRootWindow(nsIWidget *aRootWindow); + virtual nsIWidget *GetRootWindow(); + + // Get and set the root of the layer tree. + virtual nsIView *GetRootView(); + virtual void SetRootView(nsIView *aView); + + // Get and set the current framerate i.e. the rate at which timed + // refreshes occur. A framerate of 0 indicates that timed refreshes + // should not occur. + virtual PRUint32 GetFrameRate(); + virtual nsresult SetFrameRate(PRUint32 frameRate); + + // Get and set the dimensions of the root window. The latter should + // be called if the root window is resized.. The dimensions are in + // twips + virtual void GetWindowDimensions(nscoord *width, nscoord *height); + virtual void SetWindowDimensions(nscoord width, nscoord height); + + // Get and set the position of the root window relative to the + // composited area. The latter should be called if the root window + // is scrolled. + virtual void GetWindowOffsets(nscoord *xoffset, nscoord *yoffset); + virtual void SetWindowOffsets(nscoord xoffset, nscoord yoffset); + + // Called to refresh an area of the root window. The coordinates of + // the region or rectangle passed in should be in the window's + // coordinate space. Often called in response to a paint/redraw event + // from the native windowing system. + virtual void Refresh(nsIRenderingContext *aContext, nsRegion *region, + PRUint32 aUpdateFlags); + virtual void Refresh(nsIView* aView, nsIRenderingContext *aContext, + nsRect *rect, PRUint32 aUpdateFlags); + + // Called to force a redrawing of any dirty areas. + virtual void Composite(); + + // Called to inform the layer manager that some portion of a layer + // is dirty and needs to be redrawn. The region or rect passed in + // should be in the layer's coordinate space. + virtual void UpdateView(nsIView *aView, nsRegion *region, + PRUint32 aUpdateFlags); + virtual void UpdateView(nsIView *aView, nsRect *rect, PRUint32 aUpdateFlags); + + // Called to dispatch an event to the appropriate layer. Often called + // as a result of receiving a mouse or keyboard event from the native + // event system. + virtual PRBool DispatchEvent(nsIEvent *event); + + // Used to grab/capture all events of the type (mouse or keyboard) for + // a specific layer, irrespective of the cursor position at which the + // event occurred. + virtual PRBool GrabMouseEvents(nsIView *aView); + virtual PRBool GrabKeyEvents(nsIView *aView); + + // Get the current layer, if any, that's capturing a specific type of + // event. + virtual nsIView* GetMouseEventGrabber(); + virtual nsIView* GetKeyEventGrabber(); + + // Given a parent layer, insert another layer as its child. If above + // is PR_TRUE, the layer is inserted above (in z-order) the sibling. If + // it is nsfalse, the layer is inserted below. + // The layer manager generates the appopriate dirty regions. + virtual void InsertChild(nsIView *parent, nsIView *child, nsIView *sibling, + PRBool above); + + // Given a parent layer, insert another layer as its child. The zindex + // indicates where the child should be inserted relative to other + // children of the parent. + // The layer manager generates the appopriate dirty regions. + virtual void InsertChild(nsIView *parent, nsIView *child, + PRInt32 zindex); + + // Remove a specific child of a layer. + // The layer manager generates the appopriate dirty regions. + virtual void RemoveChild(nsIView *parent, nsIView *child); + + // Move a layer's position by the specified amount. + // The layer manager generates the appopriate dirty regions. + virtual void MoveViewBy(nsIView *aView, nscoord x, nscoord y); + + // Move a layer to the specified position, provided in parent coordinates. + // The layer manager generates the appopriate dirty regions. + virtual void MoveViewTo(nsIView *aView, nscoord x, nscoord y); + + // Resize a layer to the specified width and height. + // The layer manager generates the appopriate dirty regions. + virtual void ResizeView(nsIView *aView, nscoord width, nscoord height); + + // Set the clip of a layer. + // The layer manager generates the appopriate dirty regions. + virtual void SetViewClip(nsIView *aView, nsRect *rect); + + // Set the visibility of a layer. + // The layer manager generates the appopriate dirty regions. + virtual void SetViewVisibility(nsIView *aView, nsViewVisibility visible); + + // Set the z-index of a layer. Positive z-indices mean that a layer + // is above its parent in z-order. Negative z-indices mean that a + // layer is below its parent. + // The layer manager generates the appopriate dirty regions. + virtual void SetViewZindex(nsIView *aView, PRInt32 zindex); + + // Used to move a layer above or below another in z-order. + // The layer manager generates the appopriate dirty regions. + virtual void MoveViewAbove(nsIView *aView, nsIView *other); + virtual void MoveViewBelow(nsIView *aView, nsIView *other); + + // Returns whether a layer is actually shown (based on its visibility + // and that of its ancestors). + virtual PRBool IsViewShown(nsIView *aView); + + // Returns the clipping area of layer in absolute coordinates. + virtual PRBool GetViewClipAbsolute(nsIView *aView, nsRect *rect); + + // Get the presentation context associated with this manager + virtual nsIPresContext* GetPresContext(); + + virtual void ClearDirtyRegion(); + + nsDrawingSurface GetDrawingSurface(nsIRenderingContext &aContext, nsRect& aBounds); + +private: + ~nsViewManager(); + nsIRenderingContext *CreateRenderingContext(nsIView &aView); + + nsIPresContext *mContext; + nsIWidget *mRootWindow; + nsPoint mOffset; + nsRect mDSBounds; + nsDrawingSurface mDrawingSurface; + +public: + //these are public so that our timer callback can poke them. + nsITimer *mTimer; + nsRect mDirtyRect; + nsIView *mRootView; + PRUint32 mFrameRate; +}; + +#endif + diff --git a/mozilla/webshell/Makefile b/mozilla/webshell/Makefile new file mode 100644 index 00000000000..def05c31f80 --- /dev/null +++ b/mozilla/webshell/Makefile @@ -0,0 +1,24 @@ +#!gmake +# +# 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. + +DEPTH = .. + +DIRS = public src tests + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/webshell/makefile.win b/mozilla/webshell/makefile.win new file mode 100644 index 00000000000..9b672228e7d --- /dev/null +++ b/mozilla/webshell/makefile.win @@ -0,0 +1,23 @@ +#!nmake +# +# 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. + +DEPTH=.. +IGNORE_MANIFEST=1 + +DIRS=public src tests + +include <$(DEPTH)\config\rules.mak> diff --git a/mozilla/webshell/public/Makefile b/mozilla/webshell/public/Makefile new file mode 100644 index 00000000000..f7b0b206360 --- /dev/null +++ b/mozilla/webshell/public/Makefile @@ -0,0 +1,30 @@ +#!gmake +# +# 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. + +DEPTH = ../.. + +MODULE = raptor + +EXPORTS = \ + nsILinkHandler.h \ + nsIWebWidget.h \ + nsweb.h \ + $(NULL) + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/webshell/public/makefile.win b/mozilla/webshell/public/makefile.win new file mode 100644 index 00000000000..714743f81ce --- /dev/null +++ b/mozilla/webshell/public/makefile.win @@ -0,0 +1,31 @@ +#!nmake +# +# 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. + +DEPTH=..\.. + +IGNORE_MANIFEST=1 + +MODULE=raptor + +EXPORTS = \ + nsILinkHandler.h \ + nsIWebWidget.h \ + nsweb.h \ + $(NULL) + +include <$(DEPTH)\config\rules.mak> + diff --git a/mozilla/webshell/public/nsILinkHandler.h b/mozilla/webshell/public/nsILinkHandler.h new file mode 100644 index 00000000000..8163ef04eed --- /dev/null +++ b/mozilla/webshell/public/nsILinkHandler.h @@ -0,0 +1,54 @@ +/* -*- 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. + */ +#ifndef nsILinkHandler_h___ +#define nsILinkHandler_h___ + +#include "nsweb.h" +#include "nsIWebWidget.h" +class nsIFrame; +class nsString; +struct nsGUIEvent; + +/* 52bd1e30-ce3f-11d1-9328-00805f8add32 */ +#define NS_ILINKHANDLER_IID \ +{ 0x52bd1e30, 0xce3f, 0x11d1, \ + {0x93, 0x28, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +/** + * Interface used for handling clicks on links + */ +class nsILinkHandler : public nsISupports { +public: + NS_IMETHOD Init(nsIWebWidget* aWidget) = 0; + + NS_IMETHOD GetWebWidget(nsIWebWidget** aResult) = 0; + + /** + * Process a click on a link. aFrame is the frame that contains the + * linked content. aURLSpec is an absolute url spec that defines the + * destination for the link. aTargetSpec indicates where the link is + * targeted (it may be an empty string). + */ + NS_IMETHOD OnLinkClick(nsIFrame* aFrame, const nsString& aURLSpec, + const nsString& aTargetSpec) = 0; +}; + +// Standard link handler that does what you would expect (XXX doc...) +extern NS_WEB nsresult NS_NewLinkHandler(nsILinkHandler** aInstancePtrResult); + +#endif /* nsILinkHandler_h___ */ diff --git a/mozilla/webshell/public/nsIWebWidget.h b/mozilla/webshell/public/nsIWebWidget.h new file mode 100644 index 00000000000..087d2fdf775 --- /dev/null +++ b/mozilla/webshell/public/nsIWebWidget.h @@ -0,0 +1,98 @@ +/* -*- 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. + */ +#ifndef nsIWebWidget_h___ +#define nsIWebWidget_h___ + +#include "nsweb.h" +#include "nsIWidget.h" +#include "nsRect.h" +class nsIDocument; +class nsILinkHandler; +class nsIPresContext; +class nsIStyleSet; +class nsString; +class nsIScriptContext; + +// IID for the nsWebWidget interface +#define NS_IWEBWIDGET_IID \ + { 0x02606880, 0x94e1, 0x11d1, \ + {0x89, 0x5c, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } + +// Interface to the web widget. The web widget is a container for web +// content. +class nsIWebWidget : public nsISupports { +public: + // Create a native window for this web widget; may be called once + virtual nsresult Init(nsNativeWindow aNativeParent, + const nsRect& aBounds) = 0; + + // Create a native window for this web widget; may be called once. + // Use the given presentation context and document for the widget + // (this widget becomes a second view on the document using the + // context for presentation). + virtual nsresult Init(nsNativeWindow aNativeParent, + const nsRect& aBounds, + nsIDocument* aDocument, + nsIPresContext* aPresContext) = 0; + + virtual nsRect GetBounds() = 0; + + virtual void SetBounds(const nsRect& aBounds) = 0; + + virtual void Show() = 0; + + virtual void Hide() = 0; + + NS_IMETHOD SetContainer(nsISupports* aContainer) = 0; + + NS_IMETHOD GetContainer(nsISupports** aResult) = 0; + + NS_IMETHOD SetLinkHandler(nsILinkHandler* aHandler) = 0; + + NS_IMETHOD GetLinkHandler(nsILinkHandler** aResult) = 0; + + NS_IMETHOD LoadURL(const nsString& aURLSpec) = 0; + + virtual nsIDocument* GetDocument() = 0; + + virtual void HackAppendContent() = 0; + + virtual void DumpContent(FILE* out = nsnull) = 0; + + virtual void DumpFrames(FILE* out = nsnull) = 0; + + virtual void DumpStyle(FILE* out = nsnull) = 0; + + virtual void DumpViews(FILE* out = nsnull) = 0; + + virtual void ShowFrameBorders(PRBool aEnable) = 0; + + virtual PRBool GetShowFrameBorders() = 0; + + virtual nsIWidget* GetWWWindow() = 0; + + virtual nsresult GetScriptContext(nsIScriptContext **aContext) = 0; + virtual nsresult ReleaseScriptContext() = 0; +}; + +// Create a new web widget that uses the default (galley) presentation +// context. +extern NS_WEB nsresult +NS_NewWebWidget(nsIWebWidget** aInstancePtrResult); + +#endif /* nsWebWidget_h___ */ diff --git a/mozilla/webshell/public/nsweb.h b/mozilla/webshell/public/nsweb.h new file mode 100644 index 00000000000..56701ef2c6b --- /dev/null +++ b/mozilla/webshell/public/nsweb.h @@ -0,0 +1,27 @@ +/* -*- 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. + */ +#ifndef nsweb_h___ +#define nsweb_h___ + +#ifdef _IMPL_NS_WEB +#define NS_WEB NS_EXPORT +#else +#define NS_WEB NS_IMPORT +#endif + +#endif /* nsweb_h___ */ diff --git a/mozilla/webshell/src/Makefile b/mozilla/webshell/src/Makefile new file mode 100644 index 00000000000..a9d11aa41ca --- /dev/null +++ b/mozilla/webshell/src/Makefile @@ -0,0 +1,38 @@ +#!gmake +# +# 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. + +DEPTH = ../.. + +MODULE=raptor + +DEFINES = -D_IMPL_NS_WEB + +CPPSRCS= \ + nsLinkHandler.cpp \ + nsWebWidget.cpp \ + $(NULL) + +CPP_OBJS= \ + ./$(OBJDIR)/nsLinkHandler.o \ + ./$(OBJDIR)/nsWebWidget.o \ + $(NULL) + +include $(DEPTH)/config/config.mk + +TARGETS = $(LIBRARY) + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/webshell/src/makefile.win b/mozilla/webshell/src/makefile.win new file mode 100644 index 00000000000..a99573f4787 --- /dev/null +++ b/mozilla/webshell/src/makefile.win @@ -0,0 +1,65 @@ +#!nmake +# +# 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. + +DEPTH=..\.. +IGNORE_MANIFEST=1 + +DEFINES=-D_IMPL_NS_WEB +MODULE=raptor + +CPPSRCS= \ + nsLinkHandler.cpp \ + nsWebWidget.cpp \ + $(NULL) + +CPP_OBJS= \ + .\$(OBJDIR)\nsLinkHandler.obj \ + .\$(OBJDIR)\nsWebWidget.obj \ + $(NULL) + +LINCS=-I$(XPDIST)\public\xpcom -I$(XPDIST)\public\raptor -I$(XPDIST)\public\dom -I$(XPDIST)\public\js + +MAKE_OBJ_TYPE = DLL +DLLNAME = raptorweb +DLL=.\$(OBJDIR)\$(DLLNAME).dll + +LCFLAGS = \ + $(LCFLAGS) \ + $(DEFINES) \ + $(NULL) + +# These are the libraries we need to link with to create the dll +LLIBS= \ + $(DIST)\lib\xpcom32.lib \ + $(DIST)\lib\raptorbase.lib \ + $(DIST)\lib\raptorgfx.lib \ + $(DIST)\lib\raptorhtml.lib \ + $(DIST)\lib\img3240.lib \ + $(DIST)\lib\util.lib \ + $(DIST)\lib\libplc21.lib \ + $(DIST)\lib\jsdom.lib \ + $(LIBNSPR) + +include <$(DEPTH)\config\rules.mak> + +install:: $(DLL) + $(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).dll $(DIST)\bin + $(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).lib $(DIST)\lib + +clobber:: + rm -f $(DIST)\bin\$(DLLNAME).dll + rm -f $(DIST)\lib\$(DLLNAME).lib diff --git a/mozilla/webshell/src/nsLinkHandler.cpp b/mozilla/webshell/src/nsLinkHandler.cpp new file mode 100644 index 00000000000..a540ee16af9 --- /dev/null +++ b/mozilla/webshell/src/nsLinkHandler.cpp @@ -0,0 +1,175 @@ +/* -*- 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 "nsILinkHandler.h" +#include "nsString.h" +#include "nsCRT.h" +#include "prthread.h" +#include "plevent.h" + +static NS_DEFINE_IID(kILinkHandlerIID, NS_ILINKHANDLER_IID); + +class LinkHandlerImpl : public nsILinkHandler { +public: + LinkHandlerImpl(); + ~LinkHandlerImpl(); + + void* operator new(size_t sz) { + void* rv = new char[sz]; + nsCRT::zero(rv, sz); + return rv; + } + + // nsISupports + NS_DECL_ISUPPORTS; + + // nsILinkHandler + NS_IMETHOD Init(nsIWebWidget* aWidget); + NS_IMETHOD GetWebWidget(nsIWebWidget** aResult); + NS_IMETHOD OnLinkClick(nsIFrame* aFrame, const nsString& aURLSpec, + const nsString& aTargetSpec); + + void HandleLinkClickEvent(const nsString& aURLSpec, + const nsString& aTargetSpec); + + nsIWebWidget* mWidget; +}; + +//---------------------------------------------------------------------- + +struct OnLinkClickEvent : public PLEvent { + OnLinkClickEvent(LinkHandlerImpl* aHandler, const nsString& aURLSpec, + const nsString& aTargetSpec); + ~OnLinkClickEvent(); + + void HandleEvent(); + + LinkHandlerImpl* mHandler; + nsString* mURLSpec; + nsString* mTargetSpec; +}; + +static void PR_CALLBACK HandleEvent(OnLinkClickEvent* aEvent) +{ + aEvent->HandleEvent(); +} + +static void PR_CALLBACK DestroyEvent(OnLinkClickEvent* aEvent) +{ + delete aEvent; +} + +OnLinkClickEvent::OnLinkClickEvent(LinkHandlerImpl* aHandler, + const nsString& aURLSpec, + const nsString& aTargetSpec) +{ + mHandler = aHandler; + NS_ADDREF(aHandler); + mURLSpec = new nsString(aURLSpec); + mTargetSpec = new nsString(aTargetSpec); + + PL_InitEvent(this, nsnull, + (PLHandleEventProc) ::HandleEvent, + (PLDestroyEventProc) ::DestroyEvent); + +#ifdef XP_PC + PLEventQueue* eventQueue = PL_GetMainEventQueue(); +#endif + PL_PostEvent(eventQueue, this); +} + +OnLinkClickEvent::~OnLinkClickEvent() +{ + NS_IF_RELEASE(mHandler); + if (nsnull != mURLSpec) delete mURLSpec; + if (nsnull != mTargetSpec) delete mTargetSpec; +} + +void OnLinkClickEvent::HandleEvent() +{ + mHandler->HandleLinkClickEvent(*mURLSpec, *mTargetSpec); +} + +//---------------------------------------------------------------------- + +LinkHandlerImpl::LinkHandlerImpl() +{ +} + +LinkHandlerImpl::~LinkHandlerImpl() +{ +} + +NS_IMPL_ISUPPORTS(LinkHandlerImpl, kILinkHandlerIID); + +// this Init method assumes that the nsIWebWidget passed in owns this +// LinkHandlerImpl also, so it wont refcount the aWidget. +NS_IMETHODIMP LinkHandlerImpl::Init(nsIWebWidget* aWidget) +{ + NS_PRECONDITION(nsnull != aWidget, "null ptr"); + NS_PRECONDITION(nsnull == mWidget, "init twice"); + if (nsnull == aWidget) { + return NS_ERROR_NULL_POINTER; + } + if (nsnull != mWidget) { + return NS_ERROR_ALREADY_INITIALIZED; + } + mWidget = aWidget; + //NS_ADDREF(mWidget); // this widget is owned by the same owner of the LinkHandler, no circular ref. + return NS_OK; +} + +NS_IMETHODIMP LinkHandlerImpl::GetWebWidget(nsIWebWidget** aResult) +{ + NS_PRECONDITION(nsnull != aResult, "null ptr"); + if (nsnull == aResult) { + return NS_ERROR_NULL_POINTER; + } + *aResult = mWidget; + NS_IF_ADDREF(mWidget); + return NS_OK; +} + +NS_IMETHODIMP LinkHandlerImpl::OnLinkClick(nsIFrame* aFrame, + const nsString& aURLSpec, + const nsString& aTargetSpec) + +{ + new OnLinkClickEvent(this, aURLSpec, aTargetSpec); + return NS_OK; +} + +void LinkHandlerImpl::HandleLinkClickEvent(const nsString& aURLSpec, + const nsString& aTargetSpec) +{ + if (nsnull != mWidget) { + mWidget->LoadURL(aURLSpec); + } +} + +NS_WEB nsresult NS_NewLinkHandler(nsILinkHandler** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + LinkHandlerImpl* it = new LinkHandlerImpl(); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kILinkHandlerIID, (void**) aInstancePtrResult); +} diff --git a/mozilla/webshell/src/nsWebWidget.cpp b/mozilla/webshell/src/nsWebWidget.cpp new file mode 100644 index 00000000000..689b54a9057 --- /dev/null +++ b/mozilla/webshell/src/nsWebWidget.cpp @@ -0,0 +1,693 @@ +/* -*- 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 +#include "nsIWebWidget.h" +#include "nsILinkHandler.h" +#include "nsIURL.h" +#include "nsIPresContext.h" +#include "nsIPresShell.h" +#include "nsIContent.h" +#include "nsIDocument.h" +#include "nsIFrame.h" +#include "nsIWidget.h" +#include "nsIScrollbar.h" +#include "nsUnitConversion.h" +#include "nsViewsCID.h" +#include "nsIView.h" +#include "nsIViewManager.h" +#include "nsCRT.h" +#include "nsIStyleSet.h" +#include "nsIStyleSheet.h" +#include "nsWidgetsCID.h" +#include "nsString.h" +#include "nsIScriptContext.h" +#include "nsIScriptObjectOwner.h" + +#include "nsICSSParser.h" + +#define UA_CSS_URL "resource:/res/ua.css" + +#define GET_OUTER() \ + ((nsWebWidget*) ((char*)this - nsWebWidget::GetOuterOffset())) + +// Machine independent implementation portion of the web widget +class WebWidgetImpl : public nsIWebWidget, public nsIScriptObjectOwner { +public: + WebWidgetImpl(); + ~WebWidgetImpl(); + + void* operator new(size_t sz) { + void* rv = new char[sz]; + nsCRT::zero(rv, sz); + return rv; + } + + NS_DECL_ISUPPORTS + + virtual nsresult Init(nsNativeWindow aParent, + const nsRect& aBounds); + virtual nsresult Init(nsNativeWindow aParent, + const nsRect& aBounds, + nsIDocument* aDocument, + nsIPresContext* aPresContext); + + virtual nsRect GetBounds(); + virtual void SetBounds(const nsRect& aBounds); + virtual void Show(); + virtual void Hide(); + + NS_IMETHOD SetContainer(nsISupports* aContainer); + + NS_IMETHOD GetContainer(nsISupports** aResult); + + NS_IMETHOD SetLinkHandler(nsILinkHandler* aHandler); + + NS_IMETHOD GetLinkHandler(nsILinkHandler** aResult); + + NS_IMETHOD LoadURL(const nsString& aURL); + + virtual nsIDocument* GetDocument(); + + virtual void HackAppendContent(); + virtual void DumpContent(FILE* out); + virtual void DumpFrames(FILE* out); + virtual void DumpStyle(FILE* out); + virtual void DumpViews(FILE* out); + virtual void ShowFrameBorders(PRBool aEnable); + virtual PRBool GetShowFrameBorders(); + virtual nsIWidget* GetWWWindow(); + virtual nsresult GetScriptContext(nsIScriptContext **aContext); + virtual nsresult ReleaseScriptContext(); + + virtual nsresult GetScriptObject(JSContext *aContext, void** aScriptObject); + virtual nsresult ResetScriptObject(); + +private: + nsresult ProvideDefaultHandlers(); + void ForceRefresh(); + nsresult MakeWindow(nsNativeWindow aParent, const nsRect& aBounds); + nsresult InitUAStyleSheet(void); + nsresult CreateStyleSet(nsIDocument* aDocument, nsIStyleSet** aStyleSet); + + nsIWidget* mWindow; + nsIView *mView; + nsIViewManager *mViewManager; + nsIPresContext* mPresContext; + nsIPresShell* mPresShell; + nsIStyleSheet* mUAStyleSheet; + nsILinkHandler* mLinkHandler; + nsISupports* mContainer; + nsIScriptContext* mScriptContext; + void* mScriptObject; +}; + +//---------------------------------------------------------------------- + +static NS_DEFINE_IID(kIWebWidgetIID, NS_IWEBWIDGET_IID); + +// Note: operator new zeros our memory +WebWidgetImpl::WebWidgetImpl() +{ +} + +nsresult WebWidgetImpl::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if (NULL == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + static NS_DEFINE_IID(kIScriptObjectOwnerIID, NS_ISCRIPTOBJECTOWNER_IID); + if (aIID.Equals(kIWebWidgetIID)) { + *aInstancePtr = (void*)(nsIWebWidget*)this; + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIScriptObjectOwnerIID)) { + *aInstancePtr = (void*)(nsIScriptObjectOwner*)this; + AddRef(); + return NS_OK; + } + if (aIID.Equals(kISupportsIID)) { + *aInstancePtr = (void*)(nsISupports*)(nsIWebWidget*)this; + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +NS_IMPL_ADDREF(WebWidgetImpl) +NS_IMPL_RELEASE(WebWidgetImpl) + +WebWidgetImpl::~WebWidgetImpl() +{ + // Release windows and views + NS_IF_RELEASE(mViewManager); + NS_IF_RELEASE(mWindow); + NS_IF_RELEASE(mView); + + NS_IF_RELEASE(mContainer); + NS_IF_RELEASE(mLinkHandler); + + // Note: release context then shell + NS_IF_RELEASE(mPresContext); + NS_IF_RELEASE(mPresShell); + NS_IF_RELEASE(mUAStyleSheet); + + NS_IF_RELEASE(mScriptContext); +} + +nsresult WebWidgetImpl::MakeWindow(nsNativeWindow aNativeParent, + const nsRect& aBounds) +{ + nsresult rv; + static NS_DEFINE_IID(kViewManagerCID, NS_VIEW_MANAGER_CID); + static NS_DEFINE_IID(kIViewManagerIID, NS_IVIEWMANAGER_IID); + + rv = NSRepository::CreateInstance(kViewManagerCID, + nsnull, + kIViewManagerIID, + (void **)&mViewManager); + + if ((NS_OK != rv) || (NS_OK != mViewManager->Init(mPresContext))) { + return rv; + } + + nsRect tbounds = aBounds; + tbounds *= mPresContext->GetPixelsToTwips(); + + // Create a child window of the parent that is our "root view/window" + // Create a view + static NS_DEFINE_IID(kScrollingViewCID, NS_SCROLLING_VIEW_CID); + static NS_DEFINE_IID(kIViewIID, NS_IVIEW_IID); + + rv = NSRepository::CreateInstance(kScrollingViewCID, + nsnull, + kIViewIID, + (void **)&mView); + + static NS_DEFINE_IID(kWidgetCID, NS_CHILD_CID); + if ((NS_OK != rv) || (NS_OK != mView->Init(mViewManager, + tbounds, + nsnull, + &kWidgetCID, + aNativeParent))) { + return rv; + } + + // Setup hierarchical relationship in view manager + mViewManager->SetRootView(mView); + mWindow = mView->GetWidget(); + if (mWindow) { + mViewManager->SetRootWindow(mWindow); + } + + return rv; +} + +nsresult WebWidgetImpl::Init(nsNativeWindow aNativeParent, + const nsRect& aBounds) +{ + // Create presentation context + nsresult rv = NS_NewGalleyContext(&mPresContext); + if (NS_OK != rv) { + return rv; + } + return MakeWindow(aNativeParent, aBounds); +} + +nsresult WebWidgetImpl::InitUAStyleSheet(void) +{ + nsresult rv = NS_OK; + + if (nsnull == mUAStyleSheet) { // snarf one + nsIURL* uaURL; + rv = NS_NewURL(&uaURL, nsnull, UA_CSS_URL); // XXX this bites, fix it + if (NS_OK == rv) { + // Get an input stream from the url + PRInt32 ec; + nsIInputStream* in = uaURL->Open(&ec); + if (nsnull != in) { + // Translate the input using the argument character set id into unicode + nsIUnicharInputStream* uin; + rv = NS_NewConverterStream(&uin, nsnull, in); + if (NS_OK == rv) { + // Create parser and set it up to process the input file + nsICSSParser* css; + rv = NS_NewCSSParser(&css); + if (NS_OK == rv) { + // Parse the input and produce a style set + mUAStyleSheet = css->Parse(&ec, uin, uaURL); + + NS_RELEASE(css); + } + NS_RELEASE(uin); + } + NS_RELEASE(in); + } + else { +// printf("open of %s failed: error=%x\n", UA_CSS_URL, ec); + rv = NS_ERROR_ILLEGAL_VALUE; // XXX need a better error code here + } + + NS_RELEASE(uaURL); + } + } + return rv; +} + +nsresult WebWidgetImpl::Init(nsNativeWindow aNativeParent, + const nsRect& aBounds, + nsIDocument* aDocument, + nsIPresContext* aPresContext) +{ + NS_PRECONDITION(nsnull != aPresContext, "null ptr"); + NS_PRECONDITION(nsnull != aDocument, "null ptr"); + if ((nsnull == aPresContext) || (nsnull == aDocument)) { + return NS_ERROR_NULL_POINTER; + } + + mPresContext = aPresContext; + NS_ADDREF(aPresContext); + + nsresult rv = MakeWindow(aNativeParent, aBounds); + if (NS_OK != rv) { + return rv; + } + + nsIStyleSet* styleSet; + rv = CreateStyleSet(aDocument, &styleSet); + if (NS_OK != rv) { + return rv; + } + + // Now make the shell for the document + mPresShell = aDocument->CreateShell(mPresContext, mViewManager, styleSet); + NS_RELEASE(styleSet); + + // Now that we have a presentation shell trigger a reflow so we + // create a frame model + nsRect bounds; + mWindow->GetBounds(bounds); + if (nsnull != mPresShell) { + nscoord width = bounds.width; + nscoord height = bounds.height; + width = NS_TO_INT_ROUND(width * mPresContext->GetPixelsToTwips()); + height = NS_TO_INT_ROUND(height * mPresContext->GetPixelsToTwips()); + mViewManager->SetWindowDimensions(width, height); + } + ForceRefresh(); + return rv; +} + +nsRect WebWidgetImpl::GetBounds() +{ + NS_PRECONDITION(nsnull != mWindow, "null window"); + nsRect zr(0, 0, 0, 0); + if (nsnull != mWindow) { + mWindow->GetBounds(zr); + } + return zr; +} + +void WebWidgetImpl::SetBounds(const nsRect& aBounds) +{ + NS_PRECONDITION(nsnull != mWindow, "null window"); + if (nsnull != mWindow) { + mWindow->Resize(aBounds.x, aBounds.y, aBounds.width, aBounds.height); + } +} + +void WebWidgetImpl::Show() +{ + NS_PRECONDITION(nsnull != mWindow, "null window"); + if (nsnull != mWindow) { + mWindow->Show(PR_TRUE); + } +} + +void WebWidgetImpl::Hide() +{ + NS_PRECONDITION(nsnull != mWindow, "null window"); + if (nsnull != mWindow) { + mWindow->Show(PR_FALSE); + } +} + +nsresult WebWidgetImpl::ProvideDefaultHandlers() +{ + // Provide a default link handler if needed + if (nsnull == mLinkHandler) { + nsresult rv = NS_NewLinkHandler(&mLinkHandler); + if (NS_OK != rv) { + return rv; + } + if (NS_OK != mLinkHandler->Init(this)) { + NS_RELEASE(mLinkHandler); + return rv; + } + if (nsnull != mPresContext) { + mPresContext->SetLinkHandler(mLinkHandler); + } + } + return NS_OK; +} + +// XXX need to save old document in case of failure? Does caller do that? + +NS_IMETHODIMP WebWidgetImpl::LoadURL(const nsString& aURLSpec) +{ +#ifdef NS_DEBUG + printf("WebWidgetImpl::LoadURL: loadURL("); + fputs(aURLSpec, stdout); + printf(")\n"); +#endif + + nsresult rv = ProvideDefaultHandlers(); + if (NS_OK != rv) { + return rv; + } + + nsIURL* url; + rv = NS_NewURL(&url, aURLSpec); + if (NS_OK != rv) { + return rv; + } + + + if (nsnull != mPresShell) { + // Break circular reference first + mPresShell->EndObservingDocument(); + + // Then release the shell + NS_RELEASE(mPresShell); + mPresShell = nsnull; + } + + // Create document + nsIDocument* doc; + rv = NS_NewHTMLDocument(&doc); + + // Create style set + nsIStyleSet* styleSet = nsnull; + rv = CreateStyleSet(doc, &styleSet); + if (NS_OK != rv) { + NS_RELEASE(doc); + return rv; + } + + // Create presentation shell + mPresShell = doc->CreateShell(mPresContext, mViewManager, styleSet);/* XXX bad api */ + if (nsnull == mPresShell) { + rv = NS_ERROR_OUT_OF_MEMORY; + } + + // Setup view manager's window + nsRect bounds; + mWindow->GetBounds(bounds); + if (nsnull != mPresShell) { + float p2t = mPresContext->GetPixelsToTwips(); + nscoord width = NS_TO_INT_ROUND(bounds.width * p2t); + nscoord height = NS_TO_INT_ROUND(bounds.height * p2t); + mViewManager->SetWindowDimensions(width, height); + } + + // Now load the document + doc->LoadURL(url); + + NS_RELEASE(styleSet); + NS_RELEASE(doc); + + ForceRefresh();/* XXX temporary */ + + return NS_OK; +} + +nsIDocument* WebWidgetImpl::GetDocument() +{ + if (nsnull != mPresShell) { + return mPresShell->GetDocument(); + } + return nsnull; +} + +NS_IMETHODIMP WebWidgetImpl::SetLinkHandler(nsILinkHandler* aHandler) +{ + NS_IF_RELEASE(mLinkHandler); + mLinkHandler = aHandler; + NS_IF_ADDREF(aHandler); + if (nsnull != mPresContext) { + mPresContext->SetLinkHandler(aHandler); + } + return NS_OK; +} + +NS_IMETHODIMP WebWidgetImpl::GetLinkHandler(nsILinkHandler** aResult) +{ + NS_PRECONDITION(nsnull != aResult, "null ptr"); + if (nsnull == aResult) { + return NS_ERROR_NULL_POINTER; + } + *aResult = mLinkHandler; + NS_IF_ADDREF(mLinkHandler); + return NS_OK; +} + +NS_IMETHODIMP WebWidgetImpl::SetContainer(nsISupports* aContainer) +{ + NS_IF_RELEASE(mContainer); + mContainer = aContainer; + NS_IF_ADDREF(aContainer); + if (nsnull != mPresContext) { + mPresContext->SetContainer(aContainer); + } + return NS_OK; +} + +NS_IMETHODIMP WebWidgetImpl::GetContainer(nsISupports** aResult) +{ + NS_PRECONDITION(nsnull != aResult, "null ptr"); + if (nsnull == aResult) { + return NS_ERROR_NULL_POINTER; + } + *aResult = mContainer; + NS_IF_ADDREF(mContainer); + return NS_OK; +} + +//---------------------------------------------------------------------- +// Debugging methods + +void WebWidgetImpl::DumpContent(FILE* out) +{ + if (nsnull == out) { + out = stdout; + } + if (nsnull != mPresShell) { + nsIDocument* doc = mPresShell->GetDocument(); + if (nsnull != doc) { + nsIContent* root = doc->GetRootContent(); + if (nsnull == root) { + fputs("null root content\n", out); + } else { + root->List(out); + NS_RELEASE(root); + } + NS_RELEASE(doc); + } else { + fputs("null document\n", out); + } + } else { + fputs("null pres shell\n", out); + } +} + +void WebWidgetImpl::DumpFrames(FILE* out) +{ + if (nsnull == out) { + out = stdout; + } + if (nsnull != mPresShell) { + nsIFrame* root = mPresShell->GetRootFrame(); + if (nsnull == root) { + fputs("null root frame\n", out); + } else { + root->List(out); + } + } else { + fputs("null pres shell\n", out); + } +} + +void WebWidgetImpl::DumpStyle(FILE* out) +{ + if (nsnull == out) { + out = stdout; + } + if (nsnull != mPresShell) { + nsIStyleSet* styleSet = mPresShell->GetStyleSet(); + if (nsnull == styleSet) { + fputs("null style set\n", out); + } else { + styleSet->List(out); + NS_RELEASE(styleSet); + } + } else { + fputs("null pres shell\n", out); + } +} + +void WebWidgetImpl::DumpViews(FILE* out) +{ + if (nsnull == out) { + out = stdout; + } + if (nsnull != mView) { + mView->List(out); + } else { + fputs("null view\n", out); + } +} + +void WebWidgetImpl::ShowFrameBorders(PRBool aEnable) +{ + nsIFrame::ShowFrameBorders(aEnable); + ForceRefresh(); +} + +PRBool WebWidgetImpl::GetShowFrameBorders() +{ + return nsIFrame::GetShowFrameBorders(); +} + +void WebWidgetImpl::ForceRefresh() +{ + mWindow->Invalidate(PR_TRUE); +} + +NS_WEB nsresult +NS_NewWebWidget(nsIWebWidget** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + WebWidgetImpl* it = new WebWidgetImpl(); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIWebWidgetIID, (void **) aInstancePtrResult); +} + +//---------------------------------------------------------------------- +// XXX temporary code + +nsresult WebWidgetImpl::CreateStyleSet(nsIDocument* aDocument, nsIStyleSet** aStyleSet) +{ // this should eventually get expanded to allow for creating different sets for different media + nsresult rv = InitUAStyleSheet(); + + if (NS_OK != rv) { + NS_WARNING("unable to load UA style sheet"); +// return rv; + } + + rv = NS_NewStyleSet(aStyleSet); + if (NS_OK == rv) { + PRInt32 count = aDocument->GetNumberOfStyleSheets(); + for (PRInt32 index = 0; index < count; index++) { + nsIStyleSheet* sheet = aDocument->GetStyleSheetAt(index); + (*aStyleSet)->AppendDocStyleSheet(sheet); + NS_RELEASE(sheet); + } + if (nsnull != mUAStyleSheet) { + (*aStyleSet)->AppendBackstopStyleSheet(mUAStyleSheet); + } + } + return rv; +} + +void WebWidgetImpl::HackAppendContent() +{ +#ifdef NS_DEBUG + + if (nsnull != mPresShell) { + nsIDocument* doc = mPresShell->GetDocument(); + if (nsnull != doc) { + NS_HackAppendContent(doc); + NS_RELEASE(doc); + } + } + +#endif +} + +nsIWidget* WebWidgetImpl::GetWWWindow() +{ + if (nsnull != mWindow) { + NS_ADDREF(mWindow); + } + return mWindow; +} + +nsresult WebWidgetImpl::GetScriptContext(nsIScriptContext **aContext) +{ + NS_PRECONDITION(nsnull != aContext, "null arg"); + nsresult res = NS_OK; + + if (nsnull == mScriptContext) { + res = NS_CreateContext(this, &mScriptContext); + } + + if (NS_OK == res) { + NS_ADDREF(mScriptContext); + *aContext = mScriptContext; + } + + return res; +} + +nsresult WebWidgetImpl::ResetScriptObject() +{ + mScriptObject = nsnull; + return NS_OK; +} + +nsresult WebWidgetImpl::ReleaseScriptContext() +{ + NS_IF_RELEASE(mScriptContext); + mScriptContext = nsnull; + + return NS_OK; +} + +nsresult WebWidgetImpl::GetScriptObject(JSContext *aContext, void** aScriptObject) +{ + NS_PRECONDITION(nsnull != aScriptObject, "null arg"); + nsresult res = NS_OK; + if (nsnull == mScriptObject) { + mScriptObject = mScriptContext->GetGlobalObject(); + if (nsnull == mScriptObject) { + res = NS_ERROR_FAILURE; + } + } + + *aScriptObject = (void*)mScriptObject; + return res; +} + + + diff --git a/mozilla/webshell/tests/Makefile b/mozilla/webshell/tests/Makefile new file mode 100644 index 00000000000..0725c58d807 --- /dev/null +++ b/mozilla/webshell/tests/Makefile @@ -0,0 +1,22 @@ +#!gmake +# +# 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. + +DEPTH = ../.. + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/webshell/tests/imgtest/ImageTest.cpp b/mozilla/webshell/tests/imgtest/ImageTest.cpp new file mode 100644 index 00000000000..4aceca1756e --- /dev/null +++ b/mozilla/webshell/tests/imgtest/ImageTest.cpp @@ -0,0 +1,402 @@ +/* -*- Mode: C; tab-width: 4; 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. + */ + +//we need openfilename stuff... MMP +#ifdef WIN32_LEAN_AND_MEAN +#undef WIN32_LEAN_AND_MEAN +#endif + +#include "prtypes.h" +#include +#include "resources.h" +#include "nsIImageManager.h" +#include "nsIImageGroup.h" +#include "nsIImageRequest.h" +#include "nsIImageObserver.h" +#include "nsIRenderingContext.h" +#include "nsIImage.h" +#include "nsIWidget.h" +#include "nsGUIEvent.h" +#include "nsRect.h" +#include "nsWidgetsCID.h" +#include "nsGfxCIID.h" + +static NS_DEFINE_IID(kIWidgetIID, NS_IWIDGET_IID); +static NS_DEFINE_IID(kIImageObserverIID, NS_IIMAGEREQUESTOBSERVER_IID); + +static NS_DEFINE_IID(kCWindowIID, NS_WINDOW_CID); +static NS_DEFINE_IID(kCChildWindowIID, NS_CHILD_CID); +static NS_DEFINE_IID(kCScrollbarIID, NS_VERTSCROLLBAR_CID); + +static char* class1Name = "ImageTest"; + +static HANDLE gInstance, gPrevInstance; +static nsIImageManager *gImageManager = nsnull; +static nsIImageGroup *gImageGroup = nsnull; +static nsIImageRequest *gImageReq = nsnull; +static HWND gHwnd; +static nsIWidget *gWindow = nsnull; +static nsIImage *gImage = nsnull; +static PRBool gInstalledColorMap = PR_FALSE; + +class MyObserver : public nsIImageRequestObserver { +public: + MyObserver(); + ~MyObserver(); + + NS_DECL_ISUPPORTS + + virtual void Notify(nsIImageRequest *aImageRequest, + nsIImage *aImage, + nsImageNotification aNotificationType, + PRInt32 aParam1, PRInt32 aParam2, + void *aParam3); + + virtual void NotifyError(nsIImageRequest *aImageRequest, + nsImageError aErrorType); +}; + +MyObserver::MyObserver() +{ +} + +MyObserver::~MyObserver() +{ +} + +NS_IMPL_ISUPPORTS(MyObserver, kIImageObserverIID) + +void +MyObserver::Notify(nsIImageRequest *aImageRequest, + nsIImage *aImage, + nsImageNotification aNotificationType, + PRInt32 aParam1, PRInt32 aParam2, + void *aParam3) +{ + switch (aNotificationType) { + case nsImageNotification_kDimensions: + { + char buffer[40]; + sprintf(buffer, "Image:%d x %d", aParam1, aParam2); + ::SetWindowText(gHwnd, buffer); + } + break; + + case nsImageNotification_kPixmapUpdate: + case nsImageNotification_kImageComplete: + case nsImageNotification_kFrameComplete: + { + if (gImage == nsnull && aImage) { + gImage = aImage; + NS_ADDREF(aImage); + } + + if (!gInstalledColorMap && gImage) { + nsColorMap *cmap = gImage->GetColorMap(); + + if (cmap != nsnull && cmap->NumColors > 0) { + gWindow->SetColorMap(cmap); + } + gInstalledColorMap = PR_TRUE; + } + nsRect *rect = (nsRect *)aParam3; + nsIRenderingContext *drawCtx = gWindow->GetRenderingContext(); + + if (gImage) { + drawCtx->DrawImage(gImage, 0, 0, + gImage->GetWidth(), gImage->GetHeight()); + } + } + break; + } +} + +void +MyObserver::NotifyError(nsIImageRequest *aImageRequest, + nsImageError aErrorType) +{ + ::MessageBox(NULL, "Image loading error!", + class1Name, MB_OK); +} + +nsEventStatus PR_CALLBACK +MyHandleEvent(nsGUIEvent *aEvent) +{ + nsEventStatus result = nsEventStatus_eConsumeNoDefault; + switch(aEvent->message) { + case NS_PAINT: + { + // paint the background + nsIRenderingContext *drawCtx = ((nsPaintEvent*)aEvent)->renderingContext; + drawCtx->SetColor(aEvent->widget->GetBackgroundColor()); + drawCtx->FillRect(*(((nsPaintEvent*)aEvent)->rect)); + + if (gImage) { + drawCtx->DrawImage(gImage, 0, 0, + gImage->GetWidth(), gImage->GetHeight()); + } + + return nsEventStatus_eConsumeNoDefault; + } + break; + } + + return nsEventStatus_eIgnore; +} + +void +MyReleaseImages() +{ + if (gImageReq) { + NS_RELEASE(gImageReq); + gImageReq = NULL; + } + if (gImage) { + NS_RELEASE(gImage); + gImage = NULL; + } + + gInstalledColorMap = PR_FALSE; +} + +void +MyInterrupt() +{ + if (gImageGroup) { + gImageGroup->Interrupt(); + } +} + +#define FILE_URL_PREFIX "file://" + + +void +MyLoadImage(char *aFileName) +{ + char fileURL[256]; + char *str; + + MyInterrupt(); + MyReleaseImages(); + + if (gImageGroup == NULL) { + nsIRenderingContext *drawCtx = gWindow->GetRenderingContext(); + if (NS_NewImageGroup(&gImageGroup) != NS_OK || + gImageGroup->Init(drawCtx) != NS_OK) { + ::MessageBox(NULL, "Couldn't create image group", + class1Name, MB_OK); + NS_RELEASE(drawCtx); + return; + } + NS_RELEASE(drawCtx); + } + + strcpy(fileURL, FILE_URL_PREFIX); + strcpy(fileURL + strlen(FILE_URL_PREFIX), aFileName); + + str = fileURL; + while ((str = strchr(str, '\\')) != NULL) + *str = '/'; + + nscolor white; + MyObserver *observer = new MyObserver(); + + NS_ColorNameToRGB("white", &white); + gImageReq = gImageGroup->GetImage(fileURL, + observer, + white, 0, 0, 0); + if (gImageReq == NULL) { + ::MessageBox(NULL, "Couldn't create image request", + class1Name, MB_OK); + } +} + +PRBool +OpenFileDialog(char *aBuffer, int32 aBufLen) +{ + BOOL result = FALSE; + OPENFILENAME ofn; + + // *.js is the standard File Name on the Save/Open Dialog + ::strcpy(aBuffer, "*.gif;*.png;*.jpg;*.jpeg"); + + // fill the OPENFILENAME sruct + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = gHwnd; + ofn.hInstance = gInstance; + ofn.lpstrFilter = "All Images (*.gif,*.png,*.jpg,*.jpeg)\0*.gif;*png;*.jpg;*.jpeg\0GIF Files (*.gif)\0*.gif\0PNG Files (*.png)\0*.png\0JPEG Files (*.jpg,*.jpeg)\0*.jpg;*.jpeg\0All Files\0*.*\0\0"; + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 1; // the first one in lpstrFilter + ofn.lpstrFile = aBuffer; // contains the file path name on return + ofn.nMaxFile = aBufLen; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; // use default + ofn.lpstrTitle = NULL; // use default + ofn.Flags = OFN_CREATEPROMPT | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST; + ofn.nFileOffset = 0; + ofn.nFileExtension = 0; + ofn.lpstrDefExt = "gif"; // default extension is .js + ofn.lCustData = NULL; + ofn.lpfnHook = NULL; + ofn.lpTemplateName = NULL; + + // call the open file dialog or the save file dialog according to aIsOpenDialog + result = ::GetOpenFileName(&ofn); + + return (PRBool)result; +} + +long PASCAL +WndProc(HWND hWnd, UINT msg, WPARAM param, LPARAM lparam) +{ + HMENU hMenu; + + switch (msg) { + case WM_COMMAND: + hMenu = GetMenu(hWnd); + + switch (LOWORD(param)) { + case TIMER_OPEN: + { + char szFile[256]; + + if (!OpenFileDialog(szFile, 256)) + return 0L; + + MyLoadImage(szFile); + break; + } + case TIMER_EXIT: + ::DestroyWindow(hWnd); + exit(0); + default: + break; + } + break; + + case WM_CREATE: + // Initialize image library + if (NS_NewImageManager(&gImageManager) != NS_OK || + gImageManager->Init() != NS_OK) { + ::MessageBox(NULL, "Can't initialize the image library", + class1Name, MB_OK); + } + gImageManager->SetCacheSize(1024*1024); + break; + + case WM_DESTROY: + MyInterrupt(); + MyReleaseImages(); + if (gImageGroup != nsnull) { + NS_RELEASE(gImageGroup); + } + if (gImageManager != nsnull) { + NS_RELEASE(gImageManager); + } + PostQuitMessage(0); + break; + + default: + break; + } + + return DefWindowProc(hWnd, msg, param, lparam); +} + +static HWND CreateTopLevel(const char* clazz, const char* title, + int aWidth, int aHeight) +{ + // Create a simple top level window + HWND window = ::CreateWindowEx(WS_EX_CLIENTEDGE, + clazz, title, + WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN, + CW_USEDEFAULT, CW_USEDEFAULT, + aWidth, aHeight, + HWND_DESKTOP, + NULL, + gInstance, + NULL); + + nsRect rect(0, 0, aWidth, aHeight); + + nsresult rv = NSRepository::CreateInstance(kCChildWindowIID, NULL, kIWidgetIID, (void**)&gWindow); + + if (NS_OK == rv) { + gWindow->Create((nsNativeWindow)window, rect, MyHandleEvent, NULL); + } + + ::ShowWindow(window, SW_SHOW); + ::UpdateWindow(window); + return window; +} + +#define WIDGET_DLL "raptorwidget.dll" +#define GFXWIN_DLL "raptorgfxwin.dll" + +int PASCAL +WinMain(HANDLE instance, HANDLE prevInstance, LPSTR cmdParam, int nCmdShow) +{ + gInstance = instance; + + NSRepository::RegisterFactory(kCWindowIID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCChildWindowIID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCScrollbarIID, WIDGET_DLL, PR_FALSE, PR_FALSE); + + static NS_DEFINE_IID(kCRenderingContextIID, NS_RENDERING_CONTEXT_CID); + static NS_DEFINE_IID(kCDeviceContextIID, NS_DEVICE_CONTEXT_CID); + static NS_DEFINE_IID(kCFontMetricsIID, NS_FONT_METRICS_CID); + static NS_DEFINE_IID(kCImageIID, NS_IMAGE_CID); + + NSRepository::RegisterFactory(kCRenderingContextIID, GFXWIN_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCDeviceContextIID, GFXWIN_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCFontMetricsIID, GFXWIN_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCImageIID, GFXWIN_DLL, PR_FALSE, PR_FALSE); + + if (!prevInstance) { + WNDCLASS wndClass; + wndClass.style = 0; + wndClass.lpfnWndProc = WndProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = 0; + wndClass.hInstance = gInstance; + wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); + wndClass.hbrBackground = (HBRUSH) GetStockObject(LTGRAY_BRUSH); + wndClass.lpszMenuName = class1Name; + wndClass.lpszClassName = class1Name; + RegisterClass(&wndClass); + } + + // Create our first top level window + HWND gHwnd = CreateTopLevel(class1Name, "Raptor HTML Viewer", 620, 400); + + // Process messages + MSG msg; + while (GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return msg.wParam; +} + +void main(int argc, char **argv) +{ + WinMain(GetModuleHandle(NULL), NULL, 0, SW_SHOW); +} diff --git a/mozilla/webshell/tests/imgtest/image.rc b/mozilla/webshell/tests/imgtest/image.rc new file mode 100644 index 00000000000..0f8e12b7798 --- /dev/null +++ b/mozilla/webshell/tests/imgtest/image.rc @@ -0,0 +1,28 @@ +/* -*- Mode: C; tab-width: 4; 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 "resources.h" + +IMAGETEST MENU DISCARDABLE +{ + POPUP "File" + { + MENUITEM "Open...", TIMER_OPEN + MENUITEM "Exit", TIMER_EXIT + } +} diff --git a/mozilla/webshell/tests/imgtest/makefile.win b/mozilla/webshell/tests/imgtest/makefile.win new file mode 100644 index 00000000000..dec404db4ed --- /dev/null +++ b/mozilla/webshell/tests/imgtest/makefile.win @@ -0,0 +1,61 @@ +# +# 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. + +DEPTH=..\..\.. + +MAKE_OBJ_TYPE = EXE +PROG0 = .\$(OBJDIR)\ImageTest.exe +RESFILE = image.res +PROGRAMS = $(PROG0) + +LINCS=-I$(XPDIST)\public\raptor -I$(XPDIST)\public\xpcom -I..\src + +LLIBS= \ + $(DIST)\lib\raptorbase.lib \ + $(DIST)\lib\raptorgfx.lib \ + $(DIST)\lib\xpcom32.lib \ + $(LIBNSPR) \ + $(DIST)\lib\libplc21.lib \ + $(DIST)\lib\img3240.lib \ + $(DIST)\lib\util.lib \ + comdlg32.lib \ + $(RESFILE) + +include <$(DEPTH)\config\rules.mak> + +install:: $(PROGRAMS) + $(MAKE_INSTALL) $(PROG0) $(DIST)\bin + +clobber:: + rm -f $(DIST)\bin\ImageTest.exe + +# Move this into config/obj.inc when it's allowed +.cpp{.\$(OBJDIR)\}.exe: + $(CC) @<<$(CFGFILE) + $(CFLAGS) + $(LCFLAGS) + $(LINCS) + $(LINCS_1) + $(INCS) + $(LLIBS) + $(OS_LIBS) + -Fd$(PBDFILE) + -Fe.\$(OBJDIR)\ + -Fo.\$(OBJDIR)\ + $(CURDIR)$(*B).cpp +<< + +$(PROG0): $(OBJDIR) ImageTest.cpp $(RESFILE) diff --git a/mozilla/webshell/tests/imgtest/resources.h b/mozilla/webshell/tests/imgtest/resources.h new file mode 100644 index 00000000000..3358b700284 --- /dev/null +++ b/mozilla/webshell/tests/imgtest/resources.h @@ -0,0 +1,25 @@ +/* -*- Mode: C; tab-width: 4; 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. + */ + +#ifndef resources_h___ +#define resources_h___ + +#define TIMER_OPEN 40010 +#define TIMER_EXIT 40011 + +#endif /* resources_h___ */ diff --git a/mozilla/webshell/tests/makefile.win b/mozilla/webshell/tests/makefile.win new file mode 100644 index 00000000000..4d659ba06a7 --- /dev/null +++ b/mozilla/webshell/tests/makefile.win @@ -0,0 +1,23 @@ +#!nmake +# +# 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. + +DEPTH=..\.. +IGNORE_MANIFEST=1 + +DIRS= viewer imgtest nettest + +include <$(DEPTH)\config\rules.mak> diff --git a/mozilla/webshell/tests/nettest/makefile.win b/mozilla/webshell/tests/nettest/makefile.win new file mode 100644 index 00000000000..524a204239e --- /dev/null +++ b/mozilla/webshell/tests/nettest/makefile.win @@ -0,0 +1,95 @@ +# 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. + +NODEPEND=1 +IGNORE_MANIFEST = 1 + +#//------------------------------------------------------------------------ +#// +# New build system where zip dll is build indepenant of java stubs. +#// +#//------------------------------------------------------------------------ +MODULE = nettest +EXPORTS = \ + $(NULL) + + +#//------------------------------------------------------------------------ +#// +#// Specify the depth of the current directory relative to the +#// root of NS +#// +#//------------------------------------------------------------------------ +DEPTH= ..\..\.. + +MAKE_OBJ_TYPE=EXE +#//------------------------------------------------------------------------ +#// +#// Define any Public Make Variables here: (ie. PDFFILE, MAPFILE, ...) +#// +#//------------------------------------------------------------------------ +EXENAME=nettest +PDBFILE=nettest.pdb +MAPFILE=nettest.map + +#//------------------------------------------------------------------------ +#// +#// Define the files necessary to build the target (ie. OBJS) +#// +#//------------------------------------------------------------------------ +OBJS= \ + .\$(OBJDIR)\test.obj \ + $(NULL) +#//------------------------------------------------------------------------ +#// +#// Define any Public Targets here (ie. PROGRAM, LIBRARY, DLL, ...) +#// (these must be defined before the common makefiles are included) +#// +#//------------------------------------------------------------------------ + +PROGRAM=.\$(OBJDIR)\$(EXENAME).EXE + + +#//------------------------------------------------------------------------ +#// +#// Define any local options for the make tools +#// (ie. LCFLAGS, LLFLAGS, LLIBS, LINCS) +#// +#//------------------------------------------------------------------------ +LCFLAGS=-DNETSCAPE +LLIBS=$(LLIBS) \ + $(DIST)\lib\xpcom32.lib \ + $(DIST)\lib\netlib.lib + +LINCS=$(LINCS) -I. \ + -I$(PUBLIC)\raptor \ + -I$(PUBLIC)\netlib \ + -I$(PUBLIC)\xpcom + +# clobber and clobber_all will remove the following garbage: +GARBAGE = $(GARBAGE) _gen + +#//------------------------------------------------------------------------ +#// +#// Include the common makefile rules +#// +#//------------------------------------------------------------------------ +include <$(DEPTH)/config/rules.mak> + +export:: $(PROGRAM) + $(MAKE_INSTALL) $(PROGRAM) $(DIST)\bin + +clobber:: + rm -f $(DIST)\bin\$(EXENAME).exe diff --git a/mozilla/webshell/tests/nettest/test.cpp b/mozilla/webshell/tests/nettest/test.cpp new file mode 100644 index 00000000000..4ee50e7da37 --- /dev/null +++ b/mozilla/webshell/tests/nettest/test.cpp @@ -0,0 +1,194 @@ +/* -*- Mode: C++; tab-width: 4; 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 +#include + +#include "nsIStreamNotification.h" +#include "nsIInputStream.h" +#include "nsINetService.h" + +int urlLoaded; +PRBool bTraceEnabled; + + +/* XXX: Don't include net.h... */ +extern "C" { +extern int NET_PollSockets(); +extern void NET_ToggleTrace(); +}; + +class TestConsumer : public nsIStreamNotification +{ + +public: + NS_DECL_ISUPPORTS + + TestConsumer(); + + NS_IMETHOD GetBindInfo(void); + NS_IMETHOD OnProgress(void); + NS_IMETHOD OnStartBinding(void); + NS_IMETHOD OnDataAvailable(nsIInputStream *pIStream); + NS_IMETHOD OnStopBinding(void); + +protected: + ~TestConsumer(); +}; + + +TestConsumer::TestConsumer() +{ + NS_INIT_REFCNT(); +} + + +NS_DEFINE_IID(kIStreamNotificationIID, NS_ISTREAMNOTIFICATION_IID); +NS_IMPL_ISUPPORTS(TestConsumer,kIStreamNotificationIID); + + +TestConsumer::~TestConsumer() +{ + if (bTraceEnabled) { + printf("TestConsumer is being deleted...\n"); + } +} + + +NS_IMETHODIMP TestConsumer::GetBindInfo(void) +{ + if (bTraceEnabled) { + printf("+++ TestConsumer::GetBindInfo\n"); + } + + return 0; +} + +NS_IMETHODIMP TestConsumer::OnProgress(void) +{ + printf("+++ TestConsumer::OnProgress\n"); + + return 0; +} + +NS_IMETHODIMP TestConsumer::OnStartBinding(void) +{ + if (bTraceEnabled) { + printf("+++ TestConsumer::OnStartBinding\n"); + } + + return 0; +} + + +NS_IMETHODIMP TestConsumer::OnDataAvailable(nsIInputStream *pIStream) +{ + PRInt32 len; + + if (bTraceEnabled) { + printf("+++ TestConsumer::OnDataAvailable\n"); + } + + do { + PRInt32 err; + char buffer[80]; + int i; + + len = pIStream->Read(&err, buffer, 0, 80); + for (i=0; i 0); + + return 0; +} + + +NS_IMETHODIMP TestConsumer::OnStopBinding(void) +{ + if (bTraceEnabled) { + printf("+++ TestConsumer::OnStopBinding\n"); + } + + /* The document has been loaded, so drop out of the message pump... */ + urlLoaded = 1; + return 0; +} + + + +int main(int argc, char **argv) +{ + MSG msg; + char *url_address; + nsIStreamNotification *pConsumer; + nsINetService *pNetlib; + nsresult result; + + if (argc < 2) { + printf("test: -trace \n"); + return 0; + } + + urlLoaded = 0; + + /* Create an instance of the INetService... (aka Netlib) */ + if (NS_OK != NS_NewINetService(&pNetlib, NULL)) { + return 1; + } + + // Turn on netlib tracing... + if (stricmp(argv[1], "-trace") == 0) { + NET_ToggleTrace(); + url_address = argv[2]; + bTraceEnabled = PR_TRUE; + } else { + url_address = argv[1]; + bTraceEnabled = PR_FALSE; + } + + if (bTraceEnabled) { + printf("loading URL: %s...\n", url_address); + } + + pConsumer = new TestConsumer; + pConsumer->AddRef(); + + // Start the URL load... + result = pNetlib->OpenStream(url_address, pConsumer); + + /* If the open failed, then do not drop into the message loop... */ + if (NS_OK != result) { + urlLoaded = 1; + } + + // Enter the message pump to allow the URL load to proceed. + while ( !urlLoaded ) { + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + if (NET_PollSockets() == FALSE) urlLoaded = 1; + } + + pNetlib->Release(); + + return 0; + +} diff --git a/mozilla/webshell/tests/viewer/JSConsole.cpp b/mozilla/webshell/tests/viewer/JSConsole.cpp new file mode 100644 index 00000000000..b8611ccf432 --- /dev/null +++ b/mozilla/webshell/tests/viewer/JSConsole.cpp @@ -0,0 +1,920 @@ +/* -*- Mode: C++; tab-width: 4; 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. + */ + +//is case this is defined from the outside... MMP +#ifdef WIN32_LEAN_AND_MEAN +#undef WIN32_LEAN_AND_MEAN +#endif + +#include "JSConsole.h" +#include "jsconsres.h" +#include "nsIScriptContext.h" +#include +#include "jsapi.h" + +HINSTANCE JSConsole::sAppInstance = 0; +HACCEL JSConsole::sAccelTable = 0; +CHAR JSConsole::sDefaultCaption[] = "JavaScript Console"; +BOOL JSConsole::mRegistered = FALSE; + + +// display an error string along with the error returned from +// the GetLastError functions +#define MESSAGE_LENGTH 256 +void DisplayError(LPSTR lpMessage) +{ + CHAR lpMsgBuf[MESSAGE_LENGTH * 2]; + CHAR lpLastError[MESSAGE_LENGTH]; + + ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + GetLastError(), + 0, + (LPTSTR)&lpLastError, + MESSAGE_LENGTH, + NULL); + + strcpy(lpMsgBuf, lpMessage); + strcat(lpMsgBuf, "\nThe WWS (Worthless Windows System) reports:\n"); + strcat(lpMsgBuf, lpLastError); + + // Display the string. + ::MessageBox(NULL, lpMsgBuf, "JSConsole Error", MB_OK | MB_ICONSTOP); +} + +#if defined(_DEBUG) + #define VERIFY(value, errorCondition, message) \ + if((value) == (errorCondition)) DisplayError(message); +#else // !_DEBUG + #define VERIFY(value, errorCondition, message) (value) +#endif // _DEBUG + +// +// Register the window class +// +BOOL JSConsole::RegisterWidget() +{ + WNDCLASS wc; + + wc.style = 0; + wc.lpfnWndProc = JSConsole::WindowProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = JSConsole::sAppInstance; + wc.hIcon = NULL; + wc.hCursor = NULL; + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW); + wc.lpszMenuName = MAKEINTRESOURCE(JSCONSOLE_MENU); + wc.lpszClassName = "JavaScript Console"; + + return (BOOL)::RegisterClass(&wc); +} + +// +// Create the main application window +// +JSConsole* JSConsole::CreateConsole() +{ + if (!JSConsole::mRegistered){ + JSConsole::mRegistered = RegisterWidget(); + } + + HWND hWnd = ::CreateWindowEx(WS_EX_ACCEPTFILES | + WS_EX_CLIENTEDGE | + WS_EX_CONTROLPARENT, + "JavaScript Console", + JSConsole::sDefaultCaption, + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + NULL, + NULL, + JSConsole::sAppInstance, + NULL); + if (hWnd) { + ::ShowWindow(hWnd, SW_SHOW); + ::UpdateWindow(hWnd); + + JSConsole *console = (JSConsole*)::GetWindowLong(hWnd, GWL_USERDATA); + return console; + } + + return NULL; +} + +// +// Window Procedure +// +LRESULT CALLBACK JSConsole::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + JSConsole *console = (JSConsole*)::GetWindowLong(hWnd, GWL_USERDATA); + + // just ignore the message unless is WM_NCCREATE + if (!console) { + if (uMsg == WM_NCCREATE) { + HWND hWndEdit = ::CreateWindow("EDIT", + NULL, + WS_CHILDWINDOW | WS_VISIBLE | ES_MULTILINE | + ES_AUTOHSCROLL | ES_AUTOVSCROLL | + WS_HSCROLL | WS_VSCROLL, + 0, 0, 0, 0, + hWnd, + NULL, + JSConsole::sAppInstance, + NULL); + if (!hWndEdit) { + ::DisplayError("Cannot Create Edit Window"); + return FALSE; + } + ::SendMessage(hWndEdit, EM_SETLIMITTEXT, (WPARAM)0, (LPARAM)0); + + console = new JSConsole(hWnd, hWndEdit); + ::SetWindowLong(hWnd, GWL_USERDATA, (DWORD)console); + + ::SetFocus(hWndEdit); + } + + return ::CallWindowProc((FARPROC)::DefWindowProc, hWnd, uMsg, wParam, lParam); + } + + switch(uMsg) { + + // make sure the edit window covers the whole client area + case WM_SIZE: + return console->OnSize(wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); + + // exit the application + case WM_DESTROY: + console->OnDestroy(); + + return ::CallWindowProc((FARPROC)::DefWindowProc, hWnd, uMsg, wParam, lParam); + + // enable/disable menu items + case WM_INITMENUPOPUP: + return console->OnInitMenu((HMENU)wParam, (UINT)LOWORD(lParam), (BOOL)HIWORD(lParam)); + + case WM_COMMAND: + // menu or accelerator + if (HIWORD(wParam) == 0 || HIWORD(wParam) == 1) { + switch(LOWORD(wParam)) { + + case ID_FILENEW: + console->OnFileNew(); + break; + + case ID_FILEOPEN: + if (console->OpenFileDialog(OPEN_DIALOG)) { + console->LoadFile(); + } + + break; + + case ID_FILESAVE: + if (console->CanSave()) { + console->SaveFile(); + break; + } + // fall through so it can "Save As..." + + case ID_FILESAVEAS: + if (console->OpenFileDialog(SAVE_DIALOG)) { + console->SaveFile(); + } + break; + + case ID_FILEEXIT: + ::DestroyWindow(hWnd); + break; + + case ID_EDITUNDO: + console->OnEditUndo(); + break; + + case ID_EDITCUT: + console->OnEditCut(); + break; + + case ID_EDITCOPY: + console->OnEditCopy(); + break; + + case ID_EDITPASTE: + console->OnEditPaste(); + break; + + case ID_EDITDELETE: + console->OnEditDelete(); + break; + + case ID_EDITSELECTALL: + console->OnEditSelectAll(); + break; + + case ID_COMMANDSEVALALL: + console->OnCommandEvaluateAll(); + break; + + case ID_COMMANDSEVALSEL: + console->OnCommandEvaluateSelection(); + break; + + case ID_COMMANDSINSPECTOR: + console->OnCommandInspector(); + break; + + } + } + + break; + + case WM_DROPFILES: + { + HDROP hDropInfo = (HDROP)wParam; + if (::DragQueryFile(hDropInfo, (UINT)-1L, NULL, 0) != 1) { + ::MessageBox(hWnd, "Just One File Please...", "JSConsole Error", MB_OK | MB_ICONINFORMATION); + } + else { + CHAR fileName[MAX_PATH]; + ::DragQueryFile(hDropInfo, 0, fileName, MAX_PATH); + console->SetFileName(fileName); + console->LoadFile(); + } + break; + } + + case WM_SETFOCUS: + return console->OnSetFocus((HWND)wParam); + + default: + return ::CallWindowProc((FARPROC)::DefWindowProc, hWnd, uMsg, wParam, lParam); + } + + return 0; +} + +// +// Constructor +// The main window and the edit control must have been created already +// +JSConsole::JSConsole(HWND aMainWindow, HWND aEditControl) : + mMainWindow(aMainWindow), + mEditWindow(aEditControl), + mContext(NULL) +{ + mFileInfo.Init(); +} + +// +// Destructor +// +JSConsole::~JSConsole() +{ +} + +// +// Load a file into the edit field +// +BOOL JSConsole::LoadFile() +{ + BOOL result = FALSE; + + if (mMainWindow) { + // open the file + HANDLE file = ::CreateFile(mFileInfo.mCurrentFileName, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + if (file != INVALID_HANDLE_VALUE) { + // check the file size. Max is 64k + DWORD sizeHiWord; + DWORD sizeLoWord = ::GetFileSize(file, &sizeHiWord); + if (sizeLoWord < 0x10000 && sizeHiWord == 0) { + // alloc a buffer big enough to contain the file (account for '\0' + CHAR *buffer = new CHAR[sizeLoWord + 1]; + if (buffer) { + // read the file in memory + if (::ReadFile(file, + buffer, + sizeLoWord, + &sizeHiWord, + NULL)) { + NS_ASSERTION(sizeLoWord == sizeHiWord, "ReadFile inconsistency"); + buffer[sizeLoWord] = '\0'; // terminate the buffer + // write the file to the edit field + ::SendMessage(mEditWindow, WM_SETTEXT, (WPARAM)0, (LPARAM)buffer); + + // update the caption + CHAR caption[80]; + ::wsprintf(caption, + "%s - %s", + mFileInfo.mCurrentFileName + mFileInfo.mFileOffset, + sDefaultCaption); + ::SendMessage(mMainWindow, WM_SETTEXT, (WPARAM)0, (LPARAM)caption); + + result = TRUE; + } + else { + ::DisplayError("Error Reading the File"); + } + + // free the allocated buffer + delete[] buffer; + } + else { + ::MessageBox(mMainWindow, + "Cannot Allocate Enough Memory to Copy the File in Memory", + "JSConsole Error", + MB_OK | MB_ICONSTOP); + } + } + else { + ::MessageBox(mMainWindow, + "File too big. Max is 64k", + "JSConsole Error", + MB_OK | MB_ICONSTOP); + } + + // close the file handle + ::CloseHandle(file); + } +#ifdef _DEBUG + else { + CHAR message[MAX_PATH + 20]; + wsprintf(message, "Cannot Open File: %s", mFileInfo.mCurrentFileName); + ::DisplayError(message); + } +#endif + } + + return result; +} + +// +// Save the current text into a file +// +BOOL JSConsole::SaveFile() +{ + BOOL result = FALSE; + + if (mMainWindow && mFileInfo.mCurrentFileName[0] != '\0') { + // create the new file + HANDLE file = ::CreateFile(mFileInfo.mCurrentFileName, + GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + if (file != INVALID_HANDLE_VALUE) { + DWORD size; + // get the text size + size = ::SendMessage(mEditWindow, WM_GETTEXTLENGTH, (WPARAM)0, (LPARAM)0); + + // alloc a buffer big enough to contain the file + CHAR *buffer = new CHAR[++size]; + if (buffer) { + DWORD byteRead; + // read the text area content + ::SendMessage(mEditWindow, WM_GETTEXT, (WPARAM)size, (LPARAM)buffer); + + // write the buffer to disk + if (::WriteFile(file, + buffer, + size, + &byteRead, + NULL)) { + NS_ASSERTION(byteRead == size, "WriteFile inconsistency"); + // update the caption + CHAR caption[80]; + ::wsprintf(caption, + "%s - %s", + mFileInfo.mCurrentFileName + mFileInfo.mFileOffset, + sDefaultCaption); + ::SendMessage(mMainWindow, WM_SETTEXT, (WPARAM)0, (LPARAM)caption); + + result = TRUE; + } + else { + ::DisplayError("Error Writing the File"); + } + + // free the allocated buffer + delete[] buffer; + } + else { + ::MessageBox(mMainWindow, + "Cannot Allocate Enough Memory to Copy the Edit Text in Memory", + "JSConsole Error", + MB_OK | MB_ICONSTOP); + } + + // close the file handle + ::CloseHandle(file); + } +#ifdef _DEBUG + else { + CHAR message[MAX_PATH + 20]; + wsprintf(message, "Cannot Open File: %s", mFileInfo.mCurrentFileName); + ::DisplayError(message); + } +#endif + } + + return result; +} + +// +// Open a FileOpen or FileSave dialog +// +BOOL JSConsole::OpenFileDialog(UINT aWhichDialog) +{ + BOOL result = FALSE; + OPENFILENAME ofn; + + if (mMainWindow) { + + // *.js is the standard File Name on the Save/Open Dialog + if (mFileInfo.mCurrentFileName[0] == '\0') + ::strcpy(mFileInfo.mCurrentFileName, "*.js"); + + // fill the OPENFILENAME sruct + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = mMainWindow; + ofn.hInstance = JSConsole::sAppInstance; + ofn.lpstrFilter = "JavaScript Files (*.js)\0*.js\0Text Files (*.txt)\0*.txt\0All Files\0*.*\0\0"; + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 1; // the first one in lpstrFilter + ofn.lpstrFile = mFileInfo.mCurrentFileName; // contains the file path name on return + ofn.nMaxFile = sizeof(mFileInfo.mCurrentFileName); + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; // use default + ofn.lpstrTitle = NULL; // use default + ofn.Flags = OFN_CREATEPROMPT | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST; + ofn.nFileOffset = 0; + ofn.nFileExtension = 0; + ofn.lpstrDefExt = "js"; // default extension is .js + ofn.lCustData = NULL; + ofn.lpfnHook = NULL; + ofn.lpTemplateName = NULL; + + // call the open file dialog or the save file dialog according to aIsOpenDialog + if (aWhichDialog == OPEN_DIALOG) { + result = ::GetOpenFileName(&ofn); + } + else if (aWhichDialog == SAVE_DIALOG) { + result = ::GetSaveFileName(&ofn); + } + + if (!result) { + mFileInfo.mCurrentFileName[0] = '\0'; + ::CommDlgExtendedError(); + } + else { + mFileInfo.mFileOffset = ofn.nFileOffset; + mFileInfo.mFileExtension = ofn.nFileExtension; + } + } + + return result; +} + +// +// set the mFileInfo structure with the proper value given a generic path +// +void JSConsole::SetFileName(LPSTR aFileName) +{ + strcpy(mFileInfo.mCurrentFileName, aFileName); + for (int i = strlen(aFileName); i >= 0; i--) { + if (mFileInfo.mCurrentFileName[i] == '.') { + mFileInfo.mFileExtension = i; + } + + if (mFileInfo.mCurrentFileName[i] == '\\') { + mFileInfo.mFileOffset = i + 1; + break; + } + } +} + +// +// Move the edit window to cover the all client area +// +LRESULT JSConsole::OnSize(DWORD aResizeFlags, UINT aWidth, UINT aHeight) +{ + ::MoveWindow(mEditWindow, 0, 0, aWidth, aHeight, TRUE); + RECT textArea; + textArea.left = 3; + textArea.top = 1; + textArea.right = aWidth - 20; + textArea.bottom = aHeight - 17; + ::SendMessage(mEditWindow, EM_SETRECTNP, (WPARAM)0, (LPARAM)&textArea); + return 0L; +} + +// +// Initialize properly menu items +// +LRESULT JSConsole::OnInitMenu(HMENU aMenu, UINT aPos, BOOL aIsSystem) +{ + if (!aIsSystem) { + if (aPos == EDITMENUPOS) { + InitEditMenu(aMenu); + } + else if (aPos == COMMANDSMENUPOS) { + InitCommandMenu(aMenu); + } + } + + return 0L; +} + +// +// Pass the focus to the edit window +// +LRESULT JSConsole::OnSetFocus(HWND aWnd) +{ + ::SetFocus(mEditWindow); + return 0L; +} + +// +// Destroy message +// +void JSConsole::OnDestroy() +{ + if (mDestroyNotification) + (*mDestroyNotification)(); +} + +// +// File/New. Reset caption, text area and file info +// +void JSConsole::OnFileNew() +{ + SendMessage(mEditWindow, WM_SETTEXT, (WPARAM)0, (LPARAM)0); + SendMessage(mMainWindow, WM_SETTEXT, (WPARAM)0, (LPARAM)JSConsole::sDefaultCaption); + mFileInfo.Init(); +} + +// +// Edit/Undo. Undo the last operation on the edit field +// +void JSConsole::OnEditUndo() +{ + SendMessage(mEditWindow, WM_UNDO, (WPARAM)0, (LPARAM)0); +} + +// +// Edit/Cut. Cut the current selection +// +void JSConsole::OnEditCut() +{ + SendMessage(mEditWindow, WM_CUT, (WPARAM)0, (LPARAM)0); +} + +// +// Edit/Copy. Copy the current selection +// +void JSConsole::OnEditCopy() +{ + SendMessage(mEditWindow, WM_COPY, (WPARAM)0, (LPARAM)0); +} + +// +// Edit/Paste. Paste from the clipboard +// +void JSConsole::OnEditPaste() +{ + SendMessage(mEditWindow, WM_PASTE, (WPARAM)0, (LPARAM)0); +} + +// +// Edit/Delete. Delete the current selection +// +void JSConsole::OnEditDelete() +{ + SendMessage(mEditWindow, WM_CLEAR, (WPARAM)0, (LPARAM)0); +} + +// +// Edit/Select All. Select the whole text in the text area +// +void JSConsole::OnEditSelectAll() +{ + SendMessage(mEditWindow, EM_SETSEL, (WPARAM)0, (LPARAM)-1); +} + +// +// Command/Evaluate All. Take the text area content and evaluate in the js context +// +void JSConsole::OnCommandEvaluateAll() +{ + EvaluateText(0, (UINT)-1); +} + +// +// Command/Evaluate Selection. Take the current text area selection and evaluate in the js context +// +void JSConsole::OnCommandEvaluateSelection() +{ + // + // get the selection and evaluate it + // + DWORD startSel, endSel; + + // get selection range + ::SendMessage(mEditWindow, EM_GETSEL, (WPARAM)&startSel, (LPARAM)&endSel); + + EvaluateText(startSel, endSel); +} + +// +// Command/Inspector. Run the js inspector on the global object +// +void JSConsole::OnCommandInspector() +{ + ::MessageBox(mMainWindow, "Inspector not yet available", "JSConsole Error", MB_OK | MB_ICONINFORMATION); +} + +// +// Help +// +void JSConsole::OnHelp() +{ +} + +// +// private method. Deal with the "Edit" menu +// +void JSConsole::InitEditMenu(HMENU aMenu) +{ + CHAR someText[2] = {'\0', '\0'}; // some buffer + + // set flags to "disable" + UINT undoFlags = MF_BYPOSITION | MF_DISABLED | MF_GRAYED; + UINT cutFlags = MF_BYPOSITION | MF_DISABLED | MF_GRAYED; + UINT copyFlags = MF_BYPOSITION | MF_DISABLED | MF_GRAYED; + UINT pasteFlags = MF_BYPOSITION | MF_DISABLED | MF_GRAYED; + UINT deleteFlags = MF_BYPOSITION | MF_DISABLED | MF_GRAYED; + UINT selectAllFlags = MF_BYPOSITION | MF_DISABLED | MF_GRAYED; + + // check if the edit area has any text + SendMessage(mEditWindow, WM_GETTEXT, (WPARAM)2, (LPARAM)someText); + if (someText[0] != '\0') { + // enable the "Select All" + selectAllFlags = MF_BYPOSITION | MF_ENABLED; + + // enable "Copy/Cut/Paste" if there is any selection + UINT startPos, endPos; + SendMessage(mEditWindow, EM_GETSEL, (WPARAM)&startPos, (LPARAM)&endPos); + if (startPos != endPos) { + cutFlags = MF_BYPOSITION | MF_ENABLED; + copyFlags = MF_BYPOSITION | MF_ENABLED; + deleteFlags = MF_BYPOSITION | MF_ENABLED; + } + } + + // undo is available if the edit control says so + if (SendMessage(mEditWindow, EM_CANUNDO, (WPARAM)0, (LPARAM)0)) { + undoFlags = MF_BYPOSITION | MF_ENABLED; + } + + // check whether or not the clipboard contains text data + if (IsClipboardFormatAvailable(CF_TEXT)) { + pasteFlags = MF_BYPOSITION | MF_ENABLED; + } + + // do enable/disable + VERIFY(EnableMenuItem(aMenu, + ID_EDITUNDO - ID_EDITMENU - 1, + undoFlags), + -1L, + "Disable/Enable \"Undo\" Failed"); + VERIFY(EnableMenuItem(aMenu, + ID_EDITCUT - ID_EDITMENU - 1, + cutFlags), + -1L, + "Disable/Enable \"Cut\" Failed"); + VERIFY(EnableMenuItem(aMenu, + ID_EDITCOPY - ID_EDITMENU - 1, + copyFlags), + -1L, + "Disable/Enable \"Copy\" Failed"); + VERIFY(EnableMenuItem(aMenu, + ID_EDITPASTE - ID_EDITMENU - 1, + pasteFlags), + -1L, + "Disable/Enable \"Paste\" Failed"); + VERIFY(EnableMenuItem(aMenu, + ID_EDITDELETE - ID_EDITMENU - 1, + deleteFlags), + -1L, + "Disable/Enable \"Delete\" Failed"); + VERIFY(EnableMenuItem(aMenu, + ID_EDITSELECTALL - ID_EDITMENU - 1, + selectAllFlags), + -1L, + "Disable/Enable \"Select All\" Failed"); +} + +// +// private method. Deal with the "Command" menu +// +void JSConsole::InitCommandMenu(HMENU aMenu) +{ + CHAR someText[2] = {'\0', '\0'}; // some buffer + + // set flags to "disable" + UINT evaluateAllFlags = MF_BYPOSITION | MF_DISABLED | MF_GRAYED; + UINT evaluateSelectionFlags = MF_BYPOSITION | MF_DISABLED | MF_GRAYED; + + // check if the edit area has any text + SendMessage(mEditWindow, WM_GETTEXT, (WPARAM)2, (LPARAM)someText); + if (someText[0] != 0) { + // if there is some text enable "Evaluate All" + evaluateAllFlags = MF_BYPOSITION | MF_ENABLED; + + // enable "Evaluate Selection" if there is any selection + UINT startPos, endPos; + SendMessage(mEditWindow, EM_GETSEL, (WPARAM)&startPos, (LPARAM)&endPos); + if (startPos != endPos) { + evaluateSelectionFlags = MF_BYPOSITION | MF_ENABLED; + } + } + + // disable/enable commands + VERIFY(EnableMenuItem(aMenu, + ID_COMMANDSEVALALL - ID_COMMANDSMENU - 1, + evaluateAllFlags), + -1L, + "Disable/Enable \"Evaluate All\" Failed"); + VERIFY(EnableMenuItem(aMenu, + ID_COMMANDSEVALSEL - ID_COMMANDSMENU - 1, + evaluateSelectionFlags), + -1L, + "Disable/Enable \"Evaluate Selection\" Failed"); +} + +// +// normailize a buffer of char coming from a text area. +// Basically get rid of the 0x0D char +// +LPSTR NormalizeBuffer(LPSTR aBuffer) +{ + int offset = 0; + LPSTR walkingPointer = aBuffer; + + // trim all the 0x0D at the beginning (should be 1 at most, but hey...) + while (*walkingPointer++ == 0x0D) { + aBuffer++; + } + + do { + // compact the buffer if needed + *(walkingPointer - offset) = *walkingPointer; + + // skip the 0x0D + if (*walkingPointer == 0x0D) { + offset++; + } + + } while (*walkingPointer++ != '\0'); + + return aBuffer; +} + +// +// Evaluate the text enclosed between startSel and endSel +// +void JSConsole::EvaluateText(UINT aStartSel, UINT aEndSel) +{ + if (mContext) { + // get the text size + UINT size = ::SendMessage(mEditWindow, WM_GETTEXTLENGTH, (WPARAM)0, (LPARAM)0); + + // alloc a buffer big enough to contain the file + CHAR *buffer = new CHAR[++size]; + if (buffer) { + + // get the whole text + ::SendMessage(mEditWindow, WM_GETTEXT, (WPARAM)size, (LPARAM)buffer); + + // get the portion of the text to be evaluated + if (aEndSel != (UINT)-1) { + size = aEndSel - aStartSel; + strncpy(buffer, buffer + aStartSel, size); + buffer[size] = '\0'; + } + else { + aEndSel = size; + } + + + // change the 0x0D0x0A couple in 0x0A ('\n') + // no new buffer allocation, the pointer may be in the middle + // of the old buffer though, so keep buffer to call delete + LPSTR cleanBuffer = ::NormalizeBuffer(buffer); + + // evaluate the string + jsval returnValue; + if (mContext->EvaluateString(cleanBuffer, + strlen(cleanBuffer), + &returnValue)) { + // output the result on the console and on the edit area + CHAR result[512]; + ::printf("The return value is "); + if (JSVAL_IS_OBJECT(returnValue)) { + ::printf("an object\n"); + ::sprintf(result, " anObject [0x%X] ", JSVAL_TO_OBJECT(returnValue)); + } + else if (JSVAL_IS_INT(returnValue)) { + ::printf("an int [%d]\n", JSVAL_TO_INT(returnValue)); + ::sprintf(result, " %d ", JSVAL_TO_INT(returnValue)); + } + else if (JSVAL_IS_DOUBLE(returnValue)) { + ::printf("a double [%f]\n", *JSVAL_TO_DOUBLE(returnValue)); + ::sprintf(result, " %f ", *JSVAL_TO_DOUBLE(returnValue)); + } + else if (JSVAL_IS_STRING(returnValue)) { + ::printf("a string [%s]\n", JS_GetStringBytes(JSVAL_TO_STRING(returnValue))); + if (JS_GetStringLength(JSVAL_TO_STRING(returnValue)) < 512) { + ::sprintf(result, " %s ", JS_GetStringBytes(JSVAL_TO_STRING(returnValue))); + } + } + else if (JSVAL_IS_BOOLEAN(returnValue)) { + ::printf("a boolean [%d]\n", JSVAL_TO_BOOLEAN(returnValue)); + if (JSVAL_TO_BOOLEAN(returnValue)) { + ::strcpy(result, " true "); + } + else { + ::strcpy(result, " false "); + } + } + else if (JSVAL_IS_NULL(returnValue)) { + printf("null\n"); + ::strcpy(result, " null "); + } + else if (JSVAL_IS_VOID(returnValue)) { + printf("void\n"); + ::strcpy(result, " void "); + } + else { + printf("error: unknow return type!\n"); + ::strcpy(result, " error: unknow return type! "); + } + + // set the position at the end of the selection + ::SendMessage(mEditWindow, EM_SETSEL, (WPARAM)aEndSel, (LPARAM)aEndSel); + // write the result + ::SendMessage(mEditWindow, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)result); + // highlight the result + ::SendMessage(mEditWindow, EM_SETSEL, (WPARAM)aEndSel, (LPARAM)(aEndSel + strlen(result))); + } + else { + ::MessageBox(mMainWindow, + "Error evaluating the Script", + "JSConsole Error", + MB_OK | MB_ICONERROR); + } + + delete[] buffer; + JS_GC(mContext->GetContext()); + } + else { + ::MessageBox(mMainWindow, + "Not Enough Memory to Allocate a Buffer to Evaluate the Script", + "JSConsole Error", + MB_OK | MB_ICONSTOP); + } + } + else { + ::MessageBox(mMainWindow, + "Java Script Context not initialized", + "JSConsole Error", + MB_OK | MB_ICONSTOP); + } +} + + diff --git a/mozilla/webshell/tests/viewer/JSConsole.h b/mozilla/webshell/tests/viewer/JSConsole.h new file mode 100644 index 00000000000..21e8d29a554 --- /dev/null +++ b/mozilla/webshell/tests/viewer/JSConsole.h @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 4; 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. + */ + +#ifndef jsconsole_h__ +#define jsconsole_h__ + +#include + +class nsIScriptContext; + +#define OPEN_DIALOG 0 +#define SAVE_DIALOG 1 + +typedef void (*DESTROY_NOTIFICATION) (); + +class JSConsole { + +private: + HWND mMainWindow; + HWND mEditWindow; + + DESTROY_NOTIFICATION mDestroyNotification; + + // keep info from the OPENFILENAME struct + struct FileInfo { + CHAR mCurrentFileName[MAX_PATH]; + WORD mFileOffset; + WORD mFileExtension; + + void Init() {mCurrentFileName[0] = '\0'; mFileOffset = 0; mFileExtension = 0;} + } mFileInfo; + + // one context per window + nsIScriptContext *mContext; + +public: + static HINSTANCE sAppInstance; + static HACCEL sAccelTable; + static CHAR sDefaultCaption[]; + + static BOOL RegisterWidget(); + static JSConsole* CreateConsole(); + static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +private: + static BOOL mRegistered; + +public: + JSConsole(HWND aMainWindow, HWND aEditControl); + ~JSConsole(); + + BOOL LoadFile(); + BOOL SaveFile(); + + BOOL OpenFileDialog(UINT aOpenOrSave); + inline BOOL CanSave() { return mFileInfo.mCurrentFileName[0] != '\0'; } + void SetFileName(LPSTR aFileName); + + HWND GetMainWindow() { return mMainWindow; } + void SetNotification(DESTROY_NOTIFICATION aNotification) { mDestroyNotification = aNotification; } + void SetContext(nsIScriptContext *aContext) { mContext = aContext; } + + void EvaluateText(UINT aStartSel, UINT aEndSel); + + // windows messages + LRESULT OnSize(DWORD aResizeFlags, UINT aWidth, UINT aHeight); + LRESULT OnInitMenu(HMENU aMenu, UINT aPos, BOOL aIsSystem); + LRESULT OnSetFocus(HWND aWnd); + + void OnDestroy(); + + // menu items + void OnFileNew(); + void OnEditUndo(); + void OnEditCut(); + void OnEditCopy(); + void OnEditPaste(); + void OnEditDelete(); + void OnEditSelectAll(); + void OnCommandEvaluateAll(); + void OnCommandEvaluateSelection(); + void OnCommandInspector(); + void OnHelp(); + +private: + void InitEditMenu(HMENU aMenu); + void InitCommandMenu(HMENU aMenu); +}; + +#endif // jsconsole_h__ + diff --git a/mozilla/webshell/tests/viewer/jsconsres.h b/mozilla/webshell/tests/viewer/jsconsres.h new file mode 100644 index 00000000000..ba69fac3538 --- /dev/null +++ b/mozilla/webshell/tests/viewer/jsconsres.h @@ -0,0 +1,67 @@ +/* -*- 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. + */ + +#ifndef jsconsres_h___ +#define jsconsres_h___ + + +// Main menu id +#define JSCONSOLE_MENU 20100 + +#define FILEMENUPOS 0 +#define ID_FILEMENU 20200 +// File menu items ids +#define ID_FILENEW 20201 +#define ID_FILEOPEN 20202 +#define ID_FILESAVE 20203 +#define ID_FILESAVEAS 20204 +// separator +#define ID_FILEEXIT 20206 + +#define EDITMENUPOS 1 +#define ID_EDITMENU 20300 +// Edit menu items ids +#define ID_EDITUNDO 20301 +// separator +#define ID_EDITCUT 20303 +#define ID_EDITCOPY 20304 +#define ID_EDITPASTE 20305 +#define ID_EDITDELETE 20306 +// separator +#define ID_EDITSELECTALL 20308 + +#define COMMANDSMENUPOS 2 +#define ID_COMMANDSMENU 20400 +// Commands menu items ids +#define ID_COMMANDSEVALALL 20401 +#define ID_COMMANDSEVALSEL 20402 +// separator +#define ID_COMMANDSINSPECTOR 20404 + +#define HELPMENUPOS 3 +#define ID_HELPMENU 20500 +// Help menu items +#define ID_NOHELP 20501 + +// +// Accelerators table ids +// +#define ACCELERATOR_TABLE 1000 + +#endif // jsconsres_h___ + diff --git a/mozilla/webshell/tests/viewer/makefile.win b/mozilla/webshell/tests/viewer/makefile.win new file mode 100644 index 00000000000..f52865fd748 --- /dev/null +++ b/mozilla/webshell/tests/viewer/makefile.win @@ -0,0 +1,91 @@ +#!nmake +# +# 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. + +DEPTH=..\..\.. +IGNORE_MANIFEST=1 + +MAKE_OBJ_TYPE = EXE +PROGRAM = .\$(OBJDIR)\viewer.exe +RESFILE = viewer.res + +MISCDEP= \ + $(DIST)\lib\raptorweb.lib \ + $(DIST)\lib\xpcom32.lib \ + $(LIBNSPR) \ + $(DIST)\lib\libplc21.lib + + +OBJS = \ + .\$(OBJDIR)\winmain.obj \ + .\$(OBJDIR)\JSConsole.obj \ + $(NULL) + +LINCS=-I$(PUBLIC)\raptor -I$(PUBLIC)\xpcom -I$(PUBLIC)\dom -I$(PUBLIC)\js +MYLIBS= \ + $(DIST)\lib\raptorbase.lib \ + $(DIST)\lib\raptorgfx.lib \ + $(DIST)\lib\raptorhtml.lib \ + $(DIST)\lib\raptorweb.lib \ + $(DIST)\lib\xpcom32.lib \ + $(DIST)\lib\js3240.lib \ + $(LIBNSPR) \ + $(DIST)\lib\libplc21.lib \ + $(DIST)\lib\netlib.lib \ + comdlg32.lib \ + $(NULL) + +LLIBS= $(MYLIBS) \ + shell32.lib \ + -SUBSYSTEM:CONSOLE + +include <$(DEPTH)\config\rules.mak> + +install:: $(PROGRAM) + $(MAKE_INSTALL) $(PROGRAM) $(DIST)\bin + $(MAKE_INSTALL) samples\test0.html $(DIST)\bin\res\samples + $(MAKE_INSTALL) samples\test1.html $(DIST)\bin\res\samples + $(MAKE_INSTALL) samples\test2.html $(DIST)\bin\res\samples + $(MAKE_INSTALL) samples\test3.html $(DIST)\bin\res\samples + $(MAKE_INSTALL) samples\test4.html $(DIST)\bin\res\samples + $(MAKE_INSTALL) samples\test5.html $(DIST)\bin\res\samples + $(MAKE_INSTALL) samples\test6.html $(DIST)\bin\res\samples + $(MAKE_INSTALL) samples\test7.html $(DIST)\bin\res\samples + $(MAKE_INSTALL) samples\test8.html $(DIST)\bin\res\samples + $(MAKE_INSTALL) samples\raptor.jpg $(DIST)\bin\res\samples + $(MAKE_INSTALL) samples\Anieyes.gif $(DIST)\bin\res\samples + $(MAKE_INSTALL) samples\gear1.gif $(DIST)\bin\res\samples + $(MAKE_INSTALL) samples\rock_gra.gif $(DIST)\bin\res\samples + $(MAKE_INSTALL) samples\woofer.gif $(DIST)\bin\res\samples + $(MAKE_INSTALL) samples\bg.jpg $(DIST)\bin\res\samples + +clobber:: + rm -f $(DIST)\bin\viewer.exe + rm -f $(DIST)\bin\res\samples\test0.html + rm -f $(DIST)\bin\res\samples\test1.html + rm -f $(DIST)\bin\res\samples\test2.html + rm -f $(DIST)\bin\res\samples\test3.html + rm -f $(DIST)\bin\res\samples\test4.html + rm -f $(DIST)\bin\res\samples\test5.html + rm -f $(DIST)\bin\res\samples\test6.html + rm -f $(DIST)\bin\res\samples\test7.html + rm -f $(DIST)\bin\res\samples\test8.html + rm -f $(DIST)\bin\res\samples\raptor.jpg + rm -f $(DIST)\bin\res\samples\Anieyes.gif + rm -f $(DIST)\bin\res\samples\gear1.gif + rm -f $(DIST)\bin\res\samples\rock_gra.gif + rm -f $(DIST)\bin\res\samples\woofer.gif + rm -f $(DIST)\bin\res\samples\bg.jpg diff --git a/mozilla/webshell/tests/viewer/resources.h b/mozilla/webshell/tests/viewer/resources.h new file mode 100644 index 00000000000..97c9b602565 --- /dev/null +++ b/mozilla/webshell/tests/viewer/resources.h @@ -0,0 +1,54 @@ +/* -*- 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. + */ + +#ifndef resources_h___ +#define resources_h___ + +#define VIEWER_OPEN 40000 +#define VIEWER_EXIT 40002 +#define PREVIEW_CLOSE 40003 + +#define VIEWER_FILE_OPEN 40010 + +// Note: must be in ascending sequential order +#define VIEWER_DEMO0 40011 +#define VIEWER_DEMO1 40012 +#define VIEWER_DEMO2 40013 +#define VIEWER_DEMO3 40014 +#define VIEWER_DEMO4 40015 +#define VIEWER_DEMO5 40016 +#define VIEWER_DEMO6 40017 +#define VIEWER_DEMO7 40018 +#define VIEWER_DEMO8 40019 + +#define VIEWER_VISUAL_DEBUGGING 40020 +#define VIEWER_REFLOW_TEST 40021 +#define VIEWER_DUMP_CONTENT 40022 +#define VIEWER_DUMP_FRAMES 40023 +#define VIEWER_DUMP_VIEWS 40024 +#define VIEWER_DUMP_STYLE 40025 +#define VIEWER_APPEND_CONTENT 40026 + +// Note: must be in ascending sequential order +#define VIEWER_ONE_COLUMN 40031 +#define VIEWER_TWO_COLUMN 40032 +#define VIEWER_THREE_COLUMN 40033 + +#define JS_CONSOLE 40100 + +#endif /* resources_h___ */ diff --git a/mozilla/webshell/tests/viewer/samples/Anieyes.gif b/mozilla/webshell/tests/viewer/samples/Anieyes.gif new file mode 100644 index 00000000000..de488ba16c8 Binary files /dev/null and b/mozilla/webshell/tests/viewer/samples/Anieyes.gif differ diff --git a/mozilla/webshell/tests/viewer/samples/bg.jpg b/mozilla/webshell/tests/viewer/samples/bg.jpg new file mode 100644 index 00000000000..116ffd60ac8 Binary files /dev/null and b/mozilla/webshell/tests/viewer/samples/bg.jpg differ diff --git a/mozilla/webshell/tests/viewer/samples/gear1.gif b/mozilla/webshell/tests/viewer/samples/gear1.gif new file mode 100644 index 00000000000..a694f2dfcdd Binary files /dev/null and b/mozilla/webshell/tests/viewer/samples/gear1.gif differ diff --git a/mozilla/webshell/tests/viewer/samples/raptor.jpg b/mozilla/webshell/tests/viewer/samples/raptor.jpg new file mode 100644 index 00000000000..243ba9e2d43 Binary files /dev/null and b/mozilla/webshell/tests/viewer/samples/raptor.jpg differ diff --git a/mozilla/webshell/tests/viewer/samples/rock_gra.gif b/mozilla/webshell/tests/viewer/samples/rock_gra.gif new file mode 100644 index 00000000000..dcf1a19b380 Binary files /dev/null and b/mozilla/webshell/tests/viewer/samples/rock_gra.gif differ diff --git a/mozilla/webshell/tests/viewer/samples/test0.html b/mozilla/webshell/tests/viewer/samples/test0.html new file mode 100644 index 00000000000..fdcfc36d800 --- /dev/null +++ b/mozilla/webshell/tests/viewer/samples/test0.html @@ -0,0 +1,80 @@ + + + + + +This is some text which is long enough to word wrap. We +can use this text +to test out incremental reflow in addition to other basic layout +algorithms. Twas brillig and the slithey tobes doth mobe grath enable +which really confused me! + italics is here + +Now this text will someday be reallybold + But this text will not be bold +
    +

    Now this text will someday not be bold

    +

    Font size=7

    +

    Font size=6

    +

    Font size=5

    +

    Font size=4

    +

    Font size=3

    +

    Font size=2

    +

    Font size=1

    +

    Font point-size=24 font-weight=700

    +

    + Size four text size -2 green text more text + size five, courrier more text + blue +1 text + +

    +
      +
    • List Item 1
    • +
    • List Item 2
    • +
        +
      • List Item 2.1
      • +
      • List Item 2.2
      • +
      +
    +

    Headline 1

    +

    Headline 2

    +

    Headline 3

    +

    Headline 4

    +
    Headline 5
    +
    Headline 6
    +
    +One	Two	Three   Four
    +---	---	-----   ----
    +a	b	c       d
    +a	b	c       d
    +oink	two	three	four
    +
    + + + diff --git a/mozilla/webshell/tests/viewer/samples/test1.html b/mozilla/webshell/tests/viewer/samples/test1.html new file mode 100644 index 00000000000..03094eb9298 --- /dev/null +++ b/mozilla/webshell/tests/viewer/samples/test1.html @@ -0,0 +1,139 @@ + + +This is some text which is long enough to word wrap. We +can use this text +to test out incremental reflow in addition to other basic layout +algorithms. Twas brillig and the slithey tobes doth mobe grath enable +which really confused me! + +Now this text will someday be bold + But this text will not be bold +
    + + +
    CellStuff to test out table cell layout. This should be long enough.
    +

    +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +This is some text. It will be word wrapped because our container will word wrap us. It will also be baseline aligned because our container will do that too. +

    +
    +One	Two	Three   Four
    +---	---	-----   ----
    +a	b	c       d
    +a	b	c       d
    +
    + + + diff --git a/mozilla/webshell/tests/viewer/samples/test2.html b/mozilla/webshell/tests/viewer/samples/test2.html new file mode 100644 index 00000000000..db88f267240 --- /dev/null +++ b/mozilla/webshell/tests/viewer/samples/test2.html @@ -0,0 +1,13 @@ + + +A text +Bold text +


    +Italic text +Fixed text +Strike text +Underline text +Look MA, It's Threed-D text 123 + + + diff --git a/mozilla/webshell/tests/viewer/samples/test3.html b/mozilla/webshell/tests/viewer/samples/test3.html new file mode 100644 index 00000000000..770bc75589a --- /dev/null +++ b/mozilla/webshell/tests/viewer/samples/test3.html @@ -0,0 +1,41 @@ + + + + + + +  +

    DON'T PAGINATE THIS VIEW YET!

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Caption that is a really long. Long enough perhaps to really +test captions that are wider than the table to which they are attached. +You should see this caption clipped to the width of the table. +
    CellStuff to test out table cell layout. This should be long enough to really push table cell text handling.Cell
    CellStuff to test out table cell layout. This should be long enough to really push table cell text handling.Cell
    CellStuff to test out table cell layout. This should be long enough to really push table cell text handling.Cell
    +  + + diff --git a/mozilla/webshell/tests/viewer/samples/test4.html b/mozilla/webshell/tests/viewer/samples/test4.html new file mode 100644 index 00000000000..cd2bdc4f290 --- /dev/null +++ b/mozilla/webshell/tests/viewer/samples/test4.html @@ -0,0 +1,41 @@ + + + + +Some simple tables. + + + + + + +
    ColorMeaning
    lightgreenLight green is used on cells that have a colspan
    khakiKhaki is used on cells that have a rowspan
    lightgreyLight grey is used on cells that have a rowspan and a colspan
    + +Column span table: + + + + + +
    top caption
    Cell Stuff to test out table cell layout. This should be long enough.
    Cell Stuff to test out table cell layout. This should be long enough.
    Cell Stuff to test out table cell layout. This should be long enough.Cell
    +
    +Row span table, no caption: + + + + + +
    bottom caption
    Cell Stuff to test out table cell layout. This should be long enough.Cell
    CellCell
    Cell Stuff to test out table cell layout. This should be long enough.Cell
    +
    +Row and col span table: + + + + + +

    Caption Text

    Cell Stuff to test out table cell layout. This should be long enough.
    Cell
    Cell Stuff to test out table cell layout. This should be long enough.Cell
    + + + diff --git a/mozilla/webshell/tests/viewer/samples/test5.html b/mozilla/webshell/tests/viewer/samples/test5.html new file mode 100644 index 00000000000..9cd00849e23 --- /dev/null +++ b/mozilla/webshell/tests/viewer/samples/test5.html @@ -0,0 +1,22 @@ + + + + + +

    This is a paragraph. We should be yellow because there is a style +rule indicating that all paragraphs have a background of yellow.

    +

    This is a paragraph. We should be black with yellow text +because there is a style rule indicating that this paragraph should have +a background of black with yellow text.

    + + + diff --git a/mozilla/webshell/tests/viewer/samples/test6.html b/mozilla/webshell/tests/viewer/samples/test6.html new file mode 100644 index 00000000000..59df4f90b82 --- /dev/null +++ b/mozilla/webshell/tests/viewer/samples/test6.html @@ -0,0 +1,60 @@ + + +Column span table: + + + + +
    Cell Cell, and stuff to test out table cell layout. This should be long enough for testing.
    Cell Cell, and stuff to test out table cell layout. This should be long enough for testing.
    Cell Cell, and stuff to test out table cell layout. This should be long enough for testing.Cell
    +
    +Row span table + + + + +
    Cell Cell, and stuff to test out table cell layout. This should be long enough for testing.Cell
    CellCell
    Cell Cell, and stuff to test out table cell layout. This should be long enough for testing.Cell
    +
    +Row and col span table: + + + + +
    Cell + + + +
    Cell + + + +
    Cell + + + +
    Cell + + + +
    Cell + + + +
    Cell + + + +
    Cell + + + +
    Cell Cell, and stuff to test out table cell layout. This should be long enough for testing.
    Cell
    Cell Cell, and stuff to test out table cell layout. This should be long enough for testing.Cell
    +
    Cell
    Cell Cell, and stuff to test out table cell layout. This should be long enough for testing.Cell
    +
    Cell
    Cell Cell, and stuff to test out table cell layout. This should be long enough for testing.Cell
    +
    Cell
    Cell Cell, and stuff to test out table cell layout. This should be long enough for testing.Cell
    +
    Cell
    Cell Cell, and stuff to test out table cell layout. This should be long enough for testing.Cell
    +
    Cell
    Cell Cell, and stuff to test out table cell layout. This should be long enough for testing.Cell
    +
    Cell
    Cell Cell, and stuff to test out table cell layout. This should be long enough for testing.Cell
    +
    Cell
    Cell Cell, and stuff to test out table cell layout. This should be long enough for testing.Cell
    + + + diff --git a/mozilla/webshell/tests/viewer/samples/test7.html b/mozilla/webshell/tests/viewer/samples/test7.html new file mode 100644 index 00000000000..8557097368a --- /dev/null +++ b/mozilla/webshell/tests/viewer/samples/test7.html @@ -0,0 +1,7 @@ + + +A scaled animated image
    + + + + diff --git a/mozilla/webshell/tests/viewer/samples/test8.html b/mozilla/webshell/tests/viewer/samples/test8.html new file mode 100644 index 00000000000..aa42c64240b --- /dev/null +++ b/mozilla/webshell/tests/viewer/samples/test8.html @@ -0,0 +1,34 @@ + + +
    + +A checkbox:
    + +Another checkbox:
    + +Yet another checkbox:
    + +One last checkbox:
    + +

    This is a simple form

    +

    This is a simple form

    +

    This is a simple form

    +

    This is a simple form

    +

    This is a simple form

    +

    +

    enter some text

    +

    +

    +

    +

    " " + +

    +

    This is a simple form

    +

    This is a simple form

    +

    This is a simple form

    +

    This is a simple form

    +

    This is a simple form

    +
    + + + diff --git a/mozilla/webshell/tests/viewer/samples/test_form.html b/mozilla/webshell/tests/viewer/samples/test_form.html new file mode 100644 index 00000000000..aa42c64240b --- /dev/null +++ b/mozilla/webshell/tests/viewer/samples/test_form.html @@ -0,0 +1,34 @@ + + +
    + +A checkbox:
    + +Another checkbox:
    + +Yet another checkbox:
    + +One last checkbox:
    + +

    This is a simple form

    +

    This is a simple form

    +

    This is a simple form

    +

    This is a simple form

    +

    This is a simple form

    +

    +

    enter some text

    +

    +

    +

    +

    " " + +

    +

    This is a simple form

    +

    This is a simple form

    +

    This is a simple form

    +

    This is a simple form

    +

    This is a simple form

    +
    + + + diff --git a/mozilla/webshell/tests/viewer/samples/woofer.gif b/mozilla/webshell/tests/viewer/samples/woofer.gif new file mode 100644 index 00000000000..28b91d26fec Binary files /dev/null and b/mozilla/webshell/tests/viewer/samples/woofer.gif differ diff --git a/mozilla/webshell/tests/viewer/viewer.rc b/mozilla/webshell/tests/viewer/viewer.rc new file mode 100644 index 00000000000..a6afa1926db --- /dev/null +++ b/mozilla/webshell/tests/viewer/viewer.rc @@ -0,0 +1,122 @@ +/* -*- 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 "resources.h" +#include "jsconsres.h" +#include + + +VIEWER MENU DISCARDABLE +{ + POPUP "&File" + { + MENUITEM "&Open...", VIEWER_FILE_OPEN + POPUP "&Samples" + { + MENUITEM "demo #0", VIEWER_DEMO0 + MENUITEM "demo #1", VIEWER_DEMO1 + MENUITEM "demo #2", VIEWER_DEMO2 + MENUITEM "demo #3", VIEWER_DEMO3 + MENUITEM "demo #4", VIEWER_DEMO4 + MENUITEM "demo #5", VIEWER_DEMO5 + MENUITEM "demo #6", VIEWER_DEMO6 + MENUITEM "demo #7", VIEWER_DEMO7 + MENUITEM "demo #8", VIEWER_DEMO8 + } + POPUP "Print &Preview" + { + MENUITEM "One Column", VIEWER_ONE_COLUMN + MENUITEM "Two Column", VIEWER_TWO_COLUMN + MENUITEM "Three Column", VIEWER_THREE_COLUMN + } + MENUITEM "&Exit", VIEWER_EXIT + } + POPUP "&Debug" + { + MENUITEM "&Visual Debugging", VIEWER_VISUAL_DEBUGGING + MENUITEM "&Reflow Test", VIEWER_REFLOW_TEST + MENUITEM SEPARATOR + MENUITEM "Dump &Content", VIEWER_DUMP_CONTENT + MENUITEM "Dump &Frames", VIEWER_DUMP_FRAMES + MENUITEM "Dump &Views", VIEWER_DUMP_VIEWS + MENUITEM "Dump &Style", VIEWER_DUMP_STYLE + MENUITEM SEPARATOR + MENUITEM "&Append Content", VIEWER_APPEND_CONTENT + } + POPUP "&Tools" + { + MENUITEM "&JavaScript Console", JS_CONSOLE + } +} + +PRINTPREVIEW MENU DISCARDABLE +{ + POPUP "&File" + { + MENUITEM "&Close", PREVIEW_CLOSE + } + POPUP "&Debug" + { + MENUITEM "&Visual Debugging", VIEWER_VISUAL_DEBUGGING + MENUITEM SEPARATOR + MENUITEM "Dump &Content", VIEWER_DUMP_CONTENT + MENUITEM "Dump &Frames", VIEWER_DUMP_FRAMES + MENUITEM "Dump &Views", VIEWER_DUMP_VIEWS + MENUITEM "Dump &Style", VIEWER_DUMP_STYLE + } +} + +JSCONSOLE_MENU MENU DISCARDABLE +BEGIN + POPUP "&File" + BEGIN + MENUITEM "&New", ID_FILENEW + MENUITEM "&Open...", ID_FILEOPEN + MENUITEM "&Save", ID_FILESAVE + MENUITEM "Save &As...", ID_FILESAVEAS + MENUITEM SEPARATOR + MENUITEM "E&xit", ID_FILEEXIT + END + POPUP "&Edit" + BEGIN + MENUITEM "&Undo", ID_EDITUNDO + MENUITEM SEPARATOR + MENUITEM "Cu&t", ID_EDITCUT + MENUITEM "&Copy", ID_EDITCOPY + MENUITEM "&Paste", ID_EDITPASTE + MENUITEM "De&lete", ID_EDITDELETE + MENUITEM SEPARATOR + MENUITEM "Select &All", ID_EDITSELECTALL + END + POPUP "&Commands" + BEGIN + MENUITEM "&Evaluate All\tF5", ID_COMMANDSEVALALL + MENUITEM "Evaluate &Selection\tF10", ID_COMMANDSEVALSEL + MENUITEM SEPARATOR + MENUITEM "&Inspector", ID_COMMANDSINSPECTOR + END + POPUP "&Help" + BEGIN + MENUITEM "Help &Yourself", ID_NOHELP + END +END + +ACCELERATOR_TABLE ACCELERATORS +BEGIN + VK_F5, ID_COMMANDSEVALALL, VIRTKEY + VK_F10, ID_COMMANDSEVALSEL, VIRTKEY +END diff --git a/mozilla/webshell/tests/viewer/winmain.cpp b/mozilla/webshell/tests/viewer/winmain.cpp new file mode 100644 index 00000000000..4003a9675ce --- /dev/null +++ b/mozilla/webshell/tests/viewer/winmain.cpp @@ -0,0 +1,566 @@ +/* -*- 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. + */ + + +//we need openfilename stuff... MMP +#ifdef WIN32_LEAN_AND_MEAN +#undef WIN32_LEAN_AND_MEAN +#endif + +#include +#include + +#include "resources.h" +#include "jsconsres.h" +#include "JSConsole.h" + +#include "nsGlobalVariables.h" +#include "nsIWebWidget.h" +#include "nsIPresContext.h" +#include "nsIDocument.h" +#include "nsIDocumentObserver.h" +#include "nsUnitConversion.h" +#include "nsVoidArray.h" +#include "nsCRT.h" +#include "prthread.h" +#include "prprf.h" +#include "nsRepository.h" +#include "nsWidgetsCID.h" +#include "nsGfxCIID.h" +#include "nsViewsCID.h" +#include "nsString.h" +#include "plevent.h" +#include +#include "nsIScriptContext.h" + +// JSConsole window +JSConsole *gConsole = NULL; + +#define SAMPLES_BASE_URL "resource:/res/samples" +#define START_URL SAMPLES_BASE_URL "/test0.html" + +static char* class1Name = "Viewer"; +static char* class2Name = "PrintPreview"; + +static HANDLE gInstance, gPrevInstance; +static char* startURL; +static nsVoidArray* gWindows; + +// Temporary Netlib stuff... +/* XXX: Don't include net.h... */ +extern "C" { +extern int NET_PollSockets(); +}; + +//---------------------------------------------------------------------- + +class DocObserver : public nsIDocumentObserver { +public: + DocObserver(nsIWebWidget* aWebWidget) { + NS_INIT_REFCNT(); + mWebWidget = aWebWidget; + NS_ADDREF(aWebWidget); + } + + NS_DECL_ISUPPORTS; + + NS_IMETHOD SetTitle(const nsString& aTitle); + + virtual void BeginUpdate() { } + virtual void EndUpdate() { } + virtual void ContentChanged(nsIContent* aContent, + nsISubContent* aSubContent, + PRInt32 aChangeType) { } + virtual void ContentAppended(nsIContent* aContainer) { } + virtual void ContentInserted(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) { } + virtual void ContentReplaced(nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer) { } + virtual void ContentWillBeRemoved(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) { } + virtual void ContentHasBeenRemoved(nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) { } + virtual void StyleSheetAdded(nsIStyleSheet* aStyleSheet) { } + + +protected: + ~DocObserver() { + NS_RELEASE(mWebWidget); + } + + nsIWebWidget* mWebWidget; +}; + +struct WindowData { + HWND window; + nsIWebWidget* ww; + DocObserver* observer; + + WindowData() { + window = nsnull; + ww = nsnull; + } +}; + +static NS_DEFINE_IID(kIDocumentObserverIID, NS_IDOCUMENTOBSERVER_IID); + +NS_IMPL_ISUPPORTS(DocObserver, kIDocumentObserverIID); + +// Pass title information through to all of the web widgets that +// belong to this document. +NS_IMETHODIMP DocObserver::SetTitle(const nsString& aTitle) +{ + PRInt32 i, n = gWindows->Count(); + for (i = 0; i < n; i++) { + WindowData* wd = (WindowData*) gWindows->ElementAt(i); + if (wd->ww == mWebWidget) { + char* cp = aTitle.ToNewCString(); + ::SetWindowText(wd->window, cp); + delete cp; + } + } + return NS_OK; +} + +static DocObserver* NewObserver(nsIWebWidget* ww) +{ + nsISupports* oldContainer; + nsresult rv = ww->GetContainer(&oldContainer); + if (NS_OK == rv) { + if (nsnull == oldContainer) { + DocObserver* it = new DocObserver(ww); + NS_ADDREF(it); + ww->SetContainer(it); + return it; + } + else { + NS_RELEASE(oldContainer); + } + } + return nsnull; +} + +//---------------------------------------------------------------------- + +static nsresult ShowPrintPreview(nsIWebWidget* ww, PRIntn aColumns); + +void DestroyConsole() +{ + if (gConsole) { + gConsole->SetNotification(NULL); + delete gConsole; + gConsole = NULL; + } +} + +static void Destroy(WindowData* wd) +{ + DestroyConsole(); + if (nsnull != wd) { + if (nsnull != wd->ww) { + NS_RELEASE(wd->ww); + } + if (nsnull != wd->observer) { + NS_RELEASE(wd->observer); + } + gWindows->RemoveElement(wd); + delete wd; + } +} + +static void DestroyAllWindows() +{ + if (nsnull != gWindows) { + PRInt32 n = gWindows->Count(); + for (PRInt32 i = 0; i < n; i++) { + WindowData* wd = (WindowData*) gWindows->ElementAt(i); + ::DestroyWindow(wd->window); + } + gWindows->Clear(); + } +} + +#define FILE_PROTOCOL "file://" + +// Displays the Open common dialog box and lets the user specify an HTML file +// to open. Then passes the filename along to the Web widget. +static void +OpenHTMLFile(WindowData* wd) +{ + char szFile[_MAX_PATH]; + OPENFILENAME ofn; + + // Prompt the user for a filename + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = wd->window; + ofn.hInstance = gInstance; + ofn.lpstrFilter = "HTML Files\0*.html;*.htm\0All Files\0*.*\0\0"; + ofn.lpstrCustomFilter = NULL; + ofn.nFilterIndex = 1; + szFile[0] = '\0'; + ofn.lpstrFile = szFile; + ofn.nMaxFile = sizeof(szFile); + ofn.lpstrFileTitle = NULL; + ofn.lpstrInitialDir = NULL; // use current directory as initial directory + ofn.lpstrTitle = NULL; + ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NONETWORKBUTTON; + ofn.lpstrDefExt = NULL; + ofn.lpTemplateName = NULL; + + if (GetOpenFileName(&ofn)) { + PRInt32 len = strlen(szFile); + char* lpszFileURL = (char*)malloc(len + sizeof(FILE_PROTOCOL)); + + // Translate '\' to '/' + for (PRInt32 i = 0; i < len; i++) { + if (szFile[i] == '\\') { + szFile[i] = '/'; + } + } + + // Build the file URL + wsprintf(lpszFileURL, "%s%s", FILE_PROTOCOL, szFile); + + // Ask the Web widget to load the file URL + wd->ww->LoadURL(lpszFileURL); + free(lpszFileURL); + } +} + +long PASCAL +WndProc(HWND hWnd, UINT msg, WPARAM param, LPARAM lparam) +{ + HMENU hMenu; + + if (msg == WM_CREATE) { + LPCREATESTRUCT lpcs = (LPCREATESTRUCT) lparam; + WindowData* w = (WindowData*) lpcs->lpCreateParams; + SetWindowLong(hWnd, GWL_USERDATA, (LONG) w); + } + + WindowData* wd = (WindowData*) GetWindowLong(hWnd, GWL_USERDATA); + switch (msg) { + case WM_COMMAND: + hMenu = GetMenu(hWnd); + switch (LOWORD(param)) { + case VIEWER_EXIT: + DestroyAllWindows(); + return 0; + case PREVIEW_CLOSE: + ::DestroyWindow(hWnd); + return 0; + + case VIEWER_FILE_OPEN: + OpenHTMLFile(wd); + break; + + case VIEWER_DEMO0: + case VIEWER_DEMO1: + case VIEWER_DEMO2: + case VIEWER_DEMO3: + case VIEWER_DEMO4: + case VIEWER_DEMO5: + case VIEWER_DEMO6: + case VIEWER_DEMO7: + case VIEWER_DEMO8: + if ((nsnull != wd) && (nsnull != wd->ww)) { + PRIntn ix = LOWORD(param) - VIEWER_DEMO0; + char* url = new char[500]; + PR_snprintf(url, 500, "%s/test%d.html", SAMPLES_BASE_URL, ix); + wd->ww->LoadURL(url); + delete url; + } + break; + + case VIEWER_VISUAL_DEBUGGING: + if ((nsnull != wd) && (nsnull != wd->ww)) { + wd->ww->ShowFrameBorders(PRBool(!wd->ww->GetShowFrameBorders())); + } + break; + case VIEWER_DUMP_CONTENT: + if ((nsnull != wd) && (nsnull != wd->ww)) { + wd->ww->DumpContent(); + } + break; + case VIEWER_DUMP_FRAMES: + if ((nsnull != wd) && (nsnull != wd->ww)) { + wd->ww->DumpFrames(); + } + break; + case VIEWER_DUMP_VIEWS: + if ((nsnull != wd) && (nsnull != wd->ww)) { + wd->ww->DumpViews(); + } + break; + case VIEWER_DUMP_STYLE: + if ((nsnull != wd) && (nsnull != wd->ww)) { + wd->ww->DumpStyle(); + } + break; + + case VIEWER_APPEND_CONTENT: + if ((nsnull != wd) && (nsnull != wd->ww)) { + wd->ww->HackAppendContent(); + } + break; + case VIEWER_ONE_COLUMN: + case VIEWER_TWO_COLUMN: + case VIEWER_THREE_COLUMN: + if ((nsnull != wd) && (nsnull != wd->ww)) { + ShowPrintPreview(wd->ww, LOWORD(param) - VIEWER_ONE_COLUMN + 1); + } + break; + case JS_CONSOLE: + if (!gConsole) { + + // load the accelerator table for the console + if (!JSConsole::sAccelTable) { + JSConsole::sAccelTable = LoadAccelerators(gInstance, + MAKEINTRESOURCE(ACCELERATOR_TABLE)); + } + + nsIScriptContext *context = nsnull; + if (NS_OK == wd->ww->GetScriptContext(&context)) { + // create the console + gConsole = JSConsole::CreateConsole(); + gConsole->SetContext(context); + // lifetime of the context is still unclear at this point. + // Anyway, as long as the web widget is alive the context is alive. + // Maybe the context shouldn't even be RefCounted + context->Release(); + gConsole->SetNotification(DestroyConsole); + } + else { + MessageBox(hWnd, "Unable to load JavaScript", "Viewer Error", MB_ICONSTOP); + } + } + break; + + default: + break; + } + break; + + case WM_SIZE: + if ((nsnull != wd) && (nsnull != wd->ww)) { + RECT r; + ::GetClientRect(hWnd, &r); + nsRect rr(0, 0, PRInt32(r.right - r.left), PRInt32(r.bottom - r.top)); + wd->ww->SetBounds(rr); + } + return 0; + + case WM_DESTROY: + Destroy(wd); + if (gWindows->Count() == 0) { + PostQuitMessage(0); + } + return 0; + + case WM_CLOSE: + // Let windows destroy the window + break; + + default: + break; + } + return DefWindowProc(hWnd, msg, param, lparam); +} + +static WindowData* CreateTopLevel(const char* clazz, const char* title, + int aWidth, int aHeight) +{ + // Create a simple top level window + WindowData* wd = new WindowData(); + HWND window = ::CreateWindowEx(WS_EX_CLIENTEDGE, + clazz, title, + WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN, + CW_USEDEFAULT, CW_USEDEFAULT, + aWidth, aHeight, + HWND_DESKTOP, + NULL, + gInstance, + wd); + wd->window = window; + gWindows->AppendElement(wd); + ::ShowWindow(window, SW_SHOW); + ::UpdateWindow(window); + return wd; +} + +static nsresult ShowPrintPreview(nsIWebWidget* web, PRIntn aColumns) +{ + if (nsnull != web) { + nsIDocument* doc = web->GetDocument(); + if (nsnull != doc) { + nsIPresContext* cx; + nsresult rv = NS_NewPrintPreviewContext(&cx); + if (NS_OK != rv) { + return rv; + } + + WindowData* wd = CreateTopLevel(class2Name, "Print Preview", 500, 300); + + RECT r; + ::GetClientRect(wd->window, &r); + nsRect rr(0, 0, PRInt32(r.right - r.left), PRInt32(r.bottom - r.top)); + rv = NS_NewWebWidget(&wd->ww); + rv = wd->ww->Init(wd->window, rr, doc, cx); + wd->ww->Show(); + wd->observer = NewObserver(wd->ww); + + NS_RELEASE(cx); + NS_RELEASE(doc); + } + } + return NS_OK; +} + +void ReleaseMemory() +{ + nsGlobalVariables::Release(); + delete gWindows; +} + +#define WIDGET_DLL "raptorwidget.dll" +#define GFXWIN_DLL "raptorgfxwin.dll" +#define VIEW_DLL "raptorview.dll" + +int PASCAL +WinMain(HANDLE instance, HANDLE prevInstance, LPSTR cmdParam, int nCmdShow) +{ + PL_InitializeEventsLib(""); + + gInstance = instance; + gPrevInstance = prevInstance; + gWindows = new nsVoidArray(); + + static NS_DEFINE_IID(kCWindowIID, NS_WINDOW_CID); + static NS_DEFINE_IID(kCScrollbarIID, NS_VERTSCROLLBAR_CID); + static NS_DEFINE_IID(kCButtonIID, NS_BUTTON_CID); + static NS_DEFINE_IID(kCComboBoxCID, NS_COMBOBOX_CID); + static NS_DEFINE_IID(kCFileWidgetCID, NS_FILEWIDGET_CID); + static NS_DEFINE_IID(kCListBoxCID, NS_LISTBOX_CID); + static NS_DEFINE_IID(kCRadioButtonCID, NS_RADIOBUTTON_CID); + static NS_DEFINE_IID(kCTextAreaCID, NS_TEXTAREA_CID); + static NS_DEFINE_IID(kCTextFieldCID, NS_TEXTFIELD_CID); + static NS_DEFINE_IID(kCCheckButtonIID, NS_CHECKBUTTON_CID); + static NS_DEFINE_IID(kCChildIID, NS_CHILD_CID); + + NSRepository::RegisterFactory(kCWindowIID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCScrollbarIID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCButtonIID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCComboBoxCID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCFileWidgetCID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCListBoxCID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCRadioButtonCID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCTextAreaCID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCTextFieldCID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCCheckButtonIID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCChildIID, WIDGET_DLL, PR_FALSE, PR_FALSE); + + static NS_DEFINE_IID(kCRenderingContextIID, NS_RENDERING_CONTEXT_CID); + static NS_DEFINE_IID(kCDeviceContextIID, NS_DEVICE_CONTEXT_CID); + static NS_DEFINE_IID(kCFontMetricsIID, NS_FONT_METRICS_CID); + static NS_DEFINE_IID(kCImageIID, NS_IMAGE_CID); + + NSRepository::RegisterFactory(kCRenderingContextIID, GFXWIN_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCDeviceContextIID, GFXWIN_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCFontMetricsIID, GFXWIN_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCImageIID, GFXWIN_DLL, PR_FALSE, PR_FALSE); + + static NS_DEFINE_IID(kCViewManagerCID, NS_VIEW_MANAGER_CID); + static NS_DEFINE_IID(kCViewCID, NS_VIEW_CID); + static NS_DEFINE_IID(kCScrollingViewCID, NS_SCROLLING_VIEW_CID); + + NSRepository::RegisterFactory(kCViewManagerCID, VIEW_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCViewCID, VIEW_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCScrollingViewCID, VIEW_DLL, PR_FALSE, PR_FALSE); + + // initialize the toolkit (widget library). + // This may look weak and in fact it is...but hey... + //XXX move it somewhere else please + //NS_InitToolkit(PR_GetCurrentThread()); + + if (!prevInstance) { + WNDCLASS wndClass; + wndClass.style = 0; + wndClass.lpfnWndProc = WndProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = 0; + wndClass.hInstance = gInstance; + wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); + wndClass.hbrBackground = (HBRUSH) GetStockObject(LTGRAY_BRUSH); + wndClass.lpszMenuName = class1Name; + wndClass.lpszClassName = class1Name; + RegisterClass(&wndClass); + + wndClass.lpszMenuName = class2Name; + wndClass.lpszClassName = class2Name; + RegisterClass(&wndClass); + } + + // Create our first top level window + WindowData* wd = CreateTopLevel(class1Name, "Raptor HTML Viewer", 620, 400); + + // Now embed the web widget in it + RECT r; + ::GetClientRect(wd->window, &r); + nsresult rv = NS_NewWebWidget(&wd->ww); + nsRect rr(0, 0, PRInt32(r.right - r.left), PRInt32(r.bottom - r.top)); + rv = wd->ww->Init(wd->window, rr); + wd->ww->Show(); + wd->observer = NewObserver(wd->ww); + + // Load the starting url if we have one + wd->ww->LoadURL(startURL ? startURL : START_URL); + + // Process messages + MSG msg; + while (GetMessage(&msg, NULL, 0, 0)) { + if (!JSConsole::sAccelTable || + !gConsole || + !gConsole->GetMainWindow() || + !TranslateAccelerator(gConsole->GetMainWindow(), JSConsole::sAccelTable, &msg)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + /* Pump Netlib... */ + NET_PollSockets(); + } + } + ReleaseMemory(); + if (!prevInstance) { + UnregisterClass(class1Name, gInstance); + UnregisterClass(class2Name, gInstance); + } + return msg.wParam; +} + +void main(int argc, char **argv) +{ + if (argc > 1) { + startURL = argv[1]; + } + WinMain(GetModuleHandle(NULL), NULL, 0, SW_SHOW); +} diff --git a/mozilla/widget/Makefile b/mozilla/widget/Makefile new file mode 100644 index 00000000000..646e5af8b7a --- /dev/null +++ b/mozilla/widget/Makefile @@ -0,0 +1,24 @@ +#!gmake +# +# 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. + +DEPTH = .. + +DIRS= public src tests + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/widget/build.bat b/mozilla/widget/build.bat new file mode 100755 index 00000000000..7dde3ca897a --- /dev/null +++ b/mozilla/widget/build.bat @@ -0,0 +1,21 @@ +rem -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- +rem +rem The contents of this file are subject to the Netscape Public License +rem Version 1.0 (the "NPL"); you may not use this file except in +rem compliance with the NPL. You may obtain a copy of the NPL at +rem http://www.mozilla.org/NPL/ +rem +rem Software distributed under the NPL is distributed on an "AS IS" basis, +rem WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL +rem for the specific language governing rights and limitations under the +rem NPL. +rem +rem The Initial Developer of this code under the NPL is Netscape +rem Communications Corporation. Portions created by Netscape are +rem Copyright (C) 1998 Netscape Communications Corporation. All Rights +rem Reserved. +rem + +del s:\ns\raptor\ui\src\windows\win32_d.obj\%1.obj +del s:\ns\raptor\ui\tests\windows\win32_d.obj\winmain.obj +nmake -f makefile.win diff --git a/mozilla/widget/makefile.win b/mozilla/widget/makefile.win new file mode 100644 index 00000000000..b7f84e8a5a2 --- /dev/null +++ b/mozilla/widget/makefile.win @@ -0,0 +1,23 @@ +#!nmake +# +# 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. + +DEPTH=.. +IGNORE_MANIFEST=1 + +DIRS=public src tests + +include <$(DEPTH)\config\rules.mak> diff --git a/mozilla/widget/public/Makefile b/mozilla/widget/public/Makefile new file mode 100644 index 00000000000..c9f4608a5ae --- /dev/null +++ b/mozilla/widget/public/Makefile @@ -0,0 +1,48 @@ +#!gmake +# +# 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. + +DEPTH=../.. + +DEFINES = -D_IMPL_NS_UI + +EXPORTS = \ + nsui.h \ + nsIWidget.h \ + nsIButton.h \ + nsICheckButton.h\ + nsIListWidget.h \ + nsIComboBox.h \ + nsITextWidget.h \ + nsITextAreaWidget.h \ + nsIComboBox.h \ + nsIListBox.h \ + nsIFileWidget.h \ + nsIScrollbar.h \ + nsGUIEvent.h \ + nsIRadioButton.h\ + nsIRadioGroup.h \ + nsIMouseListener.h \ + nsIEventListener.h \ + nsIToolkit.h \ + nsWidgetsCID.h \ + $(NULL) + +MODULE = raptor + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/widget/public/makefile.win b/mozilla/widget/public/makefile.win new file mode 100644 index 00000000000..f4fcb500ed6 --- /dev/null +++ b/mozilla/widget/public/makefile.win @@ -0,0 +1,31 @@ +#!nmake +# +# 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. + +DEPTH=..\.. +IGNORE_MANIFEST=1 + +DEFINES=-D_IMPL_NS_UI +MODULE=raptor + +EXPORTS=nsui.h nsIWidget.h nsIButton.h nsICheckButton.h nsIListWidget.h \ + nsIComboBox.h nsITextWidget.h nsITextAreaWidget.h nsIComboBox.h \ + nsIListBox.h nsIFileWidget.h nsIScrollbar.h nsGUIEvent.h \ + nsIRadioButton.h nsIRadioGroup.h nsIMouseListener.h \ + nsIEventListener.h nsIToolkit.h nsWidgetsCID.h + +include <$(DEPTH)\config\rules.mak> + diff --git a/mozilla/widget/public/nsGUIEvent.h b/mozilla/widget/public/nsGUIEvent.h new file mode 100644 index 00000000000..92736157c66 --- /dev/null +++ b/mozilla/widget/public/nsGUIEvent.h @@ -0,0 +1,232 @@ +/* -*- 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. + */ + +#ifndef nsGUIEvent_h__ +#define nsGUIEvent_h__ + +#include "nsPoint.h" +#include "nsRect.h" + +class nsIRenderingContext; +class nsIWidget; + + +/* + * Return status for event processors. + */ + +enum nsEventStatus { + nsEventStatus_eIgnore, // The event is ignored, do default processing + nsEventStatus_eConsumeNoDefault, // The event is consumed, don't do default processing + nsEventStatus_eConsumeDoDefault // The event is consumed, but do default processing +}; + +struct nsGUIEvent { + PRUint32 message; // see GUI MESSAGES + nsIWidget* widget; // Originator of the event + nsPoint point; // in widget relative coordinates + PRUint32 time; // elapsed time, in milliseconds, from the + // time the system was started to the time + // the message was created + void* nativeMsg; // Internal platform specific mesasge. +}; + +struct nsSizeEvent : public nsGUIEvent { + nsRect *windowSize; // x,y width, height in pixels +}; + +struct nsPaintEvent : public nsGUIEvent { + nsIRenderingContext *renderingContext; + nsRect *rect; // x,y, width, height in pixels of area to paint +}; + +struct nsScrollbarEvent : public nsGUIEvent { + PRUint32 position; // ranges between scrollbar 0 + // and (maxRange - thumbSize) + // see nsIScrollbar.h +}; + +struct nsKeyEvent : public nsGUIEvent { + PRUint32 keyCode; // @see NS_VK codes + PRBool isShift; // indicates whether the shift key in down + PRBool isControl; // indicates whether the control key in down + PRBool isAlt; // indicates whether the alt key in down +}; + + +/* + * GUI MESSAGES + */ + +#define NS_WINDOW_START 100 +#define NS_CREATE (NS_WINDOW_START) +#define NS_DESTROY (NS_WINDOW_START + 1) +#define NS_SIZE (NS_WINDOW_START + 2) +#define NS_GOTFOCUS (NS_WINDOW_START + 3) +#define NS_LOSTFOCUS (NS_WINDOW_START + 4) +#define NS_PAINT (NS_WINDOW_START + 30) + +#define NS_KEY_UP (NS_WINDOW_START + 32) +#define NS_KEY_DOWN (NS_WINDOW_START + 33) + +#define NS_MOUSE_MESSAGE_START 300 +#define NS_MOUSE_MOVE (NS_MOUSE_MESSAGE_START) +#define NS_MOUSE_LEFT_BUTTON_UP (NS_MOUSE_MESSAGE_START + 1) +#define NS_MOUSE_LEFT_BUTTON_DOWN (NS_MOUSE_MESSAGE_START + 2) +#define NS_MOUSE_MIDDLE_BUTTON_UP (NS_MOUSE_MESSAGE_START + 10) +#define NS_MOUSE_MIDDLE_BUTTON_DOWN (NS_MOUSE_MESSAGE_START + 11) +#define NS_MOUSE_RIGHT_BUTTON_UP (NS_MOUSE_MESSAGE_START + 20) +#define NS_MOUSE_RIGHT_BUTTON_DOWN (NS_MOUSE_MESSAGE_START + 21) +#define NS_MOUSE_ENTER (NS_MOUSE_MESSAGE_START + 22) +#define NS_MOUSE_EXIT (NS_MOUSE_MESSAGE_START + 23) + +#define NS_SCROLLBAR_MESSAGE_START 1000 +#define NS_SCROLLBAR_POS (NS_SCROLLBAR_MESSAGE_START) +#define NS_SCROLLBAR_PAGE_NEXT (NS_SCROLLBAR_MESSAGE_START + 1) +#define NS_SCROLLBAR_PAGE_PREV (NS_SCROLLBAR_MESSAGE_START + 2) +#define NS_SCROLLBAR_LINE_NEXT (NS_SCROLLBAR_MESSAGE_START + 3) +#define NS_SCROLLBAR_LINE_PREV (NS_SCROLLBAR_MESSAGE_START + 4) + + +/* + * Virtual key bindings for keyboard events + */ + +#define NS_VK_CANCEL 0x03 +#define NS_VK_BACK 0x08 +#define NS_VK_TAB 0x09 +#define NS_VK_CLEAR 0x0C +#define NS_VK_RETURN 0x0D +#define NS_VK_SHIFT 0x10 +#define NS_VK_CONTROL 0x11 +#define NS_VK_ALT 0x12 +#define NS_VK_PAUSE 0x13 +#define NS_VK_CAPS_LOCK 0x14 +#define NS_VK_ESCAPE 0x1B +#define NS_VK_SPACE 0x20 +#define NS_VK_PAGE_UP 0x21 +#define NS_VK_PAGE_DOWN 0x22 +#define NS_VK_END 0x23 +#define NS_VK_HOME 0x24 +#define NS_VK_LEFT 0x25 +#define NS_VK_UP 0x26 +#define NS_VK_RIGHT 0x27 +#define NS_VK_DOWN 0x28 +#define NS_VK_PRINTSCREEN 0x2C +#define NS_VK_INSERT 0x2D +#define NS_VK_DELETE 0x2E + +// NS_VK_0 - NS_VK_9 match their ascii values +#define NS_VK_0 0x30 +#define NS_VK_1 0x31 +#define NS_VK_2 0x32 +#define NS_VK_3 0x33 +#define NS_VK_4 0x34 +#define NS_VK_5 0x35 +#define NS_VK_6 0x36 +#define NS_VK_7 0x37 +#define NS_VK_8 0x38 +#define NS_VK_9 0x39 + +#define NS_VK_SEMICOLON 0x3B +#define NS_VK_EQUALS 0x3D + +// NS_VK_A - NS_VK_Z match their ascii values +#define NS_VK_A 0x41 +#define NS_VK_B 0x42 +#define NS_VK_C 0x43 +#define NS_VK_D 0x44 +#define NS_VK_E 0x45 +#define NS_VK_F 0x46 +#define NS_VK_G 0x47 +#define NS_VK_H 0x48 +#define NS_VK_I 0x49 +#define NS_VK_J 0x4A +#define NS_VK_K 0x4B +#define NS_VK_L 0x4C +#define NS_VK_M 0x4D +#define NS_VK_N 0x4E +#define NS_VK_O 0x4F +#define NS_VK_P 0x50 +#define NS_VK_Q 0x51 +#define NS_VK_R 0x52 +#define NS_VK_S 0x53 +#define NS_VK_T 0x54 +#define NS_VK_U 0x55 +#define NS_VK_V 0x56 +#define NS_VK_W 0x57 +#define NS_VK_X 0x58 +#define NS_VK_Y 0x59 +#define NS_VK_Z 0x5A + +#define NS_VK_NUMPAD0 0x60 +#define NS_VK_NUMPAD1 0x61 +#define NS_VK_NUMPAD2 0x62 +#define NS_VK_NUMPAD3 0x63 +#define NS_VK_NUMPAD4 0x64 +#define NS_VK_NUMPAD5 0x65 +#define NS_VK_NUMPAD6 0x66 +#define NS_VK_NUMPAD7 0x67 +#define NS_VK_NUMPAD8 0x68 +#define NS_VK_NUMPAD9 0x69 +#define NS_VK_MULTIPLY 0x6A +#define NS_VK_ADD 0x6B +#define NS_VK_SEPARATOR 0x6C +#define NS_VK_SUBTRACT 0x6D +#define NS_VK_DECIMAL 0x6E +#define NS_VK_DIVIDE 0x6F +#define NS_VK_F1 0x70 +#define NS_VK_F2 0x71 +#define NS_VK_F3 0x72 +#define NS_VK_F4 0x73 +#define NS_VK_F5 0x74 +#define NS_VK_F6 0x75 +#define NS_VK_F7 0x76 +#define NS_VK_F8 0x77 +#define NS_VK_F9 0x78 +#define NS_VK_F10 0x79 +#define NS_VK_F11 0x7A +#define NS_VK_F12 0x7B +#define NS_VK_F13 0x7C +#define NS_VK_F14 0x7D +#define NS_VK_F15 0x7E +#define NS_VK_F16 0x7F +#define NS_VK_F17 0x80 +#define NS_VK_F18 0x81 +#define NS_VK_F19 0x82 +#define NS_VK_F20 0x83 +#define NS_VK_F21 0x84 +#define NS_VK_F22 0x85 +#define NS_VK_F23 0x86 +#define NS_VK_F24 0x87 + +#define NS_VK_NUM_LOCK 0x90 +#define NS_VK_SCROLL_LOCK 0x91 + +#define NS_VK_COMMA 0xBC +#define NS_VK_PERIOD 0xBE +#define NS_VK_SLASH 0xBF +#define NS_VK_BACK_QUOTE 0xC0 +#define NS_VK_OPEN_BRACKET 0xDB +#define NS_VK_BACK_SLASH 0xDC +#define NS_VK_CLOSE_BRACKET 0xDD +#define NS_VK_QUOTE 0xDE + + +#endif // nsGUIEvent_h__ + diff --git a/mozilla/widget/public/nsIButton.h b/mozilla/widget/public/nsIButton.h new file mode 100644 index 00000000000..a3ee208a4eb --- /dev/null +++ b/mozilla/widget/public/nsIButton.h @@ -0,0 +1,52 @@ +/* -*- 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. + */ + +#ifndef nsIButton_h__ +#define nsIButton_h__ + +#include "nsIWidget.h" +#include "nsString.h" + +// {18032AD0-B265-11d1-AA2A-000000000000} +#define NS_IBUTTON_IID \ +{ 0x18032ad0, 0xb265, 0x11d1, \ + { 0xaa, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } } + +/* + * Push button widget. + * Automatically shows itself as depressed when clicked on. + */ + +class nsIButton : public nsIWidget { + +public: + /** + * Set the button label + * @param aText button label + **/ + virtual void SetLabel(const nsString &aText) = 0; + + /** + * Get the button label + * @param aBuffer buffer for button label + **/ + virtual void GetLabel(nsString &aBuffer) = 0; + +}; + +#endif diff --git a/mozilla/widget/public/nsICheckButton.h b/mozilla/widget/public/nsICheckButton.h new file mode 100644 index 00000000000..a7d1a3293be --- /dev/null +++ b/mozilla/widget/public/nsICheckButton.h @@ -0,0 +1,52 @@ +/* -*- 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. + */ + +#ifndef nsICheckButton_h__ +#define nsICheckButton_h__ + +#include "nsIButton.h" + +// {961085F5-BD28-11d1-97EF-00609703C14E} +#define NS_ICHECKBUTTON_IID \ +{ 0x961085f5, 0xbd28, 0x11d1, { 0x97, 0xef, 0x0, 0x60, 0x97, 0x3, 0xc1, 0x4e } }; + +/** + * Checkbox widget. + * Can show itself in a checked or unchecked state. + * The checkbox widget does not automatically show itself checked or unchecked when clicked on. + */ +class nsICheckButton : public nsIButton { + +public: + + /** + * Set the check state. + * @param aState PR_TRUE show as checked. PR_FALSE show unchecked. + **/ + virtual void SetState(PRBool aState) = 0; + + /** + * Get the check state. + * @returns PR_TRUE if checked. PR_FALSE if unchecked. + **/ + virtual PRBool GetState() = 0; + +}; + +#endif // nsICheckButton_h__ + diff --git a/mozilla/widget/public/nsIComboBox.h b/mozilla/widget/public/nsIComboBox.h new file mode 100644 index 00000000000..d51ad2c431f --- /dev/null +++ b/mozilla/widget/public/nsIComboBox.h @@ -0,0 +1,38 @@ +/* -*- 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. + */ + +#ifndef nsIComboBox_h__ +#define nsIComboBox_h__ + +#include "nsIListWidget.h" +#include "nsString.h" + +// {961085F6-BD28-11d1-97EF-00609703C14E} +#define NS_ICOMBOBOX_IID \ +{ 0x961085f6, 0xbd28, 0x11d1, { 0x97, 0xef, 0x0, 0x60, 0x97, 0x3, 0xc1, 0x4e } }; + +/** + * Single selection drop down list. @see nsIListWidget for capabilities + */ +class nsIComboBox : public nsIListWidget { +}; + +#endif // nsIComboBox_h__ + + + diff --git a/mozilla/widget/public/nsIEventListener.h b/mozilla/widget/public/nsIEventListener.h new file mode 100644 index 00000000000..1109ea7a897 --- /dev/null +++ b/mozilla/widget/public/nsIEventListener.h @@ -0,0 +1,43 @@ +/* -*- 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. + */ + +#ifndef nsIEventListener_h__ +#define nsIEventListener_h__ + +#include "nsGUIEvent.h" + +/* + * Event listener interface. + * Alternative to a callback for recieving events. + */ + +class nsIEventListener { + +public: + + /** + * Processes all events. + * If a mouse listener is registered this method will not process mouse events. + * @param anEvent the event to process. @see nsGUIEvent.h for event types. + */ + + virtual nsEventStatus ProcessEvent(const nsGUIEvent & anEvent) = 0; + +}; + +#endif // nsIEventListener_h__ diff --git a/mozilla/widget/public/nsIFileWidget.h b/mozilla/widget/public/nsIFileWidget.h new file mode 100644 index 00000000000..5bf49ad0988 --- /dev/null +++ b/mozilla/widget/public/nsIFileWidget.h @@ -0,0 +1,92 @@ +/* -*- 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. + */ + +#ifndef nsIFileWidget_h__ +#define nsIFileWidget_h__ + +#include "nsString.h" + +// {F8030015-C342-11d1-97F0-00609703C14E} +#define NS_IFILEWIDGET_IID \ +{ 0xf8030015, 0xc342, 0x11d1, { 0x97, 0xf0, 0x0, 0x60, 0x97, 0x3, 0xc1, 0x4e } }; + + +/* + * File selector mode { load | save } + */ + +enum nsMode { eMode_load, eMode_save }; + +/* + * File selector widget. + * Modally select files for loading or saving. + */ + +class nsIFileWidget : public nsISupports +{ + +public: + + /** + * Creates a file widget with the specified title and mode. + * @param aParent the owner of the widget + * @param aTitle the title of the widget + * @param aMode the mode of the widget + * @param aContext context for displaying widget + * @praam aToolkit toolkit associated with file widget + */ + + virtual void Create( nsIWidget *aParent, + nsString& aTitle, + nsMode aMode, + nsIDeviceContext *aContext = nsnull, + nsIToolkit *aToolkit = nsnull) = 0; + + /** + * Set the list of file filters + * + * @param aNumberOfFilter number of filters. + * @param aTitle array of filter titles + * @param aFilter array of filters to associate with titles + * @return void + * + */ + + virtual void SetFilterList(PRUint32 aNumberOfFilters,const nsString aTitles[],const nsString aFilters[]) = 0; + + /** + * Show File Dialog. The dialog is displayed modally. + * + * @returns true if user selects , false if is selected + * + */ + + virtual PRBool Show() = 0; + + /** + * Get the file or directory including the full path. + * + * @param aFile file or directory selected + */ + + virtual void GetFile(nsString& aFile) = 0; + +}; + +#endif // nsIFileWidget_h__ + diff --git a/mozilla/widget/public/nsIListBox.h b/mozilla/widget/public/nsIListBox.h new file mode 100644 index 00000000000..c2fea0e0f69 --- /dev/null +++ b/mozilla/widget/public/nsIListBox.h @@ -0,0 +1,69 @@ +/* -*- 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. + */ + +#ifndef nsIListBox_h__ +#define nsIListBox_h__ + +#include "nsIListWidget.h" +#include "nsString.h" + +// {F8030014-C342-11d1-97F0-00609703C14E} +#define NS_ILISTBOX_IID \ +{ 0xf8030014, 0xc342, 0x11d1, { 0x97, 0xf0, 0x0, 0x60, 0x97, 0x3, 0xc1, 0x4e } }; + +/* + * Single or multi selection list of items. + */ + +class nsIListBox : public nsIListWidget { + +public: + + /** + * Set the ListBox to be multi-select. + * @param aMultiple PR_TRUE can have multiple selections. PR_FALSE single + * selections only. + * @return void + * + */ + + virtual void SetMultipleSelection(PRBool aMultipleSelections) = 0; + + /** + * Return the number of selected items. For single selection list box this + * @returns the number of selected items + * can be 1 or 0. + * + */ + virtual PRInt32 GetSelectedCount() = 0; + + /** + * Retrieves the indices of the selected items. + * @param aIndices Array to hold the selected items. Use GetSelectedCount to + * determine how large the array needs to be. + * @param aSize Size of the aIndices array + * + */ + virtual void GetSelectedIndices(PRInt32 aIndices[], PRInt32 aSize) = 0; + +}; + +#endif // nsIListBox_h__ + + + diff --git a/mozilla/widget/public/nsIListWidget.h b/mozilla/widget/public/nsIListWidget.h new file mode 100644 index 00000000000..f09bdd52561 --- /dev/null +++ b/mozilla/widget/public/nsIListWidget.h @@ -0,0 +1,124 @@ +/* -*- 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. + */ + +#ifndef nsIListWidget_h__ +#define nsIListWidget_h__ + +#include "nsIWidget.h" +#include "nsString.h" + +// {F8030013-C342-11d1-97F0-00609703C14E} +#define NS_ILISTWIDGET_IID \ +{ 0xf8030013, 0xc342, 0x11d1, { 0x97, 0xf0, 0x0, 0x60, 0x97, 0x3, 0xc1, 0x4e } }; + +/* + * Base class for nsIListBox and nsIComboBox + * + */ + +class nsIListWidget : public nsIWidget { + +public: + + /** + * Set an item at the specific position + * + * @param aItem the item name. The item has to be null terminated + * @param aPosition the position the item should be inserted at + * 0 is at the top of the list + * -1 is at the end of the list + */ + virtual void AddItemAt(nsString &aItem, PRInt32 aPosition) = 0; + + /** + * Finds the first occurrence of the specified item + * + * @param aItem the string to be filled + * @param aStartPos the starting position (index) + * @return PR_TRUE if successful, PR_FALSE otherwise + * + */ + virtual PRInt32 FindItem(nsString &aItem, PRInt32 aStartPos) = 0; + + /** + * Returns the number of items in the list + * + * @return the number of items + * + */ + virtual PRInt32 GetItemCount() = 0; + + /** + * Remove the first occurrence of the specified item + * + * @param aPosition the item position + * 0 is at the top of the list + * -1 is at the end of the list + * + * @return PR_TRUE if successful, PR_FALSE otherwise + * + */ + virtual PRBool RemoveItemAt(PRInt32 aPosition) = 0; + + /** + * Gets an item at a specific location + * + * @param anItem on return contains the string of the item at that position + * @param aPosition the Position of the item + * + */ + virtual PRBool GetItemAt(nsString& anItem, PRInt32 aPosition) = 0; + + /** + * Gets the selected item for a single selection list + * + * @param aItem on return contains the string of the selected item + * + */ + virtual void GetSelectedItem(nsString &aItem) = 0; + + /** + * Returns with the index of the selected item + * + * @return PRInt32, index of selected item + * + */ + virtual PRInt32 GetSelectedIndex() = 0; + + /** + * Select the item at the specified position + * + * @param PRInt32, the item position + * 0 is at the top of the list + * -1 is at the end of the list + * + */ + virtual void SelectItem(PRInt32 aPosition) = 0; + + /** + * Deselects all the items in the list + * + */ + virtual void Deselect() = 0; + +}; + +#endif // nsIListWidget_h__ + + + diff --git a/mozilla/widget/public/nsIMouseListener.h b/mozilla/widget/public/nsIMouseListener.h new file mode 100644 index 00000000000..13044abfdd1 --- /dev/null +++ b/mozilla/widget/public/nsIMouseListener.h @@ -0,0 +1,65 @@ +/* -*- 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. + */ + + +#ifndef nsIMouseListener_h__ +#define nsIMouseListener_h__ + +#include "nsGUIEvent.h" + +/* + * Mouse up/down/move event listener + * + */ + +class nsIMouseListener { + +public: + + /** + * Processes a mouse pressed event + * @param aMouseEvent @see nsGUIEvent.h + * @returns whether the event was consumed or ignored. @see nsEventStatus + */ + virtual nsEventStatus MousePressed(const nsGUIEvent & aMouseEvent) = 0; + + /** + * Processes a mouse release event + * @param aMouseEvent @see nsGUIEvent.h + * @returns whether the event was consumed or ignored. @see nsEventStatus + */ + virtual nsEventStatus MouseReleased(const nsGUIEvent & aMouseEvent) = 0; + + /** + * Processes a mouse clicked event + * @param aMouseEvent @see nsGUIEvent.h + * @returns whether the event was consumed or ignored. @see nsEventStatus + * + */ + virtual nsEventStatus MouseClicked(const nsGUIEvent & aMouseEvent) = 0; + + /** + * Processes a mouse moved event + * @param aMouseEvent @see nsGUIEvent.h + * @returns whether the event was consumed or ignored. @see nsEventStatus + */ + virtual nsEventStatus MouseMoved(const nsGUIEvent & aMouseEvent) = 0; + +}; + +#endif // nsIMouseListener_h__ diff --git a/mozilla/widget/public/nsIRadioButton.h b/mozilla/widget/public/nsIRadioButton.h new file mode 100644 index 00000000000..6ed2a617dbd --- /dev/null +++ b/mozilla/widget/public/nsIRadioButton.h @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; 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. + */ + +#ifndef nsIRadioButton_h__ +#define nsIRadioButton_h__ + +#include "nsIButton.h" + +#define NS_IRADIOBUTTON_IID \ +{ 0x18032ad4, 0xb265, 0x11d2, \ +{ 0xaa, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } } + +class nsIRadioGroup; + +/** + * RadioButton widget. + * Can show itself in a checked or unchecked state. + * The RadioButton widget does automatically show itself checked or unchecked when clicked on. + */ +class nsIRadioButton : public nsIButton { + +public: + /** + * Set the radio state. + * @param PRBool PR_TRUE sets the RadioButton and unsets all siblings, PR_FALSE unsets it + * + */ + virtual void SetState(PRBool aState) = 0; + + /** + * Tells the RadioButton NOT to notify the RadioGroup that it value has been changed + * + * @param PRBool PR_TRUE sets the RadioButton and unsets all siblings, PR_FALSE unsets it + * + */ + virtual void SetStateNoNotify(PRBool aState) = 0; + + /** + * Gets the state the RadioButton + * + * @return BRBool PR_TRUE if set, PR_FALSE if unset + * + */ + virtual PRBool GetState() = 0; + + /** + * Gets the RadioGroup associated with this button + * + * @return nsIRadioGroup* its RadioGroup + * + */ + virtual nsIRadioGroup* GetRadioGroup() = 0; + + /** + * Sets the RadioGroup associated with this button + * + * @param nsIRadioGroup* the new RadioGroup + * + */ + virtual void SetRadioGroup(nsIRadioGroup* aGroup) = 0; + +}; + +#endif // nsIRadioButton_h__ + + diff --git a/mozilla/widget/public/nsIRadioGroup.h b/mozilla/widget/public/nsIRadioGroup.h new file mode 100644 index 00000000000..b4fc7c2efa0 --- /dev/null +++ b/mozilla/widget/public/nsIRadioGroup.h @@ -0,0 +1,80 @@ +/* -*- 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. + */ +#ifndef nsIRadioGroup_h__ +#define nsIRadioGroup_h__ + +#include "nsString.h" + +#define NS_IRADIOGROUP_IID \ +{ 0x961085f1, 0xbd28, 0x11d1, \ +{ 0x97, 0xef, 0x0, 0x60, 0x97, 0x3, 0xc1, 0x4e } } + + +class nsIRadioGroup; +class nsIRadioButton; +class nsIEnumerator; + +/** + * Help class for implementing a "group" of radio buttons + * + */ + +class nsIRadioGroup : public nsISupports +{ + +public: + + /** + * Adds a RadioButton to the group + * @param nsIRadioButton* the radio button to be added + * + */ + virtual void Add(nsIRadioButton * aRadioBtn) = 0; + + /** + * Removes a RadioButton from the group + * @param nsIRadioButton* the radio button to be removed + * + */ + virtual void Remove(nsIRadioButton * aRadioBtn) = 0; + + /** + * Setd the name of the RadioGroup + * @param nsString The new name of the radio group + * + */ + virtual void SetName(const nsString &aName) = 0; + + /** + * Tells the RadioGroup that a child RadioButton has been clicked and it should set + * the approproate state on the other buttons + * @param nsIRadioButton* THe RadioButton that was clicked + * + */ + virtual void Clicked(nsIRadioButton * aChild) = 0; + + /** + * Gets the enumeration of children + * @param PRBool nsIEnumerator* The enumeration of children (radio buttons) in the RadioGroup + * + */ + virtual nsIEnumerator* GetChildren() = 0; +}; + +#endif // nsIRadioGroup_h__ + diff --git a/mozilla/widget/public/nsIScrollbar.h b/mozilla/widget/public/nsIScrollbar.h new file mode 100644 index 00000000000..539a1cb7c49 --- /dev/null +++ b/mozilla/widget/public/nsIScrollbar.h @@ -0,0 +1,101 @@ +/* -*- 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. + */ + +#ifndef nsIScrollbar_h__ +#define nsIScrollbar_h__ + +#include "nsIWidget.h" + +// {18032AD2-B265-11d1-AA2A-000000000000} +#define NS_ISCROLLBAR_IID \ +{ 0x18032ad2, 0xb265, 0x11d1, \ +{ 0xaa, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } } + +class nsIScrollbar : public nsIWidget +{ +public: + + /** + * Set the scrollbar range + * @param aEndRange set range for scrollbar from 0 to aEndRange + * + */ + virtual void SetMaxRange(PRUint32 aEndRange) = 0; + + /** + * Get the scrollbar range + * @returns the upper end of the scrollbar range + */ + virtual PRUint32 GetMaxRange() = 0; + + /** + * Set the thumb position. + * @param aPos a value between (startRange) and (endRange - thumbSize) + * + */ + virtual void SetPosition(PRUint32 aPos) = 0; + + /** + * Get the thumb position. + * @returns a value between (startRange) and (endRange - thumbSize) + * + */ + virtual PRUint32 GetPosition() = 0; + + /** + * Set the thumb size. + * @param aSize size of the thumb. Must be a value between + * startRange and endRange + */ + virtual void SetThumbSize(PRUint32 aSize) = 0; + + /** + * Get the thumb size. + * @returns size of the thumb. The value is between + * startRange and endRange + */ + virtual PRUint32 GetThumbSize() = 0; + + /** + * Set the line increment. + * @param aSize size of the line increment. The value must + * be between startRange and endRange + */ + virtual void SetLineIncrement(PRUint32 aSize) = 0; + + /** + * Get the line increment. + * @returns size of the line increment. The value is + * between startRange and endRange + */ + virtual PRUint32 GetLineIncrement() = 0; + + /** + * Set all scrollbar parameters at once + * @param aMaxRange set range for scrollbar from 0 to aMaxRange + * @param aThumbSize size of the thumb. Must be a value between + * startRange and endRange + * @param aPosition a value between (startRange) and (endRange - thumbSize) + * @param aLineIncrement size of the line increment. The value must + * be between startRange and endRange + */ + virtual void SetParameters(PRUint32 aMaxRange, PRUint32 aThumbSize, + PRUint32 aPosition, PRUint32 aLineIncrement) = 0; +}; + +#endif // nsIScrollbar_h__ diff --git a/mozilla/widget/public/nsITextAreaWidget.h b/mozilla/widget/public/nsITextAreaWidget.h new file mode 100644 index 00000000000..1665e3a2bae --- /dev/null +++ b/mozilla/widget/public/nsITextAreaWidget.h @@ -0,0 +1,42 @@ +/* -*- 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. + */ + +#ifndef nsITextAreaWidget_h__ +#define nsITextAreaWidget_h__ + +#include "nsIWidget.h" +#include "nsITextWidget.h" +#include "nsString.h" + +// {F8030012-C342-11d1-97F0-00609703C14E} +#define NS_ITEXTAREAWIDGET_IID \ +{ 0xf8030012, 0xc342, 0x11d1, { 0x97, 0xf0, 0x0, 0x60, 0x97, 0x3, 0xc1, 0x4e } }; + +/* + * Multi-line text editor. + * @see nsITextWidget for capabilities. + * Displays a scrollbar when the text content exceeds the number of lines + * displayed. + */ + +class nsITextAreaWidget : public nsITextWidget +{ +}; + +#endif // nsITextAreaWidget_h__ + diff --git a/mozilla/widget/public/nsITextWidget.h b/mozilla/widget/public/nsITextWidget.h new file mode 100644 index 00000000000..efb0a3a4c99 --- /dev/null +++ b/mozilla/widget/public/nsITextWidget.h @@ -0,0 +1,131 @@ +/* -*- 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. + */ +#ifndef nsITextWidget_h__ +#define nsITextWidget_h__ + +#include "nsIWidget.h" +#include "nsString.h" + +// {F8030011-C342-11d1-97F0-00609703C14E} +#define NS_ITEXTWIDGET_IID \ +{ 0xf8030011, 0xc342, 0x11d1, { 0x97, 0xf0, 0x0, 0x60, 0x97, 0x3, 0xc1, 0x4e } }; + +/* + * Single line text editor. + * + */ + +class nsITextWidget : public nsIWidget +{ + +public: + + /** + * Get the text of this component. + * + * @param aTextBuffer on return contains the text of this component + * @param aBufferSize the size of the buffer passed in + * @return the number of char copied + * + */ + + virtual PRUint32 GetText(nsString &aTextBuffer, PRUint32 aBufferSize) = 0; + + /** + * Set the text of this component. + * + * @param nsString, the text to set, must be null terminated + * @return PRUint32, the number of chars in the text string + * + */ + + virtual PRUint32 SetText(const nsString &aText) = 0; + + /** + * Insert text into this component. + * When aStartPos and aEndPos are a valid range this function performs a replace. + * When aStartPos and aEndPos are equal this function performs an insert. + * When aStartPos and aEndPos are both -1 (0xFFFFFFFF) this function performs an append. + * If aStartPos and aEndPos are out of range they are rounded to the closest end. + * + * @param aText the text to set + * @param aStartPos starting position for inserting text + * @param aEndPos ending position for inserting text + */ + + virtual PRUint32 InsertText(const nsString &aText, PRUint32 aStartPos, PRUint32 aEndPos) = 0; + + /** + * Remove any content from this text widget + */ + + virtual void RemoveText() = 0; + + /** + * Indicates a password will be entered. + * + * @param aIsPassword PR_TRUE shows contents as asterisks. PR_FALSE shows + * contents as normal text. + */ + + virtual void SetPassword(PRBool aIsPassword) = 0; + + /** + * Set the text widget to be read-only + * + * @param aReadOnlyFlag PR_TRUE the widget is read-only, + * PR_FALSE indicates the widget is writable. + * @return PR_TRUE if it was read only. PR_FALSE if it was writable + */ + + virtual PRBool SetReadOnly(PRBool aReadOnlyFlag) = 0; + + /** + * Set the selection in this text component + * @param aStartSel starting selection position in characters + * @param aEndSel ending selection position in characters + */ + + virtual void SetSelection(PRUint32 aStartSel, PRUint32 aEndSel) = 0; + + /** + * Get the selection in this text component + * @param aStartSel starting selection position in characters + * @param aEndSel ending selection position in characters + */ + + virtual void GetSelection(PRUint32 *aStartSel, PRUint32 *aEndSel) = 0; + + /** + * Set the caret position + * @param aPosition caret position in characters + */ + + virtual void SetCaretPosition(PRUint32 aPosition) = 0; + + /** + * Get the caret position + * @return caret position in characters + */ + + virtual PRUint32 GetCaretPosition() = 0; + +}; + +#endif // nsITextWidget_h__ + diff --git a/mozilla/widget/public/nsIToolkit.h b/mozilla/widget/public/nsIToolkit.h new file mode 100644 index 00000000000..a6a1ab06bb0 --- /dev/null +++ b/mozilla/widget/public/nsIToolkit.h @@ -0,0 +1,52 @@ +/* -*- 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. + */ + +#ifndef nsIToolkit_h__ +#define nsIToolkit_h__ + +#include "nsISupports.h" +#include "prthread.h" + +// {18032BD0-B265-11d1-AA2A-000000000000} +#define NS_ITOOLKIT_IID \ +{ 0x18032bd0, 0xb265, 0x11d1, \ + { 0xaa, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } } + + +/* + * Toolkit to associate with widgets. + * Each widget that is created must belong to a specific toolkit + * or the default toolkit. + */ + +class nsIToolkit : public nsISupports { + +public: + + /** + * Initialize this toolkit with aThread. + * @param aThread The thread passed in runs the message pump. + * NULL can be passed in, in which case a new thread gets created + * and a message pump will run in that thread + * + **/ + virtual void Init(PRThread *aThread) = 0; + +}; + +#endif diff --git a/mozilla/widget/public/nsIWidget.h b/mozilla/widget/public/nsIWidget.h new file mode 100644 index 00000000000..3de23fb7eec --- /dev/null +++ b/mozilla/widget/public/nsIWidget.h @@ -0,0 +1,313 @@ +/* -*- 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. + */ + +#ifndef nsIWidget_h__ +#define nsIWidget_h__ + +#include "nsISupports.h" +#include "nsColor.h" +#include "nsIMouseListener.h" +#include "nsIImage.h" + +#include "prthread.h" +#include "nsGUIEvent.h" + +// foreward declaration +class nsIToolkit; +class nsIFontMetrics; +class nsIToolkit; +class nsIRenderingContext; +class nsIEnumerator; +class nsIDeviceContext; +struct nsRect; +struct nsFont; + +class nsIPresContext; + +/** + * Callback function that deals with events. + * The argument is actually a subtype (subclass) of nsEvent which carries + * platform specific information about the event. Platform specific code knows + * how to deal with it. + * The return value determines whether or not the default action should take place. + */ + +typedef nsEventStatus (*PR_CALLBACK EVENT_CALLBACK)(nsGUIEvent *event); + +/** + * Flags for the getNativeData function. + * @see getNativeData() + */ +#define NS_NATIVE_WINDOW 0 +#define NS_NATIVE_GRAPHIC 1 +#define NS_NATIVE_COLORMAP 2 + +// {18032AD5-B265-11d1-AA2A-000000000000} +#define NS_IWIDGET_IID \ +{ 0x18032ad5, 0xb265, 0x11d1, \ +{ 0xaa, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } } + + +// Hide the native window systems real window type so as to avoid +// including native window system types and api's. This makes it +// easier to write cross-platform code. +typedef void* nsNativeWindow; + +enum nsCursor { eCursor_standard, eCursor_wait, eCursor_select, eCursor_hyperlink }; + +class nsIWidget : public nsISupports { + +public: + + /** + * Create and initialize a widget. All the arguments can be NULL in which case + * a top level window with size 0 is created. The event callback function has to + * be provided only if the caller wants to deal with the events this widget receives. + * The event callback is basically a preprocess hook called synchronously. The return + * value determines whether the event goes to the default window procedure or it is + * hidden to the os. The assumption is that if the event handler returns false the + * widget does not see the event. + * + * @param parent or null if it's a top level window + * @param the widget dimension + * @param the event handler callback function + * @return void + * + **/ + virtual void Create(nsIWidget *aParent, + const nsRect &aRect, + EVENT_CALLBACK aHandleEventFunction, + nsIDeviceContext *aContext, + nsIToolkit *aToolkit = nsnull) = 0; + + /** + * This Create takes a native window as a parent instead of a nsIWidget + **/ + virtual void Create(nsNativeWindow aParent, + const nsRect &aRect, + EVENT_CALLBACK aHandleEventFunction, + nsIDeviceContext *aContext, + nsIToolkit *aToolkit = nsnull) = 0; + + /** + * Close and destroy the current window. The object will still be around + * + **/ + virtual void Destroy(void) = 0; + + /** + * Return the parent Widget of this Widget or NULL if this is a top level window + * + * @return nsWidget*, the parent Widget + * + **/ + virtual nsIWidget* GetParent(void) = 0; + + /** + * Return an nsEnumerator over the children of this widget or null if no + * children. + * + * @return an enumerator over the list of children + * + **/ + virtual nsIEnumerator* GetChildren(void) = 0; + + /** + * used internally to add a remove from the children list + * + **/ + virtual void AddChild(nsIWidget* aChild) = 0; + virtual void RemoveChild(nsIWidget* aChild) = 0; + + /** + * Show/hide the Widget according to the boolean argument + * + * @param aState PR_TRUE to show the Widget, PR_FALSE to hide it + * + **/ + virtual void Show(PRBool aState) = 0; + + /** + * Move the Widget. The coordinates are expressed in the parent coordinate system. + * + * @param aX the new x position + * @param aY the new y position + * + **/ + virtual void Move(PRUint32 aX, PRUint32 aY) = 0; + + /** + * Move/resize/reshape the Widget. The coordinates are expressed in + * the parent coordinate system. + * + * @param aWidth the new width + * @param aHeight the new height + * + */ + virtual void Resize(PRUint32 aWidth, + PRUint32 aHeight) = 0; + + /** + * Move/resize/reshape the Widget. The coordinates are expressed in + * the parent coordinate system. + * + * @param aX the new x position + * @param aY the new y position + * @param aWidth the new width + * @param aHeight the new height + * + */ + virtual void Resize(PRUint32 aX, + PRUint32 aY, + PRUint32 aWidth, + PRUint32 aHeight) = 0; + + /** + * Enable/Disable the Widget according to the boolean argument + * + * @param aState PR_TRUE to enable the Widget, PR_FALSE to disable it + * + */ + virtual void Enable(PRBool aState) = 0; + + /** + * Give focus to this Widget + * + */ + virtual void SetFocus(void) = 0; + + /** + * Get this Widget dimension + * + * @param aRect, on return has the dimension of this Widget + * + */ + virtual void GetBounds(nsRect &aRect) = 0; + + /** + * Get the foreground color + * @returns the current foreground color + * + */ + virtual nscolor GetForegroundColor(void) = 0; + + /** + * Set the foreground color + * @param aColor the new foreground color + * + */ + + virtual void SetForegroundColor(const nscolor &aColor) = 0; + + /** + * Get the background color + * @returns the current background color + * + */ + + virtual nscolor GetBackgroundColor(void) = 0; + + /** + * Set the background color + * @param aColor the new background color + * @returns the current background color + * + */ + + virtual void SetBackgroundColor(const nscolor &aColor) = 0; + + /** + * Get the font + * @returns the font metrics + */ + + virtual nsIFontMetrics* GetFont(void) = 0; + + /** + * Set the font + * @param aFont font to display. @see nsFont for allowable fonts + */ + + virtual void SetFont(const nsFont &aFont) = 0; + + /** + * Get the cursor for this Widget. + * @returns the cursor used by the widget + */ + + virtual nsCursor GetCursor(void) = 0; + + /** + * Set the cursor for this Widget. + * @aCursor the cursor for this widget + */ + + virtual void SetCursor(nsCursor aCursor) = 0; + + /** + * Invalidate the Widget and repaint + * + * @param aIsSynchronouse repaint synchronously if aIsSynchronous is PR_TRUE/ + * + **/ + virtual void Invalidate(PRBool aIsSynchronous) = 0; + + + /** + * Adds a MouseListener to the widget + * + */ + virtual void AddMouseListener(nsIMouseListener * aListener) = 0; + + /** + * Return the widget's toolkit + * @return the toolkit this widget was created in. @see nsToolkit.h + * + */ + virtual nsIToolkit* GetToolkit() = 0; + + /** + * Set the color map for the widget + * @param aColorMap color map for displaying the widget + * + */ + + virtual void SetColorMap(nsColorMap *aColorMap) = 0; + + /** + * Scroll the widget + * + * @param aDx amount to scroll along the x-axis + * @param aDy amount to scroll along the y-axis. + * @param aClipRect clipping rectangle to limit the scroll to. + * + */ + + virtual void Scroll(PRInt32 aDx, PRInt32 aDy, nsRect *aClipRect) = 0; + + /* + * Internal methods + */ + + virtual void* GetNativeData(PRUint32 aDataType) = 0; + virtual nsIRenderingContext* GetRenderingContext() = 0; + virtual nsIDeviceContext* GetDeviceContext() = 0; + +}; + +#endif // nsIWidget_h__ diff --git a/mozilla/widget/public/nsWidgetsCID.h b/mozilla/widget/public/nsWidgetsCID.h new file mode 100644 index 00000000000..7b3c8e38ca0 --- /dev/null +++ b/mozilla/widget/public/nsWidgetsCID.h @@ -0,0 +1,83 @@ +/* -*- 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. + */ + +/* 2d96b3d0-c051-11d1-a827-0040959a28c9 */ +#define NS_WINDOW_CID \ +{ 0x2d96b3d0, 0xc051, 0x11d1, \ + {0xa8, 0x27, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9}} + +/* 2d96b3d1-c051-11d1-a827-0040959a28c9 */ +#define NS_CHILD_CID \ +{ 0x2d96b3d1, 0xc051, 0x11d1, \ + {0xa8, 0x27, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9} } + +/* 2d96b3d2-c051-11d1-a827-0040959a28c9 */ +#define NS_BUTTON_CID \ +{ 0x2d96b3d2, 0xc051, 0x11d1, \ + {0xa8, 0x27, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9} } + +/* 2d96b3d3-c051-11d1-a827-0040959a28c9 */ +#define NS_CHECKBUTTON_CID \ +{ 0x2d96b3d3, 0xc051, 0x11d1, \ + {0xa8, 0x27, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9} } + +/* 2d96b3d4-c051-11d1-a827-0040959a28c9 */ +#define NS_COMBOBOX_CID \ +{ 0x2d96b3d4, 0xc051, 0x11d1, \ + {0xa8, 0x27, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9} } + +/* 2d96b3d5-c051-11d1-a827-0040959a28c9 */ +#define NS_FILEWIDGET_CID \ +{ 0x2d96b3d5, 0xc051, 0x11d1, \ + {0xa8, 0x27, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9} } + +/* 2d96b3d6-c051-11d1-a827-0040959a28c9 */ +#define NS_LISTBOX_CID \ +{ 0x2d96b3d6, 0xc051, 0x11d1, \ + {0xa8, 0x27, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9} } + +/* 2d96b3d7-c051-11d1-a827-0040959a28c9 */ +#define NS_RADIOBUTTON_CID \ +{ 0x2d96b3d7, 0xc051, 0x11d1, \ + {0xa8, 0x27, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9} } + +/* 2d96b3d8-c051-11d1-a827-0040959a28c9 */ +#define NS_RADIOGROUP_CID \ +{ 0x2d96b3d8, 0xc051, 0x11d1, \ + {0xa8, 0x27, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9} } + +/* 2d96b3d9-c051-11d1-a827-0040959a28c9 */ +#define NS_HORZSCROLLBAR_CID \ +{ 0x2d96b3d9, 0xc051, 0x11d1, \ + {0xa8, 0x27, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9} } + +/* 2d96b3da-c051-11d1-a827-0040959a28c9 */ +#define NS_VERTSCROLLBAR_CID \ +{ 0x2d96b3da, 0xc051, 0x11d1, \ + {0xa8, 0x27, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9} } + +/* 2d96b3db-c051-11d1-a827-0040959a28c9 */ +#define NS_TEXTAREA_CID \ +{ 0x2d96b3db, 0xc051, 0x11d1, \ + {0xa8, 0x27, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9} } + +/* 2d96b3dc-c051-11d1-a827-0040959a28c9 */ +#define NS_TEXTFIELD_CID \ +{ 0x2d96b3dc, 0xc051, 0x11d1, \ + {0xa8, 0x27, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9} } + diff --git a/mozilla/widget/public/nsui.h b/mozilla/widget/public/nsui.h new file mode 100644 index 00000000000..6fdc3cb089b --- /dev/null +++ b/mozilla/widget/public/nsui.h @@ -0,0 +1,27 @@ +/* -*- 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. + */ +#ifndef nsui_h___ +#define nsui_h___ + +#ifdef _IMPL_NS_UI +#define NS_UI NS_EXPORT +#else +#define NS_UI NS_IMPORT +#endif + +#endif /* nsui_h___ */ diff --git a/mozilla/widget/src/Makefile b/mozilla/widget/src/Makefile new file mode 100644 index 00000000000..86d0c812c5a --- /dev/null +++ b/mozilla/widget/src/Makefile @@ -0,0 +1,26 @@ +#!gmake +# +# 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. + +DEPTH=../.. + +#DIRS = windows + +include $(DEPTH)/config/config.mk + +TARGET = $(LIBRARY) + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/widget/src/makefile.win b/mozilla/widget/src/makefile.win new file mode 100644 index 00000000000..f0f7579ab74 --- /dev/null +++ b/mozilla/widget/src/makefile.win @@ -0,0 +1,23 @@ +#!nmake +# +# 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. + +DEPTH=..\.. +IGNORE_MANIFEST=1 + +DIRS=windows + +include <$(DEPTH)\config\rules.mak> diff --git a/mozilla/widget/src/windows/Makefile b/mozilla/widget/src/windows/Makefile new file mode 100644 index 00000000000..f516bfbbe18 --- /dev/null +++ b/mozilla/widget/src/windows/Makefile @@ -0,0 +1,23 @@ +#!gmake +# +# 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 manifest.mn + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/widget/src/windows/makefile.win b/mozilla/widget/src/windows/makefile.win new file mode 100644 index 00000000000..23fda8c5846 --- /dev/null +++ b/mozilla/widget/src/windows/makefile.win @@ -0,0 +1,77 @@ +#!nmake +# +# 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. + +DEPTH=..\..\.. +IGNORE_MANIFEST=1 + +MAKE_OBJ_TYPE = DLL +DLLNAME = raptorwidget +DLL=.\$(OBJDIR)\$(DLLNAME).dll +RESFILE = widget.res + +MISCDEP = \ + $(DIST)\lib\xpcom32.lib \ + $(DIST)\lib\raptorbase.lib \ + $(DIST)\lib\raptorgfx.lib + +MODULE=raptor + +DEFINES =-D_IMPL_NS_WIDGET + +OBJS = \ + .\$(OBJDIR)\nsWidgetFactory.obj \ + .\$(OBJDIR)\nsObject.obj \ + .\$(OBJDIR)\nsWindow.obj \ + .\$(OBJDIR)\nsToolkit.obj \ + .\$(OBJDIR)\nsButton.obj \ + .\$(OBJDIR)\nsCheckButton.obj \ + .\$(OBJDIR)\nsRadioGroup.obj \ + .\$(OBJDIR)\nsRadioButton.obj \ + .\$(OBJDIR)\nsListBox.obj \ + .\$(OBJDIR)\nsComboBox.obj \ + .\$(OBJDIR)\nsTextWidget.obj \ + .\$(OBJDIR)\nsTextHelper.obj \ + .\$(OBJDIR)\nsTextAreaWidget.obj \ + .\$(OBJDIR)\nsFileWidget.obj \ + .\$(OBJDIR)\nsScrollbar.obj \ + $(NULL) + +LINCS= \ + -I$(PUBLIC)\raptor \ + -I$(PUBLIC)\xpcom \ + $(NULL) + +LCFLAGS = \ + $(LCFLAGS) \ + -D_IMPL_NS_WIDGET \ + -DNS_DLLNAME=$(DLLNAME).dll \ + $(NULL) + +LLIBS= \ + comdlg32.lib \ + $(DIST)\lib\xpcom32.lib \ + $(DIST)\lib\raptorgfx.lib \ + $(DIST)\lib\raptorbase.lib \ + $(LIBNSPR) + +include <$(DEPTH)\config\rules.mak> + +install:: $(DLL) + $(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).dll $(DIST)\bin + +clobber:: + rm -f $(DIST)\bin\$(DLLNAME).dll diff --git a/mozilla/widget/src/windows/nsButton.cpp b/mozilla/widget/src/windows/nsButton.cpp new file mode 100644 index 00000000000..8ffc20ee2a5 --- /dev/null +++ b/mozilla/widget/src/windows/nsButton.cpp @@ -0,0 +1,136 @@ +/* -*- 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 "nsButton.h" +#include "nsToolkit.h" +#include "nsColor.h" +#include "nsGUIEvent.h" +#include "nsString.h" +#include "nsStringUtil.h" +#include + +//------------------------------------------------------------------------- +// +// nsButton constructor +// +//------------------------------------------------------------------------- +nsButton::nsButton(nsISupports *aOuter) : nsWindow(aOuter) +{ +} + +//------------------------------------------------------------------------- +// +// nsButton destructor +// +//------------------------------------------------------------------------- +nsButton::~nsButton() +{ +} + +//------------------------------------------------------------------------- +// +// Query interface implementation +// +//------------------------------------------------------------------------- +nsresult nsButton::QueryObject(const nsIID& aIID, void** aInstancePtr) +{ + nsresult result = nsWindow::QueryObject(aIID, aInstancePtr); + + static NS_DEFINE_IID(kInsButtonIID, NS_IBUTTON_IID); + if (result == NS_NOINTERFACE && aIID.Equals(kInsButtonIID)) { + *aInstancePtr = (void*) ((nsIButton*)this); + AddRef(); + result = NS_OK; + } + + return result; +} + +//------------------------------------------------------------------------- +// +// Set this button label +// +//------------------------------------------------------------------------- +void nsButton::SetLabel(const nsString& aText) +{ + NS_ALLOC_STR_BUF(label, aText, 256); + VERIFY(::SetWindowText(mWnd, label)); + NS_FREE_STR_BUF(label); +} + +//------------------------------------------------------------------------- +// +// Get this button label +// +//------------------------------------------------------------------------- +void nsButton::GetLabel(nsString& aBuffer) +{ + int actualSize = ::GetWindowTextLength(mWnd)+1; + NS_ALLOC_CHAR_BUF(label, 256, actualSize); + ::GetWindowText(mWnd, label, actualSize); + aBuffer.SetLength(0); + aBuffer.Append(label); + NS_FREE_CHAR_BUF(label); +} + +//------------------------------------------------------------------------- +// +// paint message. Don't send the paint out +// +//------------------------------------------------------------------------- +PRBool nsButton::OnPaint() +{ + //printf("** nsButton::OnPaint **\n"); + return PR_FALSE; +} + +PRBool nsButton::OnResize(nsRect &aWindowRect) +{ + return PR_FALSE; +} + +//------------------------------------------------------------------------- +// +// return the window class name and initialize the class if needed +// +//------------------------------------------------------------------------- +LPCTSTR nsButton::WindowClass() +{ + return "BUTTON"; +} + +//------------------------------------------------------------------------- +// +// return window styles +// +//------------------------------------------------------------------------- +DWORD nsButton::WindowStyle() +{ + return WS_CHILD | WS_CLIPSIBLINGS; +} + +//------------------------------------------------------------------------- +// +// return window extended styles +// +//------------------------------------------------------------------------- +DWORD nsButton::WindowExStyle() +{ + return 0; +} + diff --git a/mozilla/widget/src/windows/nsButton.h b/mozilla/widget/src/windows/nsButton.h new file mode 100644 index 00000000000..62525d4acf9 --- /dev/null +++ b/mozilla/widget/src/windows/nsButton.h @@ -0,0 +1,57 @@ +/* -*- 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. + */ + +#ifndef nsButton_h__ +#define nsButton_h__ + +#include "nsdefs.h" +#include "nsWindow.h" +#include "nsSwitchToUIThread.h" + +#include "nsIButton.h" + +class nsButton : public nsWindow, + public nsIButton +{ + +public: + nsButton(nsISupports *aOuter); + virtual ~nsButton(); + + // nsISupports. Forward to the nsObject base class + BASE_SUPPORT + + virtual nsresult QueryObject(const nsIID& aIID, void** aInstancePtr); + + // nsIWidget interface + BASE_IWIDGET_IMPL + + // nsIButton part + virtual void SetLabel(const nsString& aText); + virtual void GetLabel(nsString& aBuffer); + virtual PRBool OnPaint(); + virtual PRBool OnResize(nsRect &aWindowRect); + +protected: + virtual LPCTSTR WindowClass(); + virtual DWORD WindowStyle(); + virtual DWORD WindowExStyle(); + +}; + +#endif // nsButton_h__ diff --git a/mozilla/widget/src/windows/nsCList.h b/mozilla/widget/src/windows/nsCList.h new file mode 100644 index 00000000000..bf9f3939fe3 --- /dev/null +++ b/mozilla/widget/src/windows/nsCList.h @@ -0,0 +1,102 @@ +/* -*- 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. + */ + +#ifndef CLIST_H +#define CLIST_H + +#include + +// ----------------------------------------------------------------------- +// +// Simple circular linked-list implementation... +// +// ----------------------------------------------------------------------- + +// Foreward declarations... +struct CList; + +#define OBJECT_PTR_FROM_CLIST(className, listElement) \ + ((char*)listElement - offsetof(className, m_link)) + + +struct CList { + CList *next; + CList *prev; + + CList() { + next = prev = this; + } + + ~CList() { + Remove(); + } + + // + // Append an element to the end of this list + // + void Append(CList &element) { + element.next = this; + element.prev = prev; + prev->next = &element; + prev = &element; + } + + // + // Add an element to the beginning of this list + // + void Add(CList &element) { + element.next = next; + element.prev = this; + next->prev = &element; + next = &element; + } + + // + // Append this element to the end of a list + // + void AppendToList(CList &list) { + list.Append(*this); + } + + // + // Add this element to the beginning of a list + // + void AddToList(CList &list) { + list.Add(*this); + } + + // + // Remove this element from the list and re-initialize + // + void Remove(void) { + prev->next = next; + next->prev = prev; + + next = prev = this; + } + + // + // Is this list empty ? + // + BOOL IsEmpty(void) { + return (next == this); + } +}; + +#endif // CLIST_H + diff --git a/mozilla/widget/src/windows/nsCheckButton.cpp b/mozilla/widget/src/windows/nsCheckButton.cpp new file mode 100644 index 00000000000..5109d36d98c --- /dev/null +++ b/mozilla/widget/src/windows/nsCheckButton.cpp @@ -0,0 +1,170 @@ +/* -*- 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 "nsCheckButton.h" +#include "nsToolkit.h" +#include "nsColor.h" +#include "nsGUIEvent.h" +#include "nsString.h" +#include "nsStringUtil.h" +#include + +//------------------------------------------------------------------------- +// +// nsCheckButton constructor +// +//------------------------------------------------------------------------- +nsCheckButton::nsCheckButton(nsISupports *aOuter) : nsWindow(aOuter) +{ +} + + +//------------------------------------------------------------------------- +// +// nsCheckButton destructor +// +//------------------------------------------------------------------------- +nsCheckButton::~nsCheckButton() +{ +} + + +//------------------------------------------------------------------------- +// +// Query interface implementation +// +//------------------------------------------------------------------------- +nsresult nsCheckButton::QueryObject(const nsIID& aIID, void** aInstancePtr) +{ + nsresult result = nsWindow::QueryObject(aIID, aInstancePtr); + + static NS_DEFINE_IID(kInsCheckButtonIID, NS_ICHECKBUTTON_IID); + if (result == NS_NOINTERFACE && aIID.Equals(kInsCheckButtonIID)) { + *aInstancePtr = (void*) ((nsICheckButton*)this); + AddRef(); + result = NS_OK; + } + + return result; +} + +//------------------------------------------------------------------------- +// +// Set this button label +// +//------------------------------------------------------------------------- +void nsCheckButton::SetState(PRBool aState) +{ + BOOL state; + if (aState) + state = BST_CHECKED; + else + state = BST_UNCHECKED; + ::SendMessage(mWnd, BM_SETCHECK, (WPARAM)state, (LPARAM)0); +} + +//------------------------------------------------------------------------- +// +// Set this button label +// +//------------------------------------------------------------------------- +PRBool nsCheckButton::GetState() +{ + if (::SendMessage(mWnd, BM_GETCHECK, (WPARAM)0, (LPARAM)0) == BST_CHECKED) + return PR_TRUE; + else + return PR_FALSE; +} + +//------------------------------------------------------------------------- +// +// Set this button label +// +//------------------------------------------------------------------------- +void nsCheckButton::SetLabel(const nsString& aText) +{ + char label[256]; + aText.ToCString(label, 256); + label[255] = '\0'; + VERIFY(::SetWindowText(mWnd, label)); +} + + +//------------------------------------------------------------------------- +// +// Get this button label +// +//------------------------------------------------------------------------- +void nsCheckButton::GetLabel(nsString& aBuffer) +{ + int actualSize = ::GetWindowTextLength(mWnd)+1; + NS_ALLOC_CHAR_BUF(label, 256, actualSize); + ::GetWindowText(mWnd, label, actualSize); + aBuffer.SetLength(0); + aBuffer.Append(label); + NS_FREE_CHAR_BUF(label); +} + +//------------------------------------------------------------------------- +// +// paint message. Don't send the paint out +// +//------------------------------------------------------------------------- +PRBool nsCheckButton::OnPaint() +{ + return PR_FALSE; +} + +PRBool nsCheckButton::OnResize(nsRect &aWindowRect) +{ + return PR_FALSE; +} + +//------------------------------------------------------------------------- +// +// return the window class name and initialize the class if needed +// +//------------------------------------------------------------------------- +LPCTSTR nsCheckButton::WindowClass() +{ + return "BUTTON"; +} + + +//------------------------------------------------------------------------- +// +// return window styles +// +//------------------------------------------------------------------------- +DWORD nsCheckButton::WindowStyle() +{ + return BS_CHECKBOX | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS; +} + + +//------------------------------------------------------------------------- +// +// return window extended styles +// +//------------------------------------------------------------------------- +DWORD nsCheckButton::WindowExStyle() +{ + return 0; +} + + diff --git a/mozilla/widget/src/windows/nsCheckButton.h b/mozilla/widget/src/windows/nsCheckButton.h new file mode 100644 index 00000000000..3daa88f1159 --- /dev/null +++ b/mozilla/widget/src/windows/nsCheckButton.h @@ -0,0 +1,63 @@ +/* -*- 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. + */ + +#ifndef nsCheckButton_h__ +#define nsCheckButton_h__ + +#include "nsdefs.h" +#include "nsWindow.h" +#include "nsSwitchToUIThread.h" + +#include "nsICheckButton.h" + +class nsCheckButton : public nsWindow, + public nsICheckButton +{ + +public: + nsCheckButton(nsISupports *aOuter); + virtual ~nsCheckButton(); + + // nsISupports. Forward to the nsObject base class + BASE_SUPPORT + + virtual nsresult QueryObject(const nsIID& aIID, void** aInstancePtr); + + // nsIWidget interface + BASE_IWIDGET_IMPL + + // nsIChecknsButton part + virtual void SetLabel(const nsString& aText); + virtual void GetLabel(nsString& aBuffer); + + virtual PRBool OnPaint(); + virtual PRBool OnResize(nsRect &aWindowRect); + + virtual void SetState(PRBool aState); + virtual PRBool GetState(); + + +protected: + + virtual LPCTSTR WindowClass(); + virtual DWORD WindowStyle(); + virtual DWORD WindowExStyle(); + +}; + +#endif // nsCheckButton_h__ diff --git a/mozilla/widget/src/windows/nsComboBox.cpp b/mozilla/widget/src/windows/nsComboBox.cpp new file mode 100644 index 00000000000..eb4ecd47525 --- /dev/null +++ b/mozilla/widget/src/windows/nsComboBox.cpp @@ -0,0 +1,222 @@ +/* -*- 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 "nsComboBox.h" +#include "nsToolkit.h" +#include "nsColor.h" +#include "nsGUIEvent.h" +#include "nsString.h" +#include "nsStringUtil.h" +#include + +//------------------------------------------------------------------------- +// +// destructor +// +//------------------------------------------------------------------------- +void nsComboBox::AddItemAt(nsString &aItem, PRInt32 aPosition) +{ + NS_ALLOC_STR_BUF(val, aItem, 256); + ::SendMessage(mWnd, CB_ADDSTRING, (int)aPosition, (LPARAM)(LPCTSTR)val); + NS_FREE_STR_BUF(val); +} + +//------------------------------------------------------------------------- +// +// Finds an item at a postion +// +//------------------------------------------------------------------------- +PRInt32 nsComboBox::FindItem(nsString &aItem, PRInt32 aStartPos) +{ + NS_ALLOC_STR_BUF(val, aItem, 256); + int index = ::SendMessage(mWnd, CB_FINDSTRINGEXACT, (int)aStartPos, (LPARAM)(LPCTSTR)val); + NS_FREE_STR_BUF(val); + + return index; +} + +//------------------------------------------------------------------------- +// +// CountItems - Get Item Count +// +//------------------------------------------------------------------------- +PRInt32 nsComboBox::GetItemCount() +{ + return (PRInt32)::SendMessage(mWnd, CB_GETCOUNT, (int)0, (LPARAM)0); +} + +//------------------------------------------------------------------------- +// +// Removes an Item at a specified location +// +//------------------------------------------------------------------------- +PRBool nsComboBox::RemoveItemAt(PRInt32 aPosition) +{ + int status = ::SendMessage(mWnd, CB_DELETESTRING, (int)aPosition, (LPARAM)(LPCTSTR)0); + return (status != CB_ERR?PR_TRUE:PR_FALSE); +} + +//------------------------------------------------------------------------- +// +// Removes an Item at a specified location +// +//------------------------------------------------------------------------- +PRBool nsComboBox::GetItemAt(nsString& anItem, PRInt32 aPosition) +{ + PRBool result = PR_FALSE; + int len = ::SendMessage(mWnd, CB_GETLBTEXTLEN, (int)aPosition, (LPARAM)0); + if (len != CB_ERR) { + char * str = new char[len+1]; + anItem.SetLength(0); + int status = ::SendMessage(mWnd, CB_GETLBTEXT, (int)aPosition, (LPARAM)(LPCTSTR)str); + if (status != CB_ERR) { + anItem.Append(str); + result = PR_TRUE; + } + delete str; + } + return result; +} + +//------------------------------------------------------------------------- +// +// Gets the selected of selected item +// +//------------------------------------------------------------------------- +void nsComboBox::GetSelectedItem(nsString& aItem) +{ + + int index = ::SendMessage(mWnd, CB_GETCURSEL, (int)0, (LPARAM)0); + GetItemAt(aItem, index); +} + +//------------------------------------------------------------------------- +// +// Gets the list of selected otems +// +//------------------------------------------------------------------------- +PRInt32 nsComboBox::GetSelectedIndex() +{ + return ::SendMessage(mWnd, CB_GETCURSEL, (int)0, (LPARAM)0); +} + +//------------------------------------------------------------------------- +// +// SelectItem +// +//------------------------------------------------------------------------- +void nsComboBox::SelectItem(PRInt32 aPosition) +{ + ::SendMessage(mWnd, CB_SETCURSEL, (int)aPosition, (LPARAM)0); +} + +//------------------------------------------------------------------------- +// +// Deselect +// +//------------------------------------------------------------------------- +void nsComboBox::Deselect() +{ + ::SendMessage(mWnd, CB_SETCURSEL, (WPARAM)-1, (LPARAM)0); +} + +//------------------------------------------------------------------------- +// +// nsComboBox constructor +// +//------------------------------------------------------------------------- +nsComboBox::nsComboBox(nsISupports *aOuter) : nsWindow(aOuter) +{ + mBackground = NS_RGB(124, 124, 124); +} + +//------------------------------------------------------------------------- +// +// destructor +// +//------------------------------------------------------------------------- +nsComboBox::~nsComboBox() +{ +} + +//------------------------------------------------------------------------- +// +// Query interface implementation +// +//------------------------------------------------------------------------- +nsresult nsComboBox::QueryObject(const nsIID& aIID, void** aInstancePtr) +{ + nsresult result = nsWindow::QueryObject(aIID, aInstancePtr); + + static NS_DEFINE_IID(kInsComboBoxIID, NS_ICOMBOBOX_IID); + if (result == NS_NOINTERFACE && aIID.Equals(kInsComboBoxIID)) { + *aInstancePtr = (void*) ((nsIComboBox*)this); + AddRef(); + result = NS_OK; + } + + return result; +} + +//------------------------------------------------------------------------- +// +// paint message. Don't send the paint out +// +//------------------------------------------------------------------------- +PRBool nsComboBox::OnPaint() +{ + return PR_FALSE; +} + +PRBool nsComboBox::OnResize(nsRect &aWindowRect) +{ + return PR_FALSE; +} + + +//------------------------------------------------------------------------- +// +// return the window class name and initialize the class if needed +// +//------------------------------------------------------------------------- +LPCTSTR nsComboBox::WindowClass() +{ + return("COMBOBOX"); +} + +//------------------------------------------------------------------------- +// +// return window styles +// +//------------------------------------------------------------------------- +DWORD nsComboBox::WindowStyle() +{ + return (CBS_DROPDOWNLIST | CBS_DISABLENOSCROLL | WS_BORDER | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS); +} + +//------------------------------------------------------------------------- +// +// return window extended styles +// +//------------------------------------------------------------------------- +DWORD nsComboBox::WindowExStyle() +{ + return WS_EX_CLIENTEDGE; +} + + diff --git a/mozilla/widget/src/windows/nsComboBox.h b/mozilla/widget/src/windows/nsComboBox.h new file mode 100644 index 00000000000..8b2a95ab31d --- /dev/null +++ b/mozilla/widget/src/windows/nsComboBox.h @@ -0,0 +1,65 @@ +/* -*- 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. + */ + +#ifndef nsComboBox_h__ +#define nsComboBox_h__ + +#include "nsdefs.h" +#include "nsWindow.h" +#include "nsSwitchToUIThread.h" +#include "nsIComboBox.h" + +class nsComboBox : public nsWindow, + public nsIComboBox +{ + +public: + nsComboBox(nsISupports *aOuter); + ~nsComboBox(); + + // nsISupports. Forward to the nsObject base class + BASE_SUPPORT + + nsresult QueryObject(const nsIID& aIID, void** aInstancePtr); + PRBool nsComboBox::OnPaint(); + virtual PRBool OnResize(nsRect &aWindowRect); + + // nsIWidget interface + BASE_IWIDGET_IMPL + + // nsIComboBox part + + void AddItemAt(nsString &aItem, PRInt32 aPosition); + PRInt32 FindItem(nsString &aItem, PRInt32 aStartPos); + PRInt32 GetItemCount(); + PRBool RemoveItemAt(PRInt32 aPosition); + PRBool GetItemAt(nsString& anItem, PRInt32 aPosition); + void GetSelectedItem(nsString& aItem); + PRInt32 GetSelectedIndex(); + void SelectItem(PRInt32 aPosition); + void Deselect() ; + +protected: + + LPCTSTR WindowClass(); + DWORD WindowStyle(); + DWORD WindowExStyle(); + +}; + +#endif // nsComboBox_h__ diff --git a/mozilla/widget/src/windows/nsFileWidget.cpp b/mozilla/widget/src/windows/nsFileWidget.cpp new file mode 100644 index 00000000000..9b1c41dc3a0 --- /dev/null +++ b/mozilla/widget/src/windows/nsFileWidget.cpp @@ -0,0 +1,186 @@ +/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */ +/* + * 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. + */ + +// Define so header files for openfilename are included +#ifdef WIN32_LEAN_AND_MEAN +#undef WIN32_LEAN_AND_MEAN +#endif + +#include "nsFileWidget.h" +#include + +//------------------------------------------------------------------------- +// +// Show - Display the file dialog +// +//------------------------------------------------------------------------- + +PRBool nsFileWidget::Show() +{ + char fileBuffer[MAX_PATH]; + fileBuffer[0] = '\0'; + OPENFILENAME ofn; + memset(&ofn, 0, sizeof(ofn)); + + ofn.lStructSize = sizeof(ofn); + + nsString filterList; + GetFilterListArray(filterList); + char *filterBuffer = filterList.ToNewCString(); + char *title = mTitle.ToNewCString(); + ofn.lpstrTitle = title; + ofn.lpstrFilter = filterBuffer; + ofn.nFilterIndex = 1; + ofn.hwndOwner = mWnd; + ofn.lpstrFile = fileBuffer; + ofn.nMaxFile = MAX_PATH; + ofn.Flags = OFN_SHAREAWARE | OFN_NOCHANGEDIR | OFN_LONGNAMES | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY; + + BOOL result; + + // Save current directory, so we can reset if it changes. + char* currentDirectory = new char[MAX_PATH+1]; + VERIFY(::GetCurrentDirectory(MAX_PATH, currentDirectory) > 0); + + if (mMode == eMode_load) { + result = GetOpenFileName(&ofn); + } + else if (mMode == eMode_save) { + result = GetSaveFileName(&ofn); + } + else { + NS_ASSERTION(0, "Only load and save are supported modes"); + } + + VERIFY(::SetCurrentDirectory(currentDirectory)); + + // Clean up filter buffers + delete filterBuffer; + delete title; + + // Set user-selected location of file or directory + mFile.SetLength(0); + if (result==PR_TRUE) { + mFile.Append(fileBuffer); + } + + return((PRBool)result); +} + +//------------------------------------------------------------------------- +// +// Convert filter titles + filters into a Windows filter string +// +//------------------------------------------------------------------------- + +void nsFileWidget::GetFilterListArray(nsString& aFilterList) +{ + aFilterList.SetLength(0); + for (PRUint32 i = 0; i < mNumberOfFilters; i++) { + const nsString& title = mTitles[i]; + const nsString& filter = mFilters[i]; + + aFilterList.Append(title); + aFilterList.Append('\0'); + aFilterList.Append(filter); + aFilterList.Append('\0'); + } + aFilterList.Append('\0'); +} + +//------------------------------------------------------------------------- +// +// Set the list of filters +// +//------------------------------------------------------------------------- + +void nsFileWidget::SetFilterList(PRUint32 aNumberOfFilters,const nsString aTitles[],const nsString aFilters[]) +{ + mNumberOfFilters = aNumberOfFilters; + mTitles = aTitles; + mFilters = aFilters; +} + +//------------------------------------------------------------------------- +// +// Get the file + path +// +//------------------------------------------------------------------------- + +void nsFileWidget::GetFile(nsString& aFile) +{ + aFile.SetLength(0); + aFile.Append(mFile); +} + +//------------------------------------------------------------------------- +// +// nsFileWidget constructor +// +//------------------------------------------------------------------------- +nsFileWidget::nsFileWidget(nsISupports *aOuter) : nsObject(aOuter) +{ + mWnd = NULL; + mNumberOfFilters = 0; +} + + +void nsFileWidget:: Create(nsIWidget *aParent, + nsString& aTitle, + nsMode aMode, + nsIDeviceContext *aContext, + nsIToolkit *aToolkit) +{ + mWnd = aParent; + mTitle.SetLength(0); + mTitle.Append(aTitle); + mMode = aMode; +} + + +//------------------------------------------------------------------------- +// +// nsFileWidget destructor +// +//------------------------------------------------------------------------- +nsFileWidget::~nsFileWidget() +{ +} + +//------------------------------------------------------------------------- +// +// Query interface implementation +// +//------------------------------------------------------------------------- +nsresult nsFileWidget::QueryObject(const nsIID& aIID, void** aInstancePtr) +{ + // nsresult result = nsWindow::QueryObject(aIID, aInstancePtr); + + nsresult result = NS_NOINTERFACE; + static NS_DEFINE_IID(kInsFileWidgetIID, NS_IFILEWIDGET_IID); + if (result == NS_NOINTERFACE && aIID.Equals(kInsFileWidgetIID)) { + *aInstancePtr = (void*) ((nsIFileWidget*)this); + AddRef(); + result = NS_OK; + } + + return result; +} + + + diff --git a/mozilla/widget/src/windows/nsFileWidget.h b/mozilla/widget/src/windows/nsFileWidget.h new file mode 100644 index 00000000000..97a46721708 --- /dev/null +++ b/mozilla/widget/src/windows/nsFileWidget.h @@ -0,0 +1,65 @@ +/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */ +/* + * 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. + */ + +#ifndef nsFileWidget_h__ +#define nsFileWidget_h__ + +#include "nsObject.h" +#include "nsToolkit.h" +#include "nsIWidget.h" +#include "nsIFileWidget.h" + +class nsFileWidget : public nsIFileWidget, public nsObject +{ + public: + nsFileWidget(nsISupports *aOuter); + virtual ~nsFileWidget(); + + // nsISupports. Forward to the nsObject base class + BASE_SUPPORT + + virtual nsresult QueryObject(const nsIID& aIID, void** aInstancePtr); + PRBool OnPaint(); + + // nsIWidget interface + + virtual void Create( nsIWidget *aParent, + nsString& aTitle, + nsMode aMode, + nsIDeviceContext *aContext = nsnull, + nsIToolkit *aToolkit = nsnull); + + // nsIFileWidget part + virtual PRBool Show(); + virtual void GetFile(nsString& aFile); + virtual void SetFilterList(PRUint32 aNumberOfFilters,const nsString aTitles[],const nsString aFilters[]); + + protected: + + HWND mWnd; + nsString mTitle; + nsMode mMode; + nsString mFile; + PRUint32 mNumberOfFilters; + const nsString* mTitles; + const nsString* mFilters; + + void GetFilterListArray(nsString& aFilterList); +}; + +#endif // nsFileWidget_h__ diff --git a/mozilla/widget/src/windows/nsListBox.cpp b/mozilla/widget/src/windows/nsListBox.cpp new file mode 100644 index 00000000000..8a930471b85 --- /dev/null +++ b/mozilla/widget/src/windows/nsListBox.cpp @@ -0,0 +1,278 @@ +/* -*- 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 "nsListBox.h" +#include "nsToolkit.h" +#include "nsColor.h" +#include "nsGUIEvent.h" +#include "nsString.h" +#include "nsStringUtil.h" +#include + +//------------------------------------------------------------------------- +// +// initializer +// +//------------------------------------------------------------------------- + +void nsListBox::SetMultipleSelection(PRBool aMultipleSelections) +{ + mMultiSelect = aMultipleSelections; +} + +//------------------------------------------------------------------------- +// +// destructor +// +//------------------------------------------------------------------------- + +void nsListBox::AddItemAt(nsString &aItem, PRInt32 aPosition) +{ + NS_ALLOC_STR_BUF(val, aItem, 256); + SendMessage(mWnd, LB_INSERTSTRING, (int)aPosition, (LPARAM)(LPCTSTR)val); + NS_FREE_STR_BUF(val); +} + +//------------------------------------------------------------------------- +// +// Finds an item at a postion +// +//------------------------------------------------------------------------- +PRInt32 nsListBox::FindItem(nsString &aItem, PRInt32 aStartPos) +{ + NS_ALLOC_STR_BUF(val, aItem, 256); + int index = ::SendMessage(mWnd, LB_FINDSTRINGEXACT, (int)aStartPos, (LPARAM)(LPCTSTR)val); + NS_FREE_STR_BUF(val); + + return index; +} + +//------------------------------------------------------------------------- +// +// CountItems - Get Item Count +// +//------------------------------------------------------------------------- +PRInt32 nsListBox::GetItemCount() +{ + return (PRInt32)::SendMessage(mWnd, LB_GETCOUNT, (int)0, (LPARAM)0); +} + +//------------------------------------------------------------------------- +// +// Removes an Item at a specified location +// +//------------------------------------------------------------------------- +PRBool nsListBox::RemoveItemAt(PRInt32 aPosition) +{ + int status = ::SendMessage(mWnd, LB_DELETESTRING, (int)aPosition, (LPARAM)(LPCTSTR)0); + return (status != LB_ERR?PR_TRUE:PR_FALSE); +} + +//------------------------------------------------------------------------- +// +// Removes an Item at a specified location +// +//------------------------------------------------------------------------- +PRBool nsListBox::GetItemAt(nsString& anItem, PRInt32 aPosition) +{ + PRBool result = PR_FALSE; + int len = ::SendMessage(mWnd, LB_GETTEXTLEN, (int)aPosition, (LPARAM)0); + if (len != LB_ERR) { + char * str = new char[len+1]; + anItem.SetLength(0); + int status = ::SendMessage(mWnd, LB_GETTEXT, (int)aPosition, (LPARAM)(LPCTSTR)str); + if (status != LB_ERR) { + anItem.Append(str); + result = PR_TRUE; + } + delete str; + } + return result; +} + +//------------------------------------------------------------------------- +// +// Gets the selected of selected item +// +//------------------------------------------------------------------------- +void nsListBox::GetSelectedItem(nsString& aItem) +{ + int index = ::SendMessage(mWnd, LB_GETCURSEL, (int)0, (LPARAM)0); + GetItemAt(aItem, index); +} + +//------------------------------------------------------------------------- +// +// Gets the list of selected otems +// +//------------------------------------------------------------------------- +PRInt32 nsListBox::GetSelectedIndex() +{ + if (!mMultiSelect) { + return ::SendMessage(mWnd, LB_GETCURSEL, (int)0, (LPARAM)0); + } else { + NS_ASSERTION(0, "Multi selection list box does not support GetSlectedIndex()"); + } + return 0; +} + +//------------------------------------------------------------------------- +// +// SelectItem +// +//------------------------------------------------------------------------- +void nsListBox::SelectItem(PRInt32 aPosition) +{ + if (!mMultiSelect) { + ::SendMessage(mWnd, LB_SETCURSEL, (int)aPosition, (LPARAM)0); + } else { + ::SendMessage(mWnd, LB_SETSEL, (WPARAM) (BOOL)PR_TRUE, (LPARAM)(UINT)aPosition); + } +} + +//------------------------------------------------------------------------- +// +// GetSelectedCount +// +//------------------------------------------------------------------------- +PRInt32 nsListBox::GetSelectedCount() +{ + if (!mMultiSelect) { + PRInt32 inx = GetSelectedIndex(); + return (inx == -1? 0 : 1); + } else { + return ::SendMessage(mWnd, LB_GETSELCOUNT, (int)0, (LPARAM)0); + } +} + +//------------------------------------------------------------------------- +// +// GetSelectedIndices +// +//------------------------------------------------------------------------- +void nsListBox::GetSelectedIndices(PRInt32 aIndices[], PRInt32 aSize) +{ + ::SendMessage(mWnd, LB_GETSELITEMS, (int)aSize, (LPARAM)aIndices); +} + +//------------------------------------------------------------------------- +// +// Deselect +// +//------------------------------------------------------------------------- +void nsListBox::Deselect() +{ + if (!mMultiSelect) { + ::SendMessage(mWnd, LB_SETCURSEL, (WPARAM)-1, (LPARAM)0); + } else { + ::SendMessage(mWnd, LB_SETSEL, (WPARAM) (BOOL)PR_FALSE, (LPARAM)(UINT)-1); + } + +} + + +//------------------------------------------------------------------------- +// +// nsListBox constructor +// +//------------------------------------------------------------------------- +nsListBox::nsListBox(nsISupports *aOuter) : nsWindow(aOuter) +{ + mMultiSelect = PR_FALSE; + mBackground = NS_RGB(124, 124, 124); +} + +//------------------------------------------------------------------------- +// +// nsListBox:: destructor +// +//------------------------------------------------------------------------- +nsListBox::~nsListBox() +{ +} + +//------------------------------------------------------------------------- +// +// Query interface implementation +// +//------------------------------------------------------------------------- +nsresult nsListBox::QueryObject(const nsIID& aIID, void** aInstancePtr) +{ + nsresult result = nsWindow::QueryObject(aIID, aInstancePtr); + + static NS_DEFINE_IID(kInsListBoxIID, NS_ILISTBOX_IID); + if (result == NS_NOINTERFACE && aIID.Equals(kInsListBoxIID)) { + *aInstancePtr = (void*) ((nsIListBox*)this); + AddRef(); + result = NS_OK; + } + + return result; +} + +//------------------------------------------------------------------------- +// +// paint message. Don't send the paint out +// +//------------------------------------------------------------------------- +PRBool nsListBox::OnPaint() +{ + return PR_FALSE; +} + +PRBool nsListBox::OnResize(nsRect &aWindowRect) +{ + return PR_FALSE; +} + + +//------------------------------------------------------------------------- +// +// return the window class name and initialize the class if needed +// +//------------------------------------------------------------------------- +LPCTSTR nsListBox::WindowClass() +{ + return("LISTBOX"); +} + +//------------------------------------------------------------------------- +// +// return window styles +// +//------------------------------------------------------------------------- +DWORD nsListBox::WindowStyle() +{ + DWORD style = (WS_BORDER | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_VSCROLL); + if (mMultiSelect) + style = LBS_MULTIPLESEL | style; + + return style; +} + +//------------------------------------------------------------------------- +// +// return window extended styles +// +//------------------------------------------------------------------------- +DWORD nsListBox::WindowExStyle() +{ + return 0; +} + + diff --git a/mozilla/widget/src/windows/nsListBox.h b/mozilla/widget/src/windows/nsListBox.h new file mode 100644 index 00000000000..c83a6406fd5 --- /dev/null +++ b/mozilla/widget/src/windows/nsListBox.h @@ -0,0 +1,68 @@ +/* -*- 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. + */ + +#ifndef nsListBox_h__ +#define nsListBox_h__ + +#include "nsdefs.h" +#include "nsWindow.h" +#include "nsSwitchToUIThread.h" +#include "nsIListBox.h" + +class nsListBox : public nsWindow, + public nsIListBox +{ + +public: + nsListBox(nsISupports *aOuter); + virtual ~nsListBox(); + + // nsISupports. Forward to the nsObject base class + BASE_SUPPORT + + virtual nsresult QueryObject(const nsIID& aIID, void** aInstancePtr); + PRBool OnPaint(); + virtual PRBool OnResize(nsRect &aWindowRect); + + // nsIWidget interface + BASE_IWIDGET_IMPL + + // nsIListBox part + void SetMultipleSelection(PRBool aMultipleSelections); + void AddItemAt(nsString &aItem, PRInt32 aPosition); + PRInt32 FindItem(nsString &aItem, PRInt32 aStartPos); + PRInt32 GetItemCount(); + PRBool RemoveItemAt(PRInt32 aPosition); + PRBool GetItemAt(nsString& anItem, PRInt32 aPosition); + void GetSelectedItem(nsString& aItem); + PRInt32 GetSelectedIndex(); + void AllowMultipleSelections(PRBool aMultiple); + PRInt32 GetSelectedCount(); + void GetSelectedIndices(PRInt32 aIndices[], PRInt32 aSize); + void SelectItem(PRInt32 aPosition); + void Deselect() ; + +protected: + PRBool mMultiSelect; + virtual LPCTSTR WindowClass(); + virtual DWORD WindowStyle(); + virtual DWORD WindowExStyle(); + +}; + +#endif // nsListBox_h__ diff --git a/mozilla/widget/src/windows/nsObject.cpp b/mozilla/widget/src/windows/nsObject.cpp new file mode 100644 index 00000000000..a3390643d34 --- /dev/null +++ b/mozilla/widget/src/windows/nsObject.cpp @@ -0,0 +1,146 @@ +/* -*- 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 "nsObject.h" + +CList nsObject::s_liveChain; +PRMonitor *nsObject::s_liveChainMutex = PR_NewMonitor(); + +#ifdef _DEBUG +int32 nsObject::s_nObjects = 0; +#endif + +/** + * constructor + */ +nsObject::nsObject(nsISupports *aOuter) +{ + // ref count init + mRefCnt = 1; + // assign outer + if (aOuter) + mOuter = aOuter; + else + mOuter = (nsISupports*)&mInner; + + // + // Add the new object the chain of allocated nsObjects + // + PR_EnterMonitor(s_liveChainMutex); + s_liveChain.Append(m_link); + PR_ExitMonitor(s_liveChainMutex); +#ifdef _DEBUG + s_nObjects++; +#endif +} + + +/** + * destructor + */ +nsObject::~nsObject() +{ +#ifdef _DEBUG + s_nObjects--; +#endif + // + // Remove from the chain of allocated nsObjects + // + PR_EnterMonitor(s_liveChainMutex); + m_link.Remove(); + PR_ExitMonitor(s_liveChainMutex); +} + +/** + * The evil triad + */ +nsresult nsObject::QueryInterface(const nsIID& aIID, void** aInstancePtr) +{ + return mOuter->QueryInterface(aIID, aInstancePtr); +} + +/** + * + */ +nsrefcnt nsObject::AddRef(void) +{ + return mOuter->AddRef(); +} + +/** + * + */ +nsrefcnt nsObject::Release(void) +{ + return NS_RELEASE(mOuter); +} + +/** + * + */ +inline nsrefcnt nsObject::AddRefObject(void) { + return ++mRefCnt; +} + +/** + * + */ +inline nsrefcnt nsObject::ReleaseObject(void) { + return (--mRefCnt) ? mRefCnt : (delete this, 0); +} + +/** + * + */ +nsresult nsObject::QueryObject(const nsIID& aIID, void** aInstancePtr) +{ + if (NULL == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + if (aIID.Equals(kISupportsIID)) { + *aInstancePtr = (void*) ((nsISupports*)&mInner); + AddRef(); + return NS_OK; + } + + return NS_NOINTERFACE; +} + + +/** + * static utility. Delete all live objects + */ +void nsObject::DeleteAllObjects(void) +{ + PR_EnterMonitor(s_liveChainMutex); + + while (!s_liveChain.IsEmpty()) { + nsObject *pnsObject; + + pnsObject = (nsObject*)OBJECT_PTR_FROM_CLIST(nsObject, s_liveChain.next); + + // Remove the event from the chain... + pnsObject->m_link.Remove(); + delete pnsObject; + } + + PR_ExitMonitor(s_liveChainMutex); +} + diff --git a/mozilla/widget/src/windows/nsObject.h b/mozilla/widget/src/windows/nsObject.h new file mode 100644 index 00000000000..12f488aaa0e --- /dev/null +++ b/mozilla/widget/src/windows/nsObject.h @@ -0,0 +1,109 @@ +/* -*- 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. + */ + +#ifndef OBJECT_H +#define OBJECT_H + +#include "nsdefs.h" +#include "nsCList.h" + +#include "nsISupports.h" + +#include "prmon.h" + +/* + * nsObject is the base class for all widgets + */ + +class nsObject : public nsISupports +{ + +public: + nsObject(nsISupports *aOuter); + virtual ~nsObject(); + + // the evil triad. + // Implementation of those, always forward to the outer object. + NS_IMETHOD QueryInterface(const nsIID& aIID, + void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(void); + NS_IMETHOD_(nsrefcnt) Release(void); + + // + // Derived classes have to implement this one + // + virtual nsresult QueryObject(const nsIID& aIID, void** aInstancePtr); + +protected: + // + // Data members: + // + CList m_link; + +private: + nsISupports *mOuter; + + class InnerSupport : public nsISupports { + public: + InnerSupport() {} + +#define INNER_OUTER \ + ((nsObject*)((char*)this - offsetof(nsObject, mInner))) + + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr) + { return INNER_OUTER->QueryObject(aIID, aInstancePtr); } + NS_IMETHOD_(nsrefcnt) AddRef(void) + { return INNER_OUTER->AddRefObject(); } + NS_IMETHOD_(nsrefcnt) Release(void) + { return INNER_OUTER->ReleaseObject(); } + } mInner; + friend InnerSupport; + + nsrefcnt mRefCnt; + nsrefcnt AddRefObject(void); + nsrefcnt ReleaseObject(void); + +public: + + // + // The following data members are used to maintain a chain of all + // allocated nsObject instances. This chain is traversed at + // shutdown to clean up any dangling instances... + // + static CList s_liveChain; + static PRMonitor *s_liveChainMutex; + +#ifdef _DEBUG + static int32 s_nObjects; +#endif + + static void DeleteAllObjects(void); + +}; + +#define BASE_SUPPORT \ + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr) \ + { return nsObject::QueryInterface(aIID, aInstancePtr); } \ + NS_IMETHOD_(nsrefcnt) AddRef(void) \ + { return nsObject::AddRef(); } \ + NS_IMETHOD_(nsrefcnt) Release(void) \ + { return nsObject::Release(); } + + +#endif // OBJECT_H + diff --git a/mozilla/widget/src/windows/nsRadioButton.cpp b/mozilla/widget/src/windows/nsRadioButton.cpp new file mode 100644 index 00000000000..74cce3a7bc0 --- /dev/null +++ b/mozilla/widget/src/windows/nsRadioButton.cpp @@ -0,0 +1,226 @@ +/* -*- 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 "nsRadioButton.h" +#include "nsToolkit.h" +#include "nsColor.h" +#include "nsGUIEvent.h" +#include "nsStringUtil.h" + +#include + +//------------------------------------------------------------------------- +// +// nsRadioButton constructor +// +//------------------------------------------------------------------------- +nsRadioButton::nsRadioButton(nsISupports *aOuter) : nsWindow(aOuter) +{ + fRadioGroup = NULL; +} + + +//------------------------------------------------------------------------- +// +// nsRadioButton destructor +// +//------------------------------------------------------------------------- +nsRadioButton::~nsRadioButton() +{ +} + + +//------------------------------------------------------------------------- +// +// Query interface implementation +// +//------------------------------------------------------------------------- +nsresult nsRadioButton::QueryObject(const nsIID& aIID, void** aInstancePtr) +{ + nsresult result = nsWindow::QueryObject(aIID, aInstancePtr); + + static NS_DEFINE_IID(kInsRadioButtonIID, NS_IRADIOBUTTON_IID); + if (result == NS_NOINTERFACE && aIID.Equals(kInsRadioButtonIID)) { + *aInstancePtr = (void*) ((nsIRadioButton*)this); + AddRef(); + result = NS_OK; + } + + return result; +} + +//------------------------------------------------------------------------- +// +// Sets the state of the nsRadioButton but it DOES notify its nsRadioGroup. +// +//------------------------------------------------------------------------- +void nsRadioButton::SetState(PRBool aState) +{ + fState = aState; + + ::SendMessage(GetWindowHandle(), BM_SETCHECK, (WPARAM)(fState), 0L); + if (nsnull != fRadioGroup) + fRadioGroup->Clicked(this); +} + +//------------------------------------------------------------------------- +// +// Sets the state of the nsRadioButton but it does not notify +// its nsRadioGroup. +// +//------------------------------------------------------------------------- +void nsRadioButton::SetStateNoNotify(PRBool aState) +{ + fState = aState; + ::SendMessage(GetWindowHandle(), BM_SETCHECK, (WPARAM)(fState), 0L); +} + +//------------------------------------------------------------------------- +// +// Set this button label +// +//------------------------------------------------------------------------- +PRBool nsRadioButton::GetState() +{ + return fState; +} + +//------------------------------------------------------------------------- +// +// Return the radio group this radio button belongs to +// +//------------------------------------------------------------------------- +nsIRadioGroup* nsRadioButton::GetRadioGroup() +{ + if (fRadioGroup) + fRadioGroup->AddRef(); + return fRadioGroup; +} + + +//------------------------------------------------------------------------- +// +// Set the radio button group +// +//------------------------------------------------------------------------- +void nsRadioButton::SetRadioGroup(nsIRadioGroup* aGroup) +{ + if (aGroup) + aGroup->AddRef(); + + if (fRadioGroup) + NS_RELEASE(fRadioGroup); + + fRadioGroup = aGroup; + fRadioGroup->Add(this); +} + +//------------------------------------------------------------------------- +// +// Set this button label +// +//------------------------------------------------------------------------- +void nsRadioButton::SetLabel(const nsString& aText) +{ + char label[256]; + aText.ToCString(label, 256); + label[255] = '\0'; + VERIFY(::SetWindowText(mWnd, label)); +} + + +//------------------------------------------------------------------------- +// +// Get this button label +// +//------------------------------------------------------------------------- +void nsRadioButton::GetLabel(nsString& aBuffer) +{ + int actualSize = ::GetWindowTextLength(mWnd)+1; + NS_ALLOC_CHAR_BUF(label, 256, actualSize); + ::GetWindowText(mWnd, label, actualSize); + aBuffer.SetLength(0); + aBuffer.Append(label); + NS_FREE_CHAR_BUF(label); +} + +//------------------------------------------------------------------------- +// +// Process all windows messages +// +//------------------------------------------------------------------------- +PRBool nsRadioButton::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *aRetValue) +{ + *aRetValue = 0; + + if (msg == WM_LBUTTONUP) { + SetState(PR_TRUE); + return PR_FALSE; + } else { + return nsWindow::ProcessMessage(msg, wParam, lParam, aRetValue); + } +} + +//------------------------------------------------------------------------- +// +// paint message. Don't send the paint out +// +//------------------------------------------------------------------------- +PRBool nsRadioButton::OnPaint() +{ + return PR_FALSE; +} + +PRBool nsRadioButton::OnResize(nsRect &aWindowRect) +{ + return PR_FALSE; +} + +//------------------------------------------------------------------------- +// +// return the window class name and initialize the class if needed +// +//------------------------------------------------------------------------- +LPCTSTR nsRadioButton::WindowClass() +{ + return "BUTTON"; +} + + +//------------------------------------------------------------------------- +// +// return window styles +// +//------------------------------------------------------------------------- +DWORD nsRadioButton::WindowStyle() +{ + return BS_RADIOBUTTON | WS_CHILD | WS_CLIPSIBLINGS; +} + + +//------------------------------------------------------------------------- +// +// return window extended styles +// +//------------------------------------------------------------------------- +DWORD nsRadioButton::WindowExStyle() +{ + return 0; +} + + diff --git a/mozilla/widget/src/windows/nsRadioButton.h b/mozilla/widget/src/windows/nsRadioButton.h new file mode 100644 index 00000000000..adc414fa2de --- /dev/null +++ b/mozilla/widget/src/windows/nsRadioButton.h @@ -0,0 +1,72 @@ +/* -*- 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. + */ + +#ifndef nsRadioButton_h__ +#define nsRadioButton_h__ + +#include "nsdefs.h" +#include "nsWindow.h" +#include "nsSwitchToUIThread.h" +#include "nsString.h" + +#include "nsIRadioButton.h" +#include "nsIRadioGroup.h" + +class nsRadioButton : public nsWindow, + public nsIRadioButton +{ + +public: + nsRadioButton(nsISupports *aOuter); + virtual ~nsRadioButton(); + + // nsISupports. Forward to the nsObject base class + BASE_SUPPORT + + virtual nsresult QueryObject(const nsIID& aIID, void** aInstancePtr); + + // nsIWidget interface + BASE_IWIDGET_IMPL + + // nsIRadioButton part + virtual void SetLabel(const nsString& aText); + virtual void GetLabel(nsString& aBuffer); + + virtual PRBool OnPaint(); + virtual PRBool OnResize(nsRect &aWindowRect); + + virtual void SetState(PRBool aState); + virtual void SetStateNoNotify(PRBool aState); + virtual PRBool GetState(); + + virtual nsIRadioGroup* GetRadioGroup(); + virtual void SetRadioGroup(nsIRadioGroup* aGroup); + +protected: + PRBool fState; + nsIRadioGroup* fRadioGroup; + + virtual LPCTSTR WindowClass(); + virtual DWORD WindowStyle(); + virtual DWORD WindowExStyle(); + + virtual PRBool ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *aRetValue); + +}; + +#endif // nsRadioButton_h__ diff --git a/mozilla/widget/src/windows/nsRadioGroup.cpp b/mozilla/widget/src/windows/nsRadioGroup.cpp new file mode 100644 index 00000000000..4e813d60366 --- /dev/null +++ b/mozilla/widget/src/windows/nsRadioGroup.cpp @@ -0,0 +1,377 @@ +/* -*- 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 "nsRadioGroup.h" +#include "nsToolkit.h" +#include "nsStringUtil.h" + + +class nsStringHashKey : public nsHashKey { +public: + nsStringHashKey(const nsString & aKey); + ~nsStringHashKey(); + + PRBool operator==(const nsStringHashKey& aOther) const; + PRBool Equals(const nsHashKey* aOther) const; + PRUint32 HashValue(void) const; + nsHashKey* Clone(void) const; + +private: + nsStringHashKey(); + nsStringHashKey(const nsStringHashKey& aCopy); + nsStringHashKey& operator=(const nsStringHashKey& aCopy); + +protected: + nsString mKey; + PRUint32 mHashValid; + PRUint32 mHashValue; + +}; + +nsStringHashKey::nsStringHashKey(const nsString & aKey) +{ + mKey.SetLength(0); + mKey.Append(aKey); + mHashValid = 0; +} + +nsStringHashKey::nsStringHashKey(const nsStringHashKey& aCopy) +{ + mKey.SetLength(0); + mKey.Append(aCopy.mKey); + mHashValid = aCopy.mHashValid; + mHashValue = aCopy.mHashValue; +} + +nsStringHashKey::~nsStringHashKey() +{ +} + +PRBool nsStringHashKey::operator==(const nsStringHashKey& aOther) const +{ + return Equals(&aOther); +} + +PRBool nsStringHashKey::Equals(const nsHashKey* aOther) const +{ + PRBool result = PR_TRUE; + + const nsStringHashKey* other = (nsStringHashKey*)aOther; + + if (nsnull != other && other != this) { + result = mKey.Equals(other->mKey); + } + return result; +} + +nsHashKey* nsStringHashKey::Clone(void) const +{ + return new nsStringHashKey(*this); +} + +PRUint32 nsStringHashKey::HashValue(void) const +{ + if (0 == mHashValid) { + ((nsStringHashKey*)this)->mHashValue = 0; + + NS_ALLOC_STR_BUF(val, mKey, 256) + PRUint32 hash = 0; + PRUint32 off = 0; + PRUint32 len = mKey.Length(); + + if (len < 16) { + for (PRUint32 i = len ; i > 0; i--) { + hash = (hash * 37) + val[off++]; + } + } else { // only sample some characters + PRUint32 skip = len / 8; + for (PRUint32 i = len ; i > 0; i -= skip, off += skip) { + hash = (hash * 39) + val[off]; + } + } + NS_FREE_STR_BUF(val) + ((nsStringHashKey*)this)->mHashValue = hash;//^= (hash & 0x7FFFFFFF); + ((nsStringHashKey*)this)->mHashValid = 1; + } + return mHashValue; +} + + + +nsHashtable * nsRadioGroup::mRadioGroupHashtable = new nsHashtable(8); + +PRBool HashtableEnum(nsHashKey *aKey, void *aData) { + printf("HashtableEnum %s\n", aKey); + return PR_TRUE; +} + +//------------------------------------------------------------------------- +// +// nsRadioGroup static methods +// +//------------------------------------------------------------------------- +nsRadioGroup * nsRadioGroup::getNamedRadioGroup(const nsString & aName) { + nsStringHashKey key(aName); + nsRadioGroup * group = (nsRadioGroup *)mRadioGroupHashtable->Get((nsHashKey *)&key); + return group; +} + +NS_EXPORT nsIRadioGroup * NS_GetRadioGroup(const nsString &aName) { + return nsRadioGroup::getNamedRadioGroup(aName); +} + + +//------------------------------------------------------------------------- +// +// nsRadioGroup constructor +// +//------------------------------------------------------------------------- +nsRadioGroup::nsRadioGroup(nsISupports *aOuter) : nsObject(aOuter) +{ + mChildren = NULL; +} + + +//------------------------------------------------------------------------- +// +// nsRadioGroup destructor +// +//------------------------------------------------------------------------- +nsRadioGroup::~nsRadioGroup() +{ + if (mChildren) { + mChildren = NULL; + } +} + + +//------------------------------------------------------------------------- +// +// Query interface implementation +// +//------------------------------------------------------------------------- +nsresult nsRadioGroup::QueryObject(const nsIID& aIID, void** aInstancePtr) +{ + nsresult result = nsObject::QueryObject(aIID, aInstancePtr); + + static NS_DEFINE_IID(kInsRadioGroupIID, NS_IRADIOGROUP_IID); + if (result == NS_NOINTERFACE && aIID.Equals(kInsRadioGroupIID)) { + *aInstancePtr = (void*) ((nsIRadioGroup*)this); + AddRef(); + result = NS_OK; + } + + return result; + +} + + +//------------------------------------------------------------------------- +// +// Gives a name to this group of radio buttons +// +//------------------------------------------------------------------------- +void nsRadioGroup::SetName(const nsString &aName) +{ + mName.SetLength(0); + mName.Append(aName); + mRadioGroupHashtable->Put(new nsStringHashKey(aName), this); +} + + +//------------------------------------------------------------------------- +// +// Adds a nsRadioButton to this group +// +//------------------------------------------------------------------------- +void nsRadioGroup::Clicked(nsIRadioButton * aChild) +{ + if (mChildren) { + nsIEnumerator * enumerator = GetChildren(); + nsIRadioButton * child = (nsIRadioButton*)enumerator->Next(); + while (child) { + child->SetStateNoNotify((PRBool)(child == aChild)); + NS_RELEASE(child); + child = (nsIRadioButton*)enumerator->Next(); + } + NS_RELEASE(enumerator); + } +} + +//------------------------------------------------------------------------- +// +// Adds a nsRadioButton to this group +// +//------------------------------------------------------------------------- +void nsRadioGroup::Add(nsIRadioButton * aChild) +{ + if (!mChildren) { + mChildren = new Enumerator(); + } + + mChildren->Append(aChild); + +} + +//------------------------------------------------------------------------- +// +// Removes a nsRadioButton from this group +// +//------------------------------------------------------------------------- +void nsRadioGroup::Remove(nsIRadioButton * aChild) +{ + if (mChildren) { + mChildren->Remove(aChild); + } + +} + +//------------------------------------------------------------------------- +// +// Get this window's list of children +// +//------------------------------------------------------------------------- +nsIEnumerator* nsRadioGroup::GetChildren() +{ + if (mChildren) { + mChildren->Reset(); + mChildren->AddRef(); + return mChildren; + } + + return NULL; +} + + +//------------------------------------------------------------------------- +// +// Constructor +// +//------------------------------------------------------------------------- +#define INITIAL_SIZE 2 + +nsRadioGroup::Enumerator::Enumerator() +{ + mRefCnt = 1; + mArraySize = INITIAL_SIZE; + mChildrens = (nsIRadioButton**)new DWORD[mArraySize]; + memset(mChildrens, 0, sizeof(DWORD) * mArraySize); + mCurrentPosition = 0; +} + + +//------------------------------------------------------------------------- +// +// Destructor +// +//------------------------------------------------------------------------- +nsRadioGroup::Enumerator::~Enumerator() +{ + if (mChildrens) { + for (int i = 0; mChildrens[i] && i < mArraySize; i++) { + NS_RELEASE(mChildrens[i]); + } + + delete[] mChildrens; + } +} + +// +// The evil triad +// +NS_IMPL_ISUPPORTS(nsRadioGroup::Enumerator, NS_IENUMERATOR_IID); + +//------------------------------------------------------------------------- +// +// Get enumeration next element. Return null at the end +// +//------------------------------------------------------------------------- +nsISupports* nsRadioGroup::Enumerator::Next() +{ + if (mCurrentPosition < mArraySize && mChildrens[mCurrentPosition]) { + mChildrens[mCurrentPosition]->AddRef(); + return mChildrens[mCurrentPosition++]; + } + + return NULL; +} + + +//------------------------------------------------------------------------- +// +// Reset enumerator internal pointer to the beginning +// +//------------------------------------------------------------------------- +void nsRadioGroup::Enumerator::Reset() +{ + mCurrentPosition = 0; +} + + +//------------------------------------------------------------------------- +// +// Append an element +// +//------------------------------------------------------------------------- +void nsRadioGroup::Enumerator::Append(nsIRadioButton* aRadioButton) +{ + NS_PRECONDITION(aRadioButton, "Adding a null radio button to a radio group"); + if (aRadioButton) { + int pos; + for (pos = 0; pos < mArraySize && mChildrens[pos]; pos++); + if (pos == mArraySize) { + GrowArray(); + } + mChildrens[pos] = aRadioButton; + aRadioButton->AddRef(); + } +} + + +//------------------------------------------------------------------------- +// +// Remove an element +// +//------------------------------------------------------------------------- +void nsRadioGroup::Enumerator::Remove(nsIRadioButton* aRadioButton) +{ + int pos; + for(pos = 0; mChildrens[pos] && (mChildrens[pos] != aRadioButton); pos++); + if (mChildrens[pos] == aRadioButton) { + NS_RELEASE(aRadioButton); + memcpy(mChildrens + pos, mChildrens + pos + 1, mArraySize - pos - 1); + } + +} + + +//------------------------------------------------------------------------- +// +// Grow the size of the children array +// +//------------------------------------------------------------------------- +void nsRadioGroup::Enumerator::GrowArray() +{ + mArraySize <<= 1; + nsIRadioButton **newArray = (nsIRadioButton**)new DWORD[mArraySize]; + memset(newArray, 0, sizeof(DWORD) * mArraySize); + memcpy(newArray, mChildrens, (mArraySize>>1) * sizeof(DWORD)); + mChildrens = newArray; +} + + diff --git a/mozilla/widget/src/windows/nsRadioGroup.h b/mozilla/widget/src/windows/nsRadioGroup.h new file mode 100644 index 00000000000..ca37bb7ae54 --- /dev/null +++ b/mozilla/widget/src/windows/nsRadioGroup.h @@ -0,0 +1,86 @@ +/* -*- 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. + */ + +#ifndef nsRadioGroup_h__ +#define nsRadioGroup_h__ + +#include "nsdefs.h" +#include "nsWindow.h" +#include "nsSwitchToUIThread.h" + +#include "nsIRadioGroup.h" +#include "nsRadioButton.h" +#include "nsHashtable.h" + +class nsRadioGroup : public nsObject, + public nsIRadioGroup +{ + +public: + nsRadioGroup(nsISupports *aOuter); + virtual ~nsRadioGroup(); + + // nsISupports. Forward to the nsObject base class + BASE_SUPPORT + + virtual nsresult QueryObject(const nsIID& aIID, void** aInstancePtr); + + // nsIRadioGroup part + virtual void Add(nsIRadioButton * aChild); + virtual void Remove(nsIRadioButton * aChild); + + virtual void SetName(const nsString &aName); + + virtual void Clicked(nsIRadioButton * aChild); + virtual nsIEnumerator* GetChildren(); + + static nsRadioGroup * getNamedRadioGroup(const nsString & aName); + +protected: + nsString mName; + + static nsHashtable * mRadioGroupHashtable; + //static PRBool HashtableEnum(nsHashKey *aKey, void *aData); + + + // keep the list of children + class Enumerator : public nsIEnumerator { + nsIRadioButton **mChildrens; + int mCurrentPosition; + int mArraySize; + + public: + NS_DECL_ISUPPORTS + + Enumerator(); + ~Enumerator(); + + NS_IMETHOD_(nsISupports*) Next(); + NS_IMETHOD_(void) Reset(); + + void Append(nsIRadioButton* aWidget); + void Remove(nsIRadioButton* aWidget); + + private: + void GrowArray(); + + } *mChildren; + +}; + +#endif // nsRadioGroup_h__ diff --git a/mozilla/widget/src/windows/nsScrollbar.cpp b/mozilla/widget/src/windows/nsScrollbar.cpp new file mode 100644 index 00000000000..70fcd37b529 --- /dev/null +++ b/mozilla/widget/src/windows/nsScrollbar.cpp @@ -0,0 +1,452 @@ +/* -*- 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 "nsScrollbar.h" +#include "nsToolkit.h" +#include "nsGUIEvent.h" +#include +#include "nsUnitConversion.h" + +//------------------------------------------------------------------------- +// +// nsScrollbar constructor +// +//------------------------------------------------------------------------- +nsScrollbar::nsScrollbar(nsISupports *aOuter, PRBool aIsVertical) : nsWindow(aOuter) +{ + mPositionFlag = (aIsVertical) ? SBS_VERT : SBS_HORZ; + mScaleFactor = 1.0; + mLineIncrement = 0; + mBackground = ::GetSysColor(COLOR_SCROLLBAR); + mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground)); +} + + +//------------------------------------------------------------------------- +// +// nsScrollbar destructor +// +//------------------------------------------------------------------------- +nsScrollbar::~nsScrollbar() +{ +} + + +//------------------------------------------------------------------------- +// +// Query interface implementation +// +//------------------------------------------------------------------------- +nsresult nsScrollbar::QueryObject(const nsIID& aIID, void** aInstancePtr) +{ + nsresult result = nsWindow::QueryObject(aIID, aInstancePtr); + + static NS_DEFINE_IID(kInsScrollbarIID, NS_ISCROLLBAR_IID); + if (result == NS_NOINTERFACE && aIID.Equals(kInsScrollbarIID)) { + *aInstancePtr = (void*) ((nsIScrollbar*)this); + AddRef(); + result = NS_OK; + } + + return result; +} + + +//------------------------------------------------------------------------- +// +// Define the range settings +// +//------------------------------------------------------------------------- +void nsScrollbar::SetMaxRange(PRUint32 aEndRange) +{ + if (aEndRange > 32767) + mScaleFactor = aEndRange / 32767.0; + if (mWnd) { + VERIFY(::SetScrollRange(mWnd, SB_CTL, 0, NS_TO_INT_ROUND(aEndRange / mScaleFactor), TRUE)); + } +} + + +//------------------------------------------------------------------------- +// +// Return the range settings +// +//------------------------------------------------------------------------- +PRUint32 nsScrollbar::GetMaxRange() +{ + int startRange, endRange; + if (mWnd) { + VERIFY(::GetScrollRange(mWnd, SB_CTL, &startRange, &endRange)); + } + + return (PRUint32)NS_TO_INT_ROUND(endRange * mScaleFactor); +} + + +//------------------------------------------------------------------------- +// +// Set the thumb position +// +//------------------------------------------------------------------------- +void nsScrollbar::SetPosition(PRUint32 aPos) +{ + ::SetScrollPos(mWnd, SB_CTL, NS_TO_INT_ROUND(aPos / mScaleFactor), TRUE); +} + + +//------------------------------------------------------------------------- +// +// Get the current thumb position. +// +//------------------------------------------------------------------------- +PRUint32 nsScrollbar::GetPosition() +{ + return (PRUint32)NS_TO_INT_ROUND(::GetScrollPos(mWnd, SB_CTL) * mScaleFactor); +} + + +//------------------------------------------------------------------------- +// +// Set the thumb size +// +//------------------------------------------------------------------------- +void nsScrollbar::SetThumbSize(PRUint32 aSize) +{ + if (mWnd) { + SCROLLINFO si; + si.cbSize = sizeof(SCROLLINFO); + si.fMask = SIF_PAGE; + si.nPage = NS_TO_INT_ROUND(aSize / mScaleFactor); + ::SetScrollInfo(mWnd, SB_CTL, &si, TRUE); + } +} + + +//------------------------------------------------------------------------- +// +// Get the thumb size +// +//------------------------------------------------------------------------- +PRUint32 nsScrollbar::GetThumbSize() +{ + if (mWnd) { + SCROLLINFO si; + si.cbSize = sizeof(SCROLLINFO); + si.fMask = SIF_PAGE; + VERIFY(::GetScrollInfo(mWnd, SB_CTL, &si)); + return (PRUint32)NS_TO_INT_ROUND(si.nPage * mScaleFactor); + } + + return 0; +} + + +//------------------------------------------------------------------------- +// +// Set the line increment for this scrollbar +// +//------------------------------------------------------------------------- +void nsScrollbar::SetLineIncrement(PRUint32 aSize) +{ + mLineIncrement = NS_TO_INT_ROUND(aSize / mScaleFactor); +} + + +//------------------------------------------------------------------------- +// +// Get the line increment for this scrollbar +// +//------------------------------------------------------------------------- +PRUint32 nsScrollbar::GetLineIncrement() +{ + return (PRUint32)NS_TO_INT_ROUND(mLineIncrement * mScaleFactor); +} + + +//------------------------------------------------------------------------- +// +// Set all scrolling parameters +// +//------------------------------------------------------------------------- +void nsScrollbar::SetParameters(PRUint32 aMaxRange, PRUint32 aThumbSize, + PRUint32 aPosition, PRUint32 aLineIncrement) +{ + if (aMaxRange > 32767) + mScaleFactor = aMaxRange / 32767.0; + + if (mWnd) { + SCROLLINFO si; + si.cbSize = sizeof(SCROLLINFO); + si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; + si.nPage = NS_TO_INT_ROUND(aThumbSize / mScaleFactor); + si.nPos = NS_TO_INT_ROUND(aPosition / mScaleFactor); + si.nMin = 0; + si.nMax = NS_TO_INT_ROUND(aMaxRange / mScaleFactor); + ::SetScrollInfo(mWnd, SB_CTL, &si, TRUE); + } + + mLineIncrement = NS_TO_INT_ROUND(aLineIncrement / mScaleFactor); +} + + +//------------------------------------------------------------------------- +// +// paint message. Don't send the paint out +// +//------------------------------------------------------------------------- +PRBool nsScrollbar::OnPaint() +{ + return PR_FALSE; +} + + +PRBool nsScrollbar::OnResize(nsRect &aWindowRect) +{ + return PR_FALSE; +} + + +//------------------------------------------------------------------------- +// +// Deal with scrollbar messages (actually implemented only in nsScrollbar) +// +//------------------------------------------------------------------------- +PRBool nsScrollbar::OnScroll(UINT scrollCode, int cPos) +{ + PRBool result = PR_TRUE; + int newPosition; + + switch (scrollCode) { + + // scroll one line right or down + // SB_LINERIGHT and SB_LINEDOWN are actually the same value + //case SB_LINERIGHT: + case SB_LINEDOWN: + { + newPosition = ::GetScrollPos(mWnd, SB_CTL) + mLineIncrement; + PRUint32 max = GetMaxRange() - GetThumbSize(); + if (newPosition > (int)max) + newPosition = (int)max; + + // if an event callback is registered, give it the chance + // to change the increment + if (mEventCallback) { + nsScrollbarEvent event; + event.message = NS_SCROLLBAR_LINE_NEXT; + event.widget = (nsWindow*)this; + DWORD pos = ::GetMessagePos(); + POINT cpos; + cpos.x = LOWORD(pos); + cpos.y = HIWORD(pos); + ::ScreenToClient(mWnd, &cpos); + event.point.x = cpos.x; + event.point.y = cpos.y; + event.time = ::GetMessageTime(); + event.position = (PRUint32)NS_TO_INT_ROUND(newPosition * mScaleFactor); + + result = ConvertStatus((*mEventCallback)(&event)); + newPosition = NS_TO_INT_ROUND(event.position / mScaleFactor); + } + + ::SetScrollPos(mWnd, SB_CTL, newPosition, TRUE); + + break; + } + + + // scroll one line left or up + //case SB_LINELEFT: + case SB_LINEUP: + { + newPosition = ::GetScrollPos(mWnd, SB_CTL) - mLineIncrement; + if (newPosition < 0) + newPosition = 0; + + // if an event callback is registered, give it the chance + // to change the decrement + if (mEventCallback) { + nsScrollbarEvent event; + event.message = NS_SCROLLBAR_LINE_PREV; + event.widget = (nsWindow*)this; + DWORD pos = ::GetMessagePos(); + POINT cpos; + cpos.x = LOWORD(pos); + cpos.y = HIWORD(pos); + ::ScreenToClient(mWnd, &cpos); + event.point.x = cpos.x; + event.point.y = cpos.y; + event.time = ::GetMessageTime(); + event.position = (PRUint32)NS_TO_INT_ROUND(newPosition * mScaleFactor); + + result = ConvertStatus((*mEventCallback)(&event)); + newPosition = NS_TO_INT_ROUND(event.position / mScaleFactor); + } + + ::SetScrollPos(mWnd, SB_CTL, newPosition, TRUE); + + break; + } + + // Scrolls one page right or down + // case SB_PAGERIGHT: + case SB_PAGEDOWN: + { + SCROLLINFO si; + si.cbSize = sizeof(SCROLLINFO); + si.fMask = SIF_PAGE; + VERIFY(::GetScrollInfo(mWnd, SB_CTL, &si)); + + newPosition = ::GetScrollPos(mWnd, SB_CTL) + si.nPage; + PRUint32 max = GetMaxRange() - GetThumbSize(); + if (newPosition > (int)max) + newPosition = (int)max; + + // if an event callback is registered, give it the chance + // to change the increment + if (mEventCallback) { + nsScrollbarEvent event; + event.message = NS_SCROLLBAR_PAGE_NEXT; + event.widget = (nsWindow*)this; + DWORD pos = ::GetMessagePos(); + POINT cpos; + cpos.x = LOWORD(pos); + cpos.y = HIWORD(pos); + ::ScreenToClient(mWnd, &cpos); + event.point.x = cpos.x; + event.point.y = cpos.y; + event.time = ::GetMessageTime(); + event.position = (PRUint32)NS_TO_INT_ROUND(newPosition * mScaleFactor);; + + + result = ConvertStatus((*mEventCallback)(&event)); + newPosition = NS_TO_INT_ROUND(event.position / mScaleFactor); + } + + ::SetScrollPos(mWnd, SB_CTL, newPosition, TRUE); + + break; + } + + // Scrolls one page left or up. + //case SB_PAGELEFT: + case SB_PAGEUP: + { + SCROLLINFO si; + si.cbSize = sizeof(SCROLLINFO); + si.fMask = SIF_PAGE; + VERIFY(::GetScrollInfo(mWnd, SB_CTL, &si)); + + newPosition = ::GetScrollPos(mWnd, SB_CTL) - si.nPage; + if (newPosition < 0) + newPosition = 0; + + // if an event callback is registered, give it the chance + // to change the increment + if (mEventCallback) { + nsScrollbarEvent event; + event.message = NS_SCROLLBAR_PAGE_PREV; + event.widget = (nsWindow*)this; + DWORD pos = ::GetMessagePos(); + POINT cpos; + cpos.x = LOWORD(pos); + cpos.y = HIWORD(pos); + ::ScreenToClient(mWnd, &cpos); + event.point.x = cpos.x; + event.point.y = cpos.y; + event.time = ::GetMessageTime(); + event.position = (PRUint32)NS_TO_INT_ROUND(newPosition * mScaleFactor); + + result = ConvertStatus((*mEventCallback)(&event)); + newPosition = NS_TO_INT_ROUND(event.position / mScaleFactor); + } + + ::SetScrollPos(mWnd, SB_CTL, newPosition - 10, TRUE); + + break; + } + + // Scrolls to the absolute position. The current position is specified by + // the cPos parameter. + case SB_THUMBPOSITION: + case SB_THUMBTRACK: + { + newPosition = cPos; + + // if an event callback is registered, give it the chance + // to change the increment + if (mEventCallback) { + nsScrollbarEvent event; + event.message = NS_SCROLLBAR_POS; + event.widget = (nsWindow*)this; + DWORD pos = ::GetMessagePos(); + POINT cpos; + cpos.x = LOWORD(pos); + cpos.y = HIWORD(pos); + ::ScreenToClient(mWnd, &cpos); + event.point.x = cpos.x; + event.point.y = cpos.y; + event.time = ::GetMessageTime(); + event.position = (PRUint32)NS_TO_INT_ROUND(newPosition * mScaleFactor); + + result = ConvertStatus((*mEventCallback)(&event)); + newPosition = NS_TO_INT_ROUND(event.position * mScaleFactor); + } + + ::SetScrollPos(mWnd, SB_CTL, newPosition, TRUE); + + break; + } + } + + return result; +} + + +//------------------------------------------------------------------------- +// +// return the window class name and initialize the class if needed +// +//------------------------------------------------------------------------- +LPCTSTR nsScrollbar::WindowClass() +{ + return "SCROLLBAR"; +} + + +//------------------------------------------------------------------------- +// +// return window styles +// +//------------------------------------------------------------------------- +DWORD nsScrollbar::WindowStyle() +{ + return mPositionFlag | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS; +} + + +//------------------------------------------------------------------------- +// +// return window extended styles +// +//------------------------------------------------------------------------- +DWORD nsScrollbar::WindowExStyle() +{ + return 0; +} + + diff --git a/mozilla/widget/src/windows/nsScrollbar.h b/mozilla/widget/src/windows/nsScrollbar.h new file mode 100644 index 00000000000..582a01771ce --- /dev/null +++ b/mozilla/widget/src/windows/nsScrollbar.h @@ -0,0 +1,73 @@ +/* -*- 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. + */ + +#ifndef nsScrollbar_h__ +#define nsScrollbar_h__ + +#include "nsdefs.h" +#include "nsWindow.h" +#include "nsSwitchToUIThread.h" + +#include "nsIScrollbar.h" + +class nsScrollbar : public nsWindow, + public nsIScrollbar +{ + +public: + nsScrollbar(nsISupports *aOuter, PRBool aIsVertical); + virtual ~nsScrollbar(); + + // nsISupports. Forward to the nsObject base class + BASE_SUPPORT + + virtual nsresult QueryObject(const nsIID& aIID, void** aInstancePtr); + + // nsIWidget interface + BASE_IWIDGET_IMPL + + + // nsIScrollbar part + virtual void SetMaxRange(PRUint32 aEndRange); + virtual PRUint32 GetMaxRange(); + virtual void SetPosition(PRUint32 aPos); + virtual PRUint32 GetPosition(); + virtual void SetThumbSize(PRUint32 aSize); + virtual PRUint32 GetThumbSize(); + virtual void SetLineIncrement(PRUint32 aSize); + virtual PRUint32 GetLineIncrement(); + virtual void SetParameters(PRUint32 aMaxRange, PRUint32 aThumbSize, + PRUint32 aPosition, PRUint32 aLineIncrement); + + virtual PRBool OnPaint(); + virtual PRBool OnScroll(UINT scrollCode, int cPos); + virtual PRBool OnResize(nsRect &aWindowRect); + +protected: + + virtual LPCTSTR WindowClass(); + virtual DWORD WindowStyle(); + virtual DWORD WindowExStyle(); + +private: + DWORD mPositionFlag; + int mLineIncrement; + double mScaleFactor; +}; + +#endif // nsButton_h__ diff --git a/mozilla/widget/src/windows/nsStringUtil.h b/mozilla/widget/src/windows/nsStringUtil.h new file mode 100644 index 00000000000..4925500ba78 --- /dev/null +++ b/mozilla/widget/src/windows/nsStringUtil.h @@ -0,0 +1,79 @@ +/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */ +/* + * 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. + */ + +// Convience macros for converting nsString's to chars + +// creating temporary char[] bufs. + +#ifndef NS_STR_UTIL_H +#define NS_STR_UTIL_H + +// nsString to temporary char[] macro + +// Convience MACROS to convert an nsString to a char * which use a +// static char array if possible to reduce memory fragmentation, +// otherwise they allocate a char[] which must be freed. +// REMEMBER to always use the NS_FREE_STR_BUF after using the +// NS_ALLOC_STR_BUF. You can not nest NS_ALLOC_STR_BUF's. + +#define NS_ALLOC_STR_BUF(varName, strName, tempSize) \ + static const int _ns_kSmallBufferSize = tempSize; \ + char* varName = 0; \ + int _ns_smallBufUsed = 0; \ + char _ns_smallBuffer[_ns_kSmallBufferSize]; \ + if (strName.Length() < (_ns_kSmallBufferSize - 1)) { \ + strName.ToCString(_ns_smallBuffer, _ns_kSmallBufferSize); \ + _ns_smallBuffer[_ns_kSmallBufferSize - 1] = '\0'; \ + _ns_smallBufUsed = 1; \ + varName = _ns_smallBuffer; \ + } \ + else { \ + varName = strName.ToNewCString(); \ + } + +#define NS_FREE_STR_BUF(varName) \ + if (! _ns_smallBufUsed) \ + delete varName; + +// Create temporary char[] macro +// +// Create a temporary buffer for storing chars. +// If the actual size is > size then the buffer +// is allocated from the heap, otherwise the buffer +// is a stack variable. REMEMBER: use NS_FREE_BUF +// when finished with the buffer allocated, and do +// NOT nest INSERT_BUF'S. + +#define NS_ALLOC_CHAR_BUF(aBuf, aSize, aActualSize) \ + char *aBuf; \ + int _ns_smallBufUsed = 0; \ + static const int _ns_kSmallBufferSize = aSize; \ + if (aActualSize < _ns_kSmallBufferSize) { \ + char _ns_smallBuffer[_ns_kSmallBufferSize]; \ + aBuf = _ns_smallBuffer; \ + _ns_smallBufUsed = 1; \ + } \ + else { \ + aBuf = new char[aActualSize]; \ + } + +#define NS_FREE_CHAR_BUF(aBuf) \ +if (! _ns_smallBufUsed) \ + delete aBuf; + + +#endif // NSStringUtil \ No newline at end of file diff --git a/mozilla/widget/src/windows/nsSwitchToUIThread.h b/mozilla/widget/src/windows/nsSwitchToUIThread.h new file mode 100644 index 00000000000..e66784e055b --- /dev/null +++ b/mozilla/widget/src/windows/nsSwitchToUIThread.h @@ -0,0 +1,54 @@ +/* -*- 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. + */ + +#ifndef SWITCHTOUITHREAD_H +#define SWITCHTOUITHREAD_H + + +// foreward declaration +struct MethodInfo; + +class nsSwitchToUIThread { + +public: + virtual BOOL CallMethod(MethodInfo *info) = 0; + +}; + +// +// Structure used for passing the information necessary for synchronously +// invoking a method on the GUI thread... +// +struct MethodInfo { + nsSwitchToUIThread* target; + UINT methodId; + int nArgs; + DWORD* args; + + MethodInfo(nsSwitchToUIThread *obj, UINT id, int numArgs=0, DWORD *arguments = 0) { + target = obj; + methodId = id; + nArgs = numArgs; + args = arguments; + } + + BOOL Invoke() { return target->CallMethod(this); } +}; + +#endif // TOUITHRD_H + diff --git a/mozilla/widget/src/windows/nsTextAreaWidget.cpp b/mozilla/widget/src/windows/nsTextAreaWidget.cpp new file mode 100644 index 00000000000..e4265e439f2 --- /dev/null +++ b/mozilla/widget/src/windows/nsTextAreaWidget.cpp @@ -0,0 +1,159 @@ +/* -*- 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 "nsTextAreaWidget.h" +#include "nsToolkit.h" +#include "nsColor.h" +#include "nsGUIEvent.h" +#include "nsString.h" +#include + +PRUint32 nsTextAreaWidget::GetText(nsString& aTextBuffer, PRUint32 aBufferSize) { + return(nsTextHelper::GetText(aTextBuffer, aBufferSize)); +} + +PRUint32 nsTextAreaWidget::SetText(const nsString &aText) { + return(nsTextHelper::SetText(aText)); +} + +PRUint32 nsTextAreaWidget::InsertText(const nsString &aText, PRUint32 aStartPos, PRUint32 aEndPos) { + return(nsTextHelper::InsertText(aText, aStartPos, aEndPos)); +} + +void nsTextAreaWidget::RemoveText() { + nsTextHelper::RemoveText(); +} + +void nsTextAreaWidget::SetPassword(PRBool aIsPassword) +{ + nsTextHelper::SetPassword(aIsPassword); +} + +PRBool nsTextAreaWidget::SetReadOnly(PRBool aReadOnlyFlag) +{ + return(nsTextHelper::SetReadOnly(aReadOnlyFlag)); +} + +void nsTextAreaWidget::SetSelection(PRUint32 aStartSel, PRUint32 aEndSel) +{ +} + +void nsTextAreaWidget::GetSelection(PRUint32 *aStartSel, PRUint32 *aEndSel) +{ +} + +void nsTextAreaWidget::SetCaretPosition(PRUint32 aPosition) +{ +} + +PRUint32 nsTextAreaWidget::GetCaretPosition() +{ + return(0); +} + +//------------------------------------------------------------------------- +// +// nsTextAreaWidget constructor +// +//------------------------------------------------------------------------- +nsTextAreaWidget::nsTextAreaWidget(nsISupports *aOuter) : nsTextHelper(aOuter) +{ + nsTextHelper::mBackground = NS_RGB(124, 124, 124); +} + +//------------------------------------------------------------------------- +// +// nsTextAreaWidget destructor +// +//------------------------------------------------------------------------- +nsTextAreaWidget::~nsTextAreaWidget() +{ +} + + +//------------------------------------------------------------------------- +// +// Query interface implementation +// +//------------------------------------------------------------------------- +nsresult nsTextAreaWidget::QueryObject(const nsIID& aIID, void** aInstancePtr) +{ + nsresult result = nsWindow::QueryObject(aIID, aInstancePtr); + + static NS_DEFINE_IID(kInsTextAreaWidgetIID, NS_ITEXTAREAWIDGET_IID); + if (result == NS_NOINTERFACE && aIID.Equals(kInsTextAreaWidgetIID)) { + *aInstancePtr = (void*) ((nsITextAreaWidget*)this); + AddRef(); + result = NS_OK; + } + + return result; +} + +//------------------------------------------------------------------------- +// +// paint message. Don't send the paint out +// +//------------------------------------------------------------------------- +PRBool nsTextAreaWidget::OnPaint() +{ + return PR_FALSE; +} + +PRBool nsTextAreaWidget::OnResize(nsRect &aWindowRect) +{ + return PR_FALSE; +} + + +//------------------------------------------------------------------------- +// +// return the window class name and initialize the class if needed +// +//------------------------------------------------------------------------- +LPCTSTR nsTextAreaWidget::WindowClass() +{ + return(nsTextHelper::WindowClass()); +} + + +//------------------------------------------------------------------------- +// +// return window styles +// +//------------------------------------------------------------------------- +DWORD nsTextAreaWidget::WindowStyle() +{ + DWORD style = nsTextHelper::WindowStyle(); + style = style | ES_MULTILINE | ES_WANTRETURN | ES_AUTOVSCROLL; + return style; +} + + +//------------------------------------------------------------------------- +// +// return window extended styles +// +//------------------------------------------------------------------------- + +DWORD nsTextAreaWidget::WindowExStyle() +{ + return WS_EX_CLIENTEDGE; +} + + + diff --git a/mozilla/widget/src/windows/nsTextAreaWidget.h b/mozilla/widget/src/windows/nsTextAreaWidget.h new file mode 100644 index 00000000000..1ef66deec56 --- /dev/null +++ b/mozilla/widget/src/windows/nsTextAreaWidget.h @@ -0,0 +1,67 @@ +/* -*- 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. + */ + +#ifndef nsTextAreaWidget_h__ +#define nsTextAreaWidget_h__ + +#include "nsdefs.h" +#include "nsWindow.h" +#include "nsSwitchToUIThread.h" +#include "nsTextHelper.h" + +#include "nsITextAreaWidget.h" + +class nsTextAreaWidget : public nsTextHelper, + public nsITextAreaWidget +{ + +public: + nsTextAreaWidget(nsISupports *aOuter); + virtual ~nsTextAreaWidget(); + + // nsISupports. Forward to the nsObject base class + BASE_SUPPORT + + virtual nsresult QueryObject(const nsIID& aIID, void** aInstancePtr); + PRBool OnPaint(); + virtual PRBool OnResize(nsRect &aWindowRect); + + // nsIWidget interface + BASE_IWIDGET_IMPL + + // nsITextWidget part + virtual PRUint32 SetText(const nsString &aText); + virtual PRUint32 GetText(nsString& aTextBuffer, PRUint32 aBufferSize); + virtual PRUint32 InsertText(const nsString &aText, PRUint32 aStartPos, PRUint32 aEndPos); + virtual void RemoveText(); + virtual void SetPassword(PRBool aIsPassword); + virtual PRBool SetReadOnly(PRBool aReadOnlyFlag); + virtual void SetSelection(PRUint32 aStartSel, PRUint32 aEndSel); + virtual void GetSelection(PRUint32 *aStartSel, PRUint32 *aEndSel); + virtual void SetCaretPosition(PRUint32 aPosition); + virtual PRUint32 GetCaretPosition(); + +protected: + + virtual LPCTSTR WindowClass(); + virtual DWORD WindowStyle(); + virtual DWORD WindowExStyle(); + +}; + +#endif // nsTextAreaWidget_h__ diff --git a/mozilla/widget/src/windows/nsTextHelper.cpp b/mozilla/widget/src/windows/nsTextHelper.cpp new file mode 100644 index 00000000000..6b08f610029 --- /dev/null +++ b/mozilla/widget/src/windows/nsTextHelper.cpp @@ -0,0 +1,151 @@ +/* -*- 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 "nsTextHelper.h" +#include "nsToolkit.h" +#include "nsColor.h" +#include "nsGUIEvent.h" +#include "nsString.h" +#include "nsStringUtil.h" +#include + + +PRUint32 nsTextHelper::GetText(nsString& aTextBuffer, PRUint32 aBufferSize) { + + int length = GetWindowTextLength(mWnd); + int bufLength = length + 1; + NS_ALLOC_CHAR_BUF(buf, 512, bufLength); + int charsCopied = GetWindowText(mWnd, buf, bufLength); + aTextBuffer.SetLength(0); + aTextBuffer.Append(buf); + NS_FREE_CHAR_BUF(buf); + + return(0); +} + +PRUint32 nsTextHelper::SetText(const nsString &aText) +{ + NS_ALLOC_STR_BUF(buf, aText, 512); + SetWindowText(mWnd, buf); + NS_FREE_STR_BUF(buf); + return(aText.Length()); +} + +PRUint32 nsTextHelper::InsertText(const nsString &aText, PRUint32 aStartPos, PRUint32 aEndPos) +{ + // NOT IMPLEMENTED + return(0); +} + +void nsTextHelper::RemoveText() +{ + SetWindowText(mWnd, ""); +} + +void nsTextHelper::SetPassword(PRBool aIsPassword) +{ + mIsPassword = aIsPassword; +} + +PRBool nsTextHelper::SetReadOnly(PRBool aReadOnlyFlag) +{ + PRBool oldSetting = mIsReadOnly; + mIsReadOnly = aReadOnlyFlag; + return(oldSetting); +} + +void nsTextHelper::SetSelection(PRUint32 aStartSel, PRUint32 aEndSel) +{ + ::SendMessage(mWnd, EM_SETSEL, (WPARAM) (INT)aStartSel, (INT) (LPDWORD)aEndSel); +} + + +void nsTextHelper::GetSelection(PRUint32 *aStartSel, PRUint32 *aEndSel) +{ + ::SendMessage(mWnd, EM_GETSEL, (WPARAM) (LPDWORD)aStartSel, (LPARAM) (LPDWORD)aEndSel); +} + +void nsTextHelper::SetCaretPosition(PRUint32 aPosition) +{ +} + +PRUint32 nsTextHelper::GetCaretPosition() +{ + return(0); +} + +//------------------------------------------------------------------------- +// +// nsTextHelper constructor +// +//------------------------------------------------------------------------- + +nsTextHelper::nsTextHelper(nsISupports *aOuter) : nsWindow(aOuter) +{ + mIsReadOnly = PR_FALSE; + mIsPassword = PR_FALSE; +} + +//------------------------------------------------------------------------- +// +// nsTextHelper destructor +// +//------------------------------------------------------------------------- +nsTextHelper::~nsTextHelper() +{ +} + +//------------------------------------------------------------------------- +// +// return the window class name and initialize the class if needed +// +//------------------------------------------------------------------------- +LPCTSTR nsTextHelper::WindowClass() +{ + return("EDIT"); +} + +//------------------------------------------------------------------------- +// +// return window styles +// +//------------------------------------------------------------------------- +DWORD nsTextHelper::WindowStyle() +{ + DWORD style = ES_AUTOHSCROLL | WS_BORDER | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | ES_NOHIDESEL; + if (mIsPassword) + style = style | ES_PASSWORD; + + if (mIsReadOnly) + style = style | ES_READONLY; + + return style; +} + +//------------------------------------------------------------------------- +// +// return window extended styles +// +//------------------------------------------------------------------------- + +DWORD nsTextHelper::WindowExStyle() +{ + return 0; +} + + diff --git a/mozilla/widget/src/windows/nsTextHelper.h b/mozilla/widget/src/windows/nsTextHelper.h new file mode 100644 index 00000000000..32862a03df2 --- /dev/null +++ b/mozilla/widget/src/windows/nsTextHelper.h @@ -0,0 +1,54 @@ +/* -*- 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. + */ +#ifndef nsTextHelper_h__ +#define nsTextHelper_h__ + +#include "nsdefs.h" +#include "nsITextWidget.h" +#include "nsWindow.h" + +class nsTextHelper : public nsWindow, public nsITextWidget +{ + +public: + nsTextHelper(nsISupports *aOuter); + virtual ~nsTextHelper(); + + virtual PRUint32 GetText(nsString& aTextBuffer, PRUint32 aBufferSize); + virtual PRUint32 SetText(const nsString &aText); + virtual PRUint32 InsertText(const nsString &aText, PRUint32 aStartPos, PRUint32 aEndPos); + virtual void RemoveText(); + virtual void SetPassword(PRBool aIsPassword); + virtual PRBool SetReadOnly(PRBool aReadOnlyFlag); + virtual void SetSelection(PRUint32 aStartSel, PRUint32 aEndSel); + virtual void GetSelection(PRUint32 *aStartSel, PRUint32 *aEndSel); + virtual void SetCaretPosition(PRUint32 aPosition); + virtual PRUint32 GetCaretPosition(); + virtual LPCTSTR WindowClass(); + virtual DWORD WindowStyle(); + +protected: + + PRBool mIsPassword; + PRBool mIsReadOnly; + + virtual DWORD WindowExStyle(); + +}; + +#endif // nsTextHelper_h__ diff --git a/mozilla/widget/src/windows/nsTextWidget.cpp b/mozilla/widget/src/windows/nsTextWidget.cpp new file mode 100644 index 00000000000..0945c6232fa --- /dev/null +++ b/mozilla/widget/src/windows/nsTextWidget.cpp @@ -0,0 +1,132 @@ +/* -*- 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 "nsTextWidget.h" +#include "nsToolkit.h" +#include "nsColor.h" +#include "nsGUIEvent.h" +#include "nsString.h" +#include + + +void nsTextWidget::SetSelection(PRUint32 aStartSel, PRUint32 aEndSel) +{ +} + +void nsTextWidget::GetSelection(PRUint32 *aStartSel, PRUint32 *aEndSel) +{ +} + +void nsTextWidget::SetCaretPosition(PRUint32 aPosition) +{ +} + +PRUint32 nsTextWidget::GetCaretPosition() +{ + return(0); +} + +//------------------------------------------------------------------------- +// +// nsTextWidget constructor +// +//------------------------------------------------------------------------- +nsTextWidget::nsTextWidget(nsISupports *aOuter) : nsTextHelper(aOuter) +{ + mBackground = NS_RGB(124, 124, 124); +} + + +//------------------------------------------------------------------------- +// +// nsTextWidget destructor +// +//------------------------------------------------------------------------- +nsTextWidget::~nsTextWidget() +{ +} + + +//------------------------------------------------------------------------- +// +// Query interface implementation +// +//------------------------------------------------------------------------- +nsresult nsTextWidget::QueryObject(const nsIID& aIID, void** aInstancePtr) +{ + nsresult result = nsWindow::QueryObject(aIID, aInstancePtr); + + static NS_DEFINE_IID(kInsTextWidgetIID, NS_ITEXTWIDGET_IID); + if (result == NS_NOINTERFACE && aIID.Equals(kInsTextWidgetIID)) { + *aInstancePtr = (void*) ((nsITextWidget*)this); + AddRef(); + result = NS_OK; + } + + return result; +} + +//------------------------------------------------------------------------- +// +// paint message. Don't send the paint out +// +//------------------------------------------------------------------------- +PRBool nsTextWidget::OnPaint() +{ + return PR_FALSE; +} + + +PRBool nsTextWidget::OnResize(nsRect &aWindowRect) +{ + return PR_FALSE; +} + +//------------------------------------------------------------------------- +// +// return the window class name and initialize the class if needed +// +//------------------------------------------------------------------------- +LPCTSTR nsTextWidget::WindowClass() +{ + return(nsTextHelper::WindowClass()); +} + +//------------------------------------------------------------------------- +// +// return window styles +// +//------------------------------------------------------------------------- +DWORD nsTextWidget::WindowStyle() +{ + return(nsTextHelper::WindowStyle()); +} + + +//------------------------------------------------------------------------- +// +// return window extended styles +// +//------------------------------------------------------------------------- + +DWORD nsTextWidget::WindowExStyle() +{ + return WS_EX_CLIENTEDGE; +} + + diff --git a/mozilla/widget/src/windows/nsTextWidget.h b/mozilla/widget/src/windows/nsTextWidget.h new file mode 100644 index 00000000000..783567cf555 --- /dev/null +++ b/mozilla/widget/src/windows/nsTextWidget.h @@ -0,0 +1,58 @@ +/* -*- 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. + */ + +#ifndef nsTextWidget_h__ +#define nsTextWidget_h__ + +#include "nsdefs.h" +#include "nsWindow.h" +#include "nsSwitchToUIThread.h" +#include "nsTextHelper.h" + +#include "nsITextWidget.h" + +class nsTextWidget : public nsTextHelper +{ + +public: + nsTextWidget(nsISupports *aOuter); + virtual ~nsTextWidget(); + + // nsISupports. Forward to the nsObject base class + BASE_SUPPORT + + virtual nsresult QueryObject(const nsIID& aIID, void** aInstancePtr); + PRBool nsTextWidget::OnPaint(); + virtual PRBool OnResize(nsRect &aWindowRect); + + // nsIWidget interface + BASE_IWIDGET_IMPL + + // nsITextWidget part + virtual void SetSelection(PRUint32 aStartSel, PRUint32 aEndSel); + virtual void GetSelection(PRUint32 *aStartSel, PRUint32 *aEndSel); + virtual void SetCaretPosition(PRUint32 aPosition); + virtual PRUint32 GetCaretPosition(); + +protected: + virtual LPCTSTR WindowClass(); + virtual DWORD WindowStyle(); + virtual DWORD WindowExStyle(); +}; + +#endif // nsTextWidget_h__ diff --git a/mozilla/widget/src/windows/nsToolkit.cpp b/mozilla/widget/src/windows/nsToolkit.cpp new file mode 100644 index 00000000000..66015738c89 --- /dev/null +++ b/mozilla/widget/src/windows/nsToolkit.cpp @@ -0,0 +1,359 @@ +/* -*- 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 "nsToolkit.h" +#include "nsWindow.h" +#include "prmon.h" +#include "prtime.h" +#include "nsGUIEvent.h" + +HINSTANCE nsToolkit::mDllInstance = 0; + +nsWindow *MouseTrailer::mHoldMouse; +MouseTrailer *MouseTrailer::theMouseTrailer; + +// +// Dll entry point. Keep the dll instance +// +BOOL APIENTRY DllMain( HINSTANCE hModule, + DWORD reason, + LPVOID lpReserved ) +{ + switch( reason ) { + case DLL_PROCESS_ATTACH: + nsToolkit::mDllInstance = hModule; + + // + // register the internal window class + // + WNDCLASS wc; + + wc.style = CS_GLOBALCLASS; + wc.lpfnWndProc = nsToolkit::WindowProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = nsToolkit::mDllInstance; + wc.hIcon = NULL; + wc.hCursor = NULL; + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = "nsToolkitClass"; + + VERIFY(::RegisterClass(&wc)); + + break; + + case DLL_THREAD_ATTACH: + break; + + case DLL_THREAD_DETACH: + break; + + case DLL_PROCESS_DETACH: + //VERIFY(::UnregisterClass("nsToolkitClass", nsToolkit::mDllInstance)); + ::UnregisterClass("nsToolkitClass", nsToolkit::mDllInstance); + break; + + } + + return TRUE; +} + + +// +// main for the message pump thread +// +PRBool gThreadState = PR_FALSE; + +struct ThreadInitInfo { + PRMonitor *monitor; + nsToolkit *toolkit; +}; + +void RunPump(void* arg) +{ + ThreadInitInfo *info = (ThreadInitInfo*)arg; + ::PR_EnterMonitor(info->monitor); + + // do registration and creation in this thread + info->toolkit->CreateInternalWindow(PR_GetCurrentThread()); + + gThreadState = PR_TRUE; + + ::PR_Notify(info->monitor); + ::PR_ExitMonitor(info->monitor); + + delete info; + + // Process messages + MSG msg; + while (GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + +//------------------------------------------------------------------------- +// +// constructor +// +//------------------------------------------------------------------------- +nsToolkit::nsToolkit() +{ + mGuiThread = NULL; + mDispatchWnd = 0; + NS_INIT_REFCNT(); +} + + +//------------------------------------------------------------------------- +// +// destructor +// +//------------------------------------------------------------------------- +nsToolkit::~nsToolkit() +{ + NS_PRECONDITION(::IsWindow(mDispatchWnd), "Invalid window handle"); + + // Destroy the Dispatch Window + ::DestroyWindow(mDispatchWnd); + mDispatchWnd = NULL; +} + + +//------------------------------------------------------------------------- +// +// The evil triad in a single shot macro +// +//------------------------------------------------------------------------- +NS_IMPL_ISUPPORTS(nsToolkit, NS_ITOOLKIT_IID) + + +//------------------------------------------------------------------------- +// +// Register the window class for the internal window and create the window +// +//------------------------------------------------------------------------- +void nsToolkit::CreateInternalWindow(PRThread *aThread) +{ + + NS_PRECONDITION(aThread, "null thread"); + mGuiThread = aThread; + + // + // create the internal window + // + mDispatchWnd = ::CreateWindow("nsToolkitClass", + "NetscapeDispatchWnd", + WS_DISABLED, + -50, -50, + 10, 10, + NULL, + NULL, + nsToolkit::mDllInstance, + NULL); + VERIFY(mDispatchWnd); +} + + +//------------------------------------------------------------------------- +// +// Create a new thread and run the message pump in there +// +//------------------------------------------------------------------------- +void nsToolkit::CreateUIThread() +{ + PRMonitor *monitor = ::PR_NewMonitor(); + + ::PR_EnterMonitor(monitor); + + ThreadInitInfo *ti = new ThreadInitInfo(); + ti->monitor = monitor; + ti->toolkit = this; + + // create a gui thread + mGuiThread = ::PR_CreateThread(PR_SYSTEM_THREAD, + RunPump, + (void*)ti, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + + // wait for the gui thread to start + while(gThreadState == PR_FALSE) { + ::PR_Wait(monitor, PR_INTERVAL_NO_TIMEOUT); + } + + // at this point the thread is running + ::PR_ExitMonitor(monitor); + ::PR_DestroyMonitor(monitor); +} + + +//------------------------------------------------------------------------- +// +// +//------------------------------------------------------------------------- +void nsToolkit::Init(PRThread *aThread) +{ + // Store the thread ID of the thread containing the message pump. + // If no thread is provided create one + if (NULL != aThread) { + CreateInternalWindow(aThread); + } + else { + // create a thread where the message pump will run + CreateUIThread(); + } +} + + +//------------------------------------------------------------------------- +// +// nsToolkit WindowProc. Used to call methods on the "main GUI thread"... +// +//------------------------------------------------------------------------- +LRESULT CALLBACK nsToolkit::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, + LPARAM lParam) +{ + switch (msg) { + case WM_CALLMETHOD: + { + MethodInfo *info = (MethodInfo *)lParam; + return info->Invoke(); + } + } + + return ::DefWindowProc(hWnd, msg, wParam, lParam); +} + +//------------------------------------------------------------------------- +// +// +//------------------------------------------------------------------------- +MouseTrailer * MouseTrailer::GetMouseTrailer(DWORD aThreadID) { + if (nsnull == MouseTrailer::theMouseTrailer) { + MouseTrailer::theMouseTrailer = new MouseTrailer(); + } + return MouseTrailer::theMouseTrailer; + +} + +//------------------------------------------------------------------------- +// +// +//------------------------------------------------------------------------- +nsWindow * MouseTrailer::GetMouseTrailerWindow() { + return MouseTrailer::mHoldMouse; +} +//------------------------------------------------------------------------- +// +// +//------------------------------------------------------------------------- +void MouseTrailer::SetMouseTrailerWindow(nsWindow * aNSWin) { + MouseTrailer::mHoldMouse = aNSWin; +} + +//------------------------------------------------------------------------- +// +// +//------------------------------------------------------------------------- +MouseTrailer::MouseTrailer() +{ + mTimerId = 0; + mHoldMouse = NULL; +} + + +//------------------------------------------------------------------------- +// +// +//------------------------------------------------------------------------- +MouseTrailer::~MouseTrailer() +{ + DestroyTimer(); + if (mHoldMouse) { + NS_RELEASE(mHoldMouse); + } +} + + +//------------------------------------------------------------------------- +// +// +//------------------------------------------------------------------------- +UINT MouseTrailer::CreateTimer() +{ + if (!mTimerId) { + mTimerId = ::SetTimer(NULL, 0, 200, (TIMERPROC)MouseTrailer::TimerProc); + } + + return mTimerId; +} + + +//------------------------------------------------------------------------- +// +// +//------------------------------------------------------------------------- +void MouseTrailer::DestroyTimer() +{ + if (mTimerId) { + ::KillTimer(NULL, mTimerId); + mTimerId = 0; + } + +} + +#define TIMER_DEBUG 1 +//------------------------------------------------------------------------- +// +// +//------------------------------------------------------------------------- +void CALLBACK MouseTrailer::TimerProc(HWND hWnd, UINT msg, UINT event, DWORD time) +{ + if (MouseTrailer::mHoldMouse && ::IsWindow(MouseTrailer::mHoldMouse->GetWindowHandle())) { + + + POINT mp; + DWORD pos = ::GetMessagePos(); + mp.x = LOWORD(pos); + mp.y = HIWORD(pos); + + if (::WindowFromPoint(mp) != mHoldMouse->GetWindowHandle()) { + int64 time = PR_Now(); // time in milliseconds + ::ScreenToClient(mHoldMouse->GetWindowHandle(), &mp); + + //notify someone that a mouse exit happened + if (nsnull != MouseTrailer::mHoldMouse) { + MouseTrailer::mHoldMouse->DispatchMouseEvent(NS_MOUSE_EXIT); + } + + // we are out of this window and of any window, destroy timer + MouseTrailer::theMouseTrailer->DestroyTimer(); + MouseTrailer::mHoldMouse = NULL; + } + } else { + MouseTrailer::theMouseTrailer->DestroyTimer(); + MouseTrailer::mHoldMouse = NULL; + } + +} + + diff --git a/mozilla/widget/src/windows/nsToolkit.h b/mozilla/widget/src/windows/nsToolkit.h new file mode 100644 index 00000000000..09eec3c02da --- /dev/null +++ b/mozilla/widget/src/windows/nsToolkit.h @@ -0,0 +1,120 @@ +/* -*- 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. + */ + +#ifndef TOOLKIT_H +#define TOOLKIT_H + +#include "nsdefs.h" +#include "nsIToolkit.h" + +struct MethodInfo; + +// +// nsToolkit is a wrapper around the thread running the message pump +// +class nsToolkit : public nsIToolkit +{ + +public: + nsToolkit(); + + NS_DECL_ISUPPORTS + + virtual void Init(PRThread *aThread); + + + void CallMethod(MethodInfo *info); + + // Return whether the current thread is the application's Gui thread. + PRBool IsGuiThread(void) { return (PRBool)(mGuiThread == PR_GetCurrentThread());} + + PRThread* GetGuiThread(void) { return mGuiThread; } + HWND GetDispatchWindow(void) { return mDispatchWnd; } + + void CreateInternalWindow(PRThread *aThread); + +private: + ~nsToolkit(); + + void CreateUIThread(void); + +public: + // Window procedure for the internal window + static LRESULT CALLBACK WindowProc(HWND hWnd, + UINT Msg, + WPARAM WParam, + LPARAM lParam); + +protected: + // Handle of the window used to receive dispatch messages. + HWND mDispatchWnd; + // Thread Id of the "main" Gui thread. + PRThread *mGuiThread; + +public: + static HINSTANCE mDllInstance; +}; + +#define WM_CALLMETHOD (WM_USER+1) + +inline void nsToolkit::CallMethod(MethodInfo *info) +{ + NS_PRECONDITION(::IsWindow(mDispatchWnd), "Invalid window handle"); + ::SendMessage(mDispatchWnd, WM_CALLMETHOD, (WPARAM)0, (LPARAM)info); +} + +// +// MouseTrailer is used to make sure exit/enter mouse messages +// are always dispatched +// +class nsWindow; + +class MouseTrailer { + +public: + static MouseTrailer * GetMouseTrailer(DWORD aThreadID); + static nsWindow * GetMouseTrailerWindow(); + static void SetMouseTrailerWindow(nsWindow * aNSWin); + +private: + // Global nsToolkit Instance + static MouseTrailer* theMouseTrailer; + +public: + ~MouseTrailer(); + + UINT CreateTimer(); + void DestroyTimer(); + +private: + static void CALLBACK TimerProc(HWND hWnd, + UINT msg, + UINT event, + DWORD time); + + MouseTrailer(); + +private: + // global information for mouse enter/exit events + static nsWindow* mHoldMouse; + UINT mTimerId; + +}; + + +#endif // TOOLKIT_H diff --git a/mozilla/widget/src/windows/nsWidgetFactory.cpp b/mozilla/widget/src/windows/nsWidgetFactory.cpp new file mode 100644 index 00000000000..a00461fcb98 --- /dev/null +++ b/mozilla/widget/src/windows/nsWidgetFactory.cpp @@ -0,0 +1,225 @@ +/* -*- Mode: C++; tab-width: 4; 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 "nsIFactory.h" +#include "nsISupports.h" +#include "nsdefs.h" +#include "nsWidgetsCID.h" + +#include "nsButton.h" +#include "nsCheckButton.h" +#include "nsComboBox.h" +#include "nsFileWidget.h" +#include "nsListBox.h" +#include "nsRadioButton.h" +#include "nsRadioGroup.h" +#include "nsScrollbar.h" +#include "nsTextAreaWidget.h" +#include "nsTextHelper.h" +#include "nsTextWidget.h" +#include "nsToolkit.h" +#include "nsWindow.h" + +static NS_DEFINE_IID(kCWindow, NS_WINDOW_CID); +static NS_DEFINE_IID(kCChild, NS_CHILD_CID); +static NS_DEFINE_IID(kCButton, NS_BUTTON_CID); +static NS_DEFINE_IID(kCCheckButton, NS_CHECKBUTTON_CID); +static NS_DEFINE_IID(kCCombobox, NS_COMBOBOX_CID); +static NS_DEFINE_IID(kCFileOpen, NS_FILEWIDGET_CID); +static NS_DEFINE_IID(kCListbox, NS_LISTBOX_CID); +static NS_DEFINE_IID(kCRadioButton, NS_RADIOBUTTON_CID); +static NS_DEFINE_IID(kCRadioGroup, NS_RADIOGROUP_CID); +static NS_DEFINE_IID(kCHorzScrollbar, NS_HORZSCROLLBAR_CID); +static NS_DEFINE_IID(kCVertScrollbar, NS_VERTSCROLLBAR_CID); +static NS_DEFINE_IID(kCTextArea, NS_TEXTAREA_CID); +static NS_DEFINE_IID(kCTextField, NS_TEXTFIELD_CID); + +static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); +static NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID); + +class nsWidgetFactory : public nsIFactory +{ +public: + // nsISupports methods + NS_IMETHOD QueryInterface(const nsIID &aIID, + void **aResult); + NS_IMETHOD_(nsrefcnt) AddRef(void); + NS_IMETHOD_(nsrefcnt) Release(void); + + // nsIFactory methods + NS_IMETHOD CreateInstance(nsISupports *aOuter, + const nsIID &aIID, + void **aResult); + + NS_IMETHOD LockFactory(PRBool aLock); + + nsWidgetFactory(const nsCID &aClass); + ~nsWidgetFactory(); + +private: + nsrefcnt mRefCnt; + nsCID mClassID; +}; + + + +nsWidgetFactory::nsWidgetFactory(const nsCID &aClass) +{ + mRefCnt = 0; + mClassID = aClass; +} + +nsWidgetFactory::~nsWidgetFactory() +{ + NS_ASSERTION(mRefCnt == 0, "Reference count not zero in destructor"); +} + +nsresult nsWidgetFactory::QueryInterface(const nsIID &aIID, + void **aResult) +{ + if (aResult == NULL) { + return NS_ERROR_NULL_POINTER; + } + + // Always NULL result, in case of failure + *aResult = NULL; + + if (aIID.Equals(kISupportsIID)) { + *aResult = (void *)(nsISupports*)this; + } else if (aIID.Equals(kIFactoryIID)) { + *aResult = (void *)(nsIFactory*)this; + } + + if (*aResult == NULL) { + return NS_NOINTERFACE; + } + + AddRef(); // Increase reference count for caller + return NS_OK; +} + +nsrefcnt nsWidgetFactory::AddRef() +{ + return ++mRefCnt; +} + +nsrefcnt nsWidgetFactory::Release() +{ + if (--mRefCnt == 0) { + delete this; + return 0; // Don't access mRefCnt after deleting! + } + return mRefCnt; +} + +nsresult nsWidgetFactory::CreateInstance(nsISupports *aOuter, + const nsIID &aIID, + void **aResult) +{ + if (aResult == NULL) { + return NS_ERROR_NULL_POINTER; + } + + *aResult = NULL; + + if (nsnull != aOuter && !aIID.Equals(kISupportsIID)) { + // aggregation with IID != nsISupports + return NS_ERROR_ILLEGAL_VALUE; + } + + nsObject *inst = nsnull; + if (mClassID.Equals(kCWindow)) { + inst = (nsObject*)new nsWindow(aOuter); + } + else if (mClassID.Equals(kCChild)) { + inst = (nsObject*)new ChildWindow(aOuter); + } + else if (mClassID.Equals(kCButton)) { + inst = (nsObject*)new nsButton(aOuter); + } + else if (mClassID.Equals(kCCheckButton)) { + inst = (nsObject*)new nsCheckButton(aOuter); + } + else if (mClassID.Equals(kCCombobox)) { + inst = (nsObject*)new nsComboBox(aOuter); + } + else if (mClassID.Equals(kCRadioButton)) { + inst = (nsObject*)new nsRadioButton(aOuter); + } + else if (mClassID.Equals(kCRadioGroup)) { + inst = (nsObject*)new nsRadioGroup(aOuter); + } + else if (mClassID.Equals(kCFileOpen)) { + inst = (nsObject*)new nsFileWidget(aOuter); + } + else if (mClassID.Equals(kCListbox)) { + inst = (nsObject*)new nsListBox(aOuter); + } + else if (mClassID.Equals(kCHorzScrollbar)) { + inst = (nsObject*)new nsScrollbar(aOuter, PR_FALSE); + } + else if (mClassID.Equals(kCVertScrollbar)) { + inst = (nsObject*)new nsScrollbar(aOuter, PR_TRUE); + } + else if (mClassID.Equals(kCTextArea)) { + inst = (nsObject*)new nsTextAreaWidget(aOuter); + } + else if (mClassID.Equals(kCTextField)) { + inst = (nsObject*)new nsTextWidget(aOuter); + } + + if (inst == NULL) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsresult res = inst->QueryObject(aIID, aResult); + + if (res != NS_OK) { + // We didn't get the right interface, so clean up + delete inst; + } + else { + NS_RELEASE(inst); + } + + return res; +} + +nsresult nsWidgetFactory::LockFactory(PRBool aLock) +{ + // Not implemented in simplest case. + return NS_OK; +} + +// return the proper factory to the caller +extern "C" NS_WIDGET nsresult NSGetFactory(const nsCID &aClass, nsIFactory **aFactory) +{ + if (nsnull == aFactory) { + return NS_ERROR_NULL_POINTER; + } + + *aFactory = new nsWidgetFactory(aClass); + + if (nsnull == aFactory) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return (*aFactory)->QueryInterface(kIFactoryIID, (void**)aFactory); +} + + diff --git a/mozilla/widget/src/windows/nsWindow.cpp b/mozilla/widget/src/windows/nsWindow.cpp new file mode 100644 index 00000000000..ed4e61720e5 --- /dev/null +++ b/mozilla/widget/src/windows/nsWindow.cpp @@ -0,0 +1,1731 @@ +/* -*- 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 "nsWindow.h" +#include "nsIFontMetrics.h" +#include "nsIFontCache.h" +#include "nsGUIEvent.h" +#include "nsIRenderingContext.h" +#include "nsIDeviceContext.h" +#include "nsRect.h" +#include "nsTransform2D.h" +#include +#include "nsGfxCIID.h" +#include "resource.h" + +#include "prtime.h" + +BOOL nsWindow::sIsRegistered = FALSE; + +nsWindow * mCurrentWindow = NULL; + +static NS_DEFINE_IID(kIWidgetIID, NS_IWIDGET_IID); + + +//------------------------------------------------------------------------- +// +// Convert nsEventStatus value to a windows boolean +// +//------------------------------------------------------------------------- + +PRBool nsWindow::ConvertStatus(nsEventStatus aStatus) +{ + switch(aStatus) { + case nsEventStatus_eIgnore: + return(PR_FALSE); + break; + case nsEventStatus_eConsumeNoDefault: + return(PR_TRUE); + break; + case nsEventStatus_eConsumeDoDefault: + return(PR_FALSE); + break; + default: + NS_ASSERTION(0, "Illegal nsEventStatus enumeration value"); + return(PR_FALSE); + break; + } +} + +//------------------------------------------------------------------------- +// +// the nsWindow procedure for all nsWindows in this toolkit +// +//------------------------------------------------------------------------- +LRESULT CALLBACK nsWindow::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + nsWindow *someWindow = (nsWindow*)::GetWindowLong(hWnd, GWL_USERDATA); + if (nsnull != someWindow) { + LRESULT retValue; + if (PR_TRUE == someWindow->ProcessMessage(msg, wParam, lParam, &retValue)) { + return retValue; + } + } + + return ::CallWindowProc((FARPROC)someWindow->GetPrevWindowProc(), hWnd, msg, wParam, lParam); +} + + +//------------------------------------------------------------------------- +// +// nsWindow constructor +// +//------------------------------------------------------------------------- +nsWindow::nsWindow(nsISupports *aOuter) : nsObject(aOuter) +{ + mWnd = 0; + mPrevWndProc = NULL; + mChildren = NULL; + mEventCallback = NULL; + mToolkit = NULL; + mMouseListener = NULL; + mEventListener = NULL; + mBackground = ::GetSysColor(COLOR_WINDOW); + mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground)); + mForeground = ::GetSysColor(COLOR_WINDOWTEXT); + mPalette = NULL; + mCursor = eCursor_standard; + mIsShiftDown = PR_FALSE; + mIsControlDown = PR_FALSE; + mIsAltDown = PR_FALSE; +} + + +//------------------------------------------------------------------------- +// +// nsWindow destructor +// +//------------------------------------------------------------------------- +nsWindow::~nsWindow() +{ + Destroy(); +} + + +//------------------------------------------------------------------------- +// +// Query interface implementation +// +//------------------------------------------------------------------------- +nsresult nsWindow::QueryObject(const nsIID& aIID, void** aInstancePtr) +{ + nsresult result = nsObject::QueryObject(aIID, aInstancePtr); + + static NS_DEFINE_IID(kIWidgetIID, NS_IWIDGET_IID); + if (result == NS_NOINTERFACE && aIID.Equals(kIWidgetIID)) { + *aInstancePtr = (void*) ((nsIWidget*)this); + AddRef(); + result = NS_OK; + } + + return result; +} + + +//------------------------------------------------------------------------- +// +// Create the proper widget +// +//------------------------------------------------------------------------- +void nsWindow::Create(nsIWidget *aParent, + const nsRect &aRect, + EVENT_CALLBACK aHandleEventFunction, + nsIDeviceContext *aContext, + nsIToolkit *aToolkit) +{ + if (NULL == mToolkit) { + if (NULL != aToolkit) { + mToolkit = (nsToolkit*)aToolkit; + mToolkit->AddRef(); + } + else { + if (NULL != aParent) { + mToolkit = (nsToolkit*)(aParent->GetToolkit()); // the call AddRef's, we don't have to + } + // it's some top level window with no toolkit passed in. + // Create a default toolkit with the current thread + else { + mToolkit = new nsToolkit(); + mToolkit->AddRef(); + mToolkit->Init(PR_GetCurrentThread()); + } + } + + } + + // + // Switch to the "main gui thread" if necessary... This method must + // be executed on the "gui thread"... + // + if (!mToolkit->IsGuiThread()) { + DWORD args[5]; + args[0] = (DWORD)aParent; + args[1] = (DWORD)&aRect; + args[2] = (DWORD)aHandleEventFunction; + args[3] = (DWORD)aContext; + args[4] = (DWORD)aToolkit; + MethodInfo info(this, nsWindow::CREATE, 5, args); + mToolkit->CallMethod(&info); + return; + } + + // save the event callback function + mEventCallback = aHandleEventFunction; + + // keep a reference to the toolkit object + if (aContext) { + mContext = aContext; + mContext->AddRef(); + } + else { + nsresult res; + + static NS_DEFINE_IID(kDeviceContextCID, NS_DEVICE_CONTEXT_CID); + static NS_DEFINE_IID(kDeviceContextIID, NS_IDEVICE_CONTEXT_IID); + + res = NSRepository::CreateInstance(kDeviceContextCID, nsnull, kDeviceContextIID, (void **)&mContext); + + if (NS_OK == res) + mContext->Init(); + } + + mWnd = ::CreateWindowEx(WindowExStyle(), + WindowClass(), + "", + WindowStyle(), + aRect.x, + aRect.y, + aRect.width, + aRect.height, + (aParent) ? (HWND)aParent->GetNativeData(NS_NATIVE_WINDOW): + (HWND)NULL, + NULL, + nsToolkit::mDllInstance, + NULL); + + VERIFY(mWnd); + if (aParent) { + aParent->AddChild(this); + } + + // Force cursor to default setting + mCursor = eCursor_select; + SetCursor(eCursor_standard); + + // call the event callback to notify about creation + if (mEventCallback) { + nsGUIEvent event; + event.widget = this; + + DWORD pos = ::GetMessagePos(); + POINT cpos; + + cpos.x = LOWORD(pos); + cpos.y = HIWORD(pos); + + ::ScreenToClient(mWnd, &cpos); + + event.point.x = cpos.x; + event.point.y = cpos.y; + + event.time = ::GetMessageTime(); + + // + event.message = NS_CREATE; + (*mEventCallback)(&event); + } + + SubclassWindow(TRUE); +} + + +//------------------------------------------------------------------------- +// +// create with a native parent +// +//------------------------------------------------------------------------- +void nsWindow::Create(nsNativeWindow aParent, + const nsRect &aRect, + EVENT_CALLBACK aHandleEventFunction, + nsIDeviceContext *aContext, + nsIToolkit *aToolkit) +{ + + if (NULL == mToolkit) { + if (NULL != aToolkit) { + mToolkit = (nsToolkit*)aToolkit; + mToolkit->AddRef(); + } + else { + mToolkit = new nsToolkit(); + mToolkit->AddRef(); + mToolkit->Init(PR_GetCurrentThread()); + } + + } + + // + // Switch to the "main gui thread" if necessary... This method must + // be executed on the "gui thread"... + // + if (!mToolkit->IsGuiThread()) { + DWORD args[5]; + args[0] = (DWORD)aParent; + args[1] = (DWORD)&aRect; + args[2] = (DWORD)aHandleEventFunction; + args[3] = (DWORD)aContext; + args[4] = (DWORD)aToolkit; + MethodInfo info(this, nsWindow::CREATE_NATIVE, 5, args); + mToolkit->CallMethod(&info); + return; + } + + // save the event callback function + mEventCallback = aHandleEventFunction; + + // keep a reference to the toolkit object + if (aContext) { + mContext = aContext; + mContext->AddRef(); + } + else { + nsresult res; + + static NS_DEFINE_IID(kDeviceContextCID, NS_DEVICE_CONTEXT_CID); + static NS_DEFINE_IID(kDeviceContextIID, NS_IDEVICE_CONTEXT_IID); + + res = NSRepository::CreateInstance(kDeviceContextCID, nsnull, kDeviceContextIID, (void **)&mContext); + + if (NS_OK == res) + mContext->Init(); + } + + mWnd = ::CreateWindowEx(WindowExStyle(), + WindowClass(), + "", + WindowStyle(), + aRect.x, + aRect.y, + aRect.width, + aRect.height, + aParent, + NULL, + nsToolkit::mDllInstance, + NULL); + + VERIFY(mWnd); + + // call the event callback to notify about creation + if (mEventCallback) { + nsGUIEvent event; + event.widget = this; + + DWORD pos = ::GetMessagePos(); + POINT cpos; + + cpos.x = LOWORD(pos); + cpos.y = HIWORD(pos); + + ::ScreenToClient(mWnd, &cpos); + + event.point.x = cpos.x; + event.point.y = cpos.y; + + event.time = ::GetMessageTime(); + + // + event.message = NS_CREATE; + (*mEventCallback)(&event); + } + + SubclassWindow(TRUE); +} + + +//------------------------------------------------------------------------- +// +// Close this nsWindow +// +//------------------------------------------------------------------------- +void nsWindow::Destroy() +{ + // + // Switch to the "main gui thread" if necessary... This method must + // be executed on the "gui thread"... + // + if (!mToolkit->IsGuiThread()) { + MethodInfo info(this, nsWindow::DESTROY); + mToolkit->CallMethod(&info); + return; + } + + // destroy the nsWindow + if (mWnd) { + // destroy the nsWindow + mEventCallback = nsnull; // prevent the widget from causing additional events + VERIFY(::DestroyWindow(mWnd)); + } + + if (mPalette) { + VERIFY(::DeleteObject(mPalette)); + } +} + + +//------------------------------------------------------------------------- +// +// Get this nsWindow parent +// +//------------------------------------------------------------------------- +nsIWidget* nsWindow::GetParent(void) +{ + nsIWidget* widget = NULL; + if (mWnd) { + HWND parent = ::GetParent(mWnd); + if (parent) { + nsIWidget* widget = (nsIWidget*)::GetWindowLong(mWnd, GWL_USERDATA); + widget->AddRef(); + } + } + + return widget; +} + + +//------------------------------------------------------------------------- +// +// Get this nsWindow's list of children +// +//------------------------------------------------------------------------- +nsIEnumerator* nsWindow::GetChildren() +{ + if (mChildren) { + mChildren->Reset(); + //mChildren->AddRef(); + + Enumerator * children = new Enumerator(); + nsISupports * next = mChildren->Next(); + if (next) { + nsIWidget *widget; + if (NS_OK == next->QueryInterface(kIWidgetIID, (void**)&widget)) { + children->Append(widget); + //NS_RELEASE(widget); + } + } + + return (nsIEnumerator*)children; + } + + return NULL; +} + + +//------------------------------------------------------------------------- +// +// Add a child to the list of children +// +//------------------------------------------------------------------------- +void nsWindow::AddChild(nsIWidget* aChild) +{ + if (!mChildren) { + mChildren = new Enumerator(); + } + + mChildren->Append(aChild); +} + + +//------------------------------------------------------------------------- +// +// Remove a child from the list of children +// +//------------------------------------------------------------------------- +void nsWindow::RemoveChild(nsIWidget* aChild) +{ + if (mChildren) { + mChildren->Remove(aChild); + } +} + + +//------------------------------------------------------------------------- +// +// Hide or show this component +// +//------------------------------------------------------------------------- +void nsWindow::Show(PRBool bState) +{ + if (mWnd) { + if (bState) { + ::SetWindowPos(mWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW); + } + else + ::ShowWindow(mWnd, SW_HIDE); + } +} + +//------------------------------------------------------------------------- +// +// Move this component +// +//------------------------------------------------------------------------- +void nsWindow::Move(PRUint32 aX, PRUint32 aY) +{ + if (mWnd) { + VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, 0, 0, + SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE)); + } +} + +//------------------------------------------------------------------------- +// +// Resize this component +// +//------------------------------------------------------------------------- +void nsWindow::Resize(PRUint32 aWidth, PRUint32 aHeight) +{ + if (mWnd) { + VERIFY(::SetWindowPos(mWnd, NULL, 0, 0, aWidth, aHeight, + SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE)); + } +} + + +//------------------------------------------------------------------------- +// +// Resize this component +// +//------------------------------------------------------------------------- +void nsWindow::Resize(PRUint32 aX, PRUint32 aY, PRUint32 aWidth, PRUint32 aHeight) +{ + if (mWnd) { + VERIFY(::SetWindowPos(mWnd, NULL, aX, aY, aWidth, aHeight, + SWP_NOZORDER | SWP_NOACTIVATE)); + } +} + + +//------------------------------------------------------------------------- +// +// Enable/disable this component +// +//------------------------------------------------------------------------- +void nsWindow::Enable(PRBool bState) +{ + if (mWnd) { + ::EnableWindow(mWnd, bState); + } +} + + +//------------------------------------------------------------------------- +// +// Give the focus to this component +// +//------------------------------------------------------------------------- +void nsWindow::SetFocus(void) +{ + // + // Switch to the "main gui thread" if necessary... This method must + // be executed on the "gui thread"... + // + if (!mToolkit->IsGuiThread()) { + MethodInfo info(this, nsWindow::SET_FOCUS); + mToolkit->CallMethod(&info); + return; + } + + if (mWnd) { + ::SetFocus(mWnd); + } +} + + +//------------------------------------------------------------------------- +// +// Get this component dimension +// +//------------------------------------------------------------------------- +void nsWindow::GetBounds(nsRect &aRect) +{ + if (mWnd) { + RECT r; + VERIFY(::GetWindowRect(mWnd, &r)); + + // assign size + aRect.width = r.right - r.left; + aRect.height = r.bottom - r.top; + + // convert coordinates if parent exists + HWND parent = ::GetParent(mWnd); + if (parent) { + ::ScreenToClient(parent, (LPPOINT)&r); + } + aRect.x = r.left; + aRect.y = r.top; + } +} + + +//------------------------------------------------------------------------- +// +// Get the foreground color +// +//------------------------------------------------------------------------- +nscolor nsWindow::GetForegroundColor(void) +{ + return mForeground; +} + + +//------------------------------------------------------------------------- +// +// Set the foreground color +// +//------------------------------------------------------------------------- +void nsWindow::SetForegroundColor(const nscolor &aColor) +{ + mForeground = aColor; +} + + +//------------------------------------------------------------------------- +// +// Get the background color +// +//------------------------------------------------------------------------- +nscolor nsWindow::GetBackgroundColor(void) +{ + return mBackground; +} + + +//------------------------------------------------------------------------- +// +// Set the background color +// +//------------------------------------------------------------------------- +void nsWindow::SetBackgroundColor(const nscolor &aColor) +{ + mBackground = aColor; + + ::DeleteObject(mBrush); + mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground)); + SetClassLong(mWnd, GCL_HBRBACKGROUND, (LONG)mBrush); +} + + +//------------------------------------------------------------------------- +// +// Get this component font +// +//------------------------------------------------------------------------- +nsIFontMetrics* nsWindow::GetFont(void) +{ + NS_NOTYETIMPLEMENTED("GetFont not yet implemented"); // to be implemented + return NULL; +} + + +//------------------------------------------------------------------------- +// +// Set this component font +// +//------------------------------------------------------------------------- +void nsWindow::SetFont(const nsFont &aFont) +{ + nsIFontCache* fontCache = mContext->GetFontCache(); + nsIFontMetrics* metrics = fontCache->GetMetricsFor(aFont); + HFONT hfont = metrics->GetFontHandle(); + + // Draw in the new font + ::SendMessage(mWnd, WM_SETFONT, (WPARAM)hfont, (LPARAM)0); + NS_RELEASE(metrics); + NS_RELEASE(fontCache); +} + + +//------------------------------------------------------------------------- +// +// Get this component cursor +// +//------------------------------------------------------------------------- +nsCursor nsWindow::GetCursor() +{ + return mCursor; +} + + +//------------------------------------------------------------------------- +// +// Set this component cursor +// +//------------------------------------------------------------------------- + +#define DLLQUOTE(x) #x +#define DLLNAME(x) DLLQUOTE(x) + +void nsWindow::SetCursor(nsCursor aCursor) +{ + // Only change cursor if it's changing + if (aCursor != mCursor) { + HCURSOR newCursor = NULL; + + switch(aCursor) { + case eCursor_select: + newCursor = ::LoadCursor(NULL, IDC_IBEAM); + break; + + case eCursor_wait: + newCursor = ::LoadCursor(NULL, IDC_WAIT); + break; + + case eCursor_hyperlink: { + HMODULE hm = ::GetModuleHandle(DLLNAME(NS_DLLNAME)); + newCursor = ::LoadCursor(hm, MAKEINTRESOURCE(IDC_SELECTANCHOR)); + break; + } + + case eCursor_standard: + newCursor = ::LoadCursor(NULL, IDC_ARROW); + break; + + default: + NS_ASSERTION(0, "Invalid cursor type"); + break; + } + + if (NULL != newCursor) { + mCursor = aCursor; + HCURSOR oldCursor = ::SetCursor(newCursor); + } + } +} + +//------------------------------------------------------------------------- +// +// Invalidate this component visible area +// +//------------------------------------------------------------------------- +void nsWindow::Invalidate(PRBool aIsSynchronous) +{ + if (mWnd) { + VERIFY(::InvalidateRect(mWnd, NULL, TRUE)); + if (aIsSynchronous) { + VERIFY(::UpdateWindow(mWnd)); + } + } +} + + +//------------------------------------------------------------------------- +// +// Return some native data according to aDataType +// +//------------------------------------------------------------------------- +void* nsWindow::GetNativeData(PRUint32 aDataType) +{ + switch(aDataType) { + case NS_NATIVE_WINDOW: + return (void*)mWnd; + case NS_NATIVE_GRAPHIC: + return (void*)::GetDC(mWnd); + case NS_NATIVE_COLORMAP: + default: + break; + } + + return NULL; +} + + +//------------------------------------------------------------------------- +// +// Create a rendering context from this nsWindow +// +//------------------------------------------------------------------------- +nsIRenderingContext* nsWindow::GetRenderingContext() +{ +nsRect bounds; + + nsIRenderingContext *renderingCtx = NULL; + if (mWnd) { + HDC aDC = ::GetDC(mWnd); + nsresult res; + + static NS_DEFINE_IID(kRenderingContextCID, NS_RENDERING_CONTEXT_CID); + static NS_DEFINE_IID(kRenderingContextIID, NS_IRENDERING_CONTEXT_IID); + + res = NSRepository::CreateInstance(kRenderingContextCID, nsnull, kRenderingContextIID, (void **)&renderingCtx); + + if (NS_OK == res) + renderingCtx->Init(mContext, (nsDrawingSurface)aDC); + + NS_ASSERTION(NULL != renderingCtx, "Null rendering context"); + } + + return renderingCtx; +} + +//------------------------------------------------------------------------- +// +// Return the toolkit this widget was created on +// +//------------------------------------------------------------------------- +nsIToolkit* nsWindow::GetToolkit() +{ + if (NULL != mToolkit) { + mToolkit->AddRef(); + } + + return mToolkit; +} + + +//------------------------------------------------------------------------- +// +// Set the colormap of the window +// +//------------------------------------------------------------------------- +void nsWindow::SetColorMap(nsColorMap *aColorMap) +{ + if (mPalette != NULL) { + ::DeleteObject(mPalette); + } + + PRUint8 *map = aColorMap->Index; + LPLOGPALETTE pLogPal = (LPLOGPALETTE) new char[2 * sizeof(WORD) + + aColorMap->NumColors * sizeof(PALETTEENTRY)]; + pLogPal->palVersion = 0x300; + pLogPal->palNumEntries = aColorMap->NumColors; + for(int i = 0; i < aColorMap->NumColors; i++) + { + pLogPal->palPalEntry[i].peRed = *map++; + pLogPal->palPalEntry[i].peGreen = *map++; + pLogPal->palPalEntry[i].peBlue = *map++; + pLogPal->palPalEntry[i].peFlags = 0; + } + mPalette = ::CreatePalette(pLogPal); + delete pLogPal; + + NS_ASSERTION(mPalette != NULL, "Null palette"); + if (mPalette != NULL) { + HDC hDC = ::GetDC(mWnd); + HPALETTE hOldPalette = ::SelectPalette(hDC, mPalette, TRUE); + ::RealizePalette(hDC); + ::SelectPalette(hDC, hOldPalette, TRUE); + ::ReleaseDC(mWnd, hDC); + } +} + +//------------------------------------------------------------------------- +// +// Return the used device context +// +//------------------------------------------------------------------------- +nsIDeviceContext* nsWindow::GetDeviceContext() +{ + if (mContext) { + mContext->AddRef(); + } + + return mContext; +} + + +//------------------------------------------------------------------------- +// +// Scroll the bits of a window +// +//------------------------------------------------------------------------- +void nsWindow::Scroll(PRInt32 aDx, PRInt32 aDy, nsRect *aClipRect) +{ + RECT trect; + + if (nsnull != aClipRect) + { + trect.left = aClipRect->x; + trect.top = aClipRect->y; + trect.right = aClipRect->XMost(); + trect.bottom = aClipRect->YMost(); + } + + ::ScrollWindowEx(mWnd, aDx, aDy, (nsnull != aClipRect) ? &trect : NULL, NULL, + NULL, NULL, SW_INVALIDATE); + ::UpdateWindow(mWnd); +} + +//------------------------------------------------------------------------- +// +// Every function that needs a thread switch goes through this function +// by calling SendMessage (..WM_CALLMETHOD..) in nsToolkit::CallMethod. +// +//------------------------------------------------------------------------- +BOOL nsWindow::CallMethod(MethodInfo *info) +{ + BOOL bRet = TRUE; + + switch (info->methodId) { + case nsWindow::CREATE: + NS_ASSERTION(info->nArgs == 5, "Wrong number of arguments to CallMethod"); + Create((nsIWidget*)(info->args[0]), + (nsRect&)*(nsRect*)(info->args[1]), + (EVENT_CALLBACK)(info->args[2]), + (nsIDeviceContext*)(info->args[3]), + (nsIToolkit*)(info->args[4])); + break; + + case nsWindow::CREATE_NATIVE: + NS_ASSERTION(info->nArgs == 5, "Wrong number of arguments to CallMethod"); + Create((nsNativeWindow)(info->args[0]), + (nsRect&)*(nsRect*)(info->args[1]), + (EVENT_CALLBACK)(info->args[2]), + (nsIDeviceContext*)(info->args[3]), + (nsIToolkit*)(info->args[4])); + return TRUE; + + case nsWindow::DESTROY: + NS_ASSERTION(info->nArgs == 0, "Wrong number of arguments to CallMethod"); + Destroy(); + break; + + case nsWindow::SET_FOCUS: + NS_ASSERTION(info->nArgs == 0, "Wrong number of arguments to CallMethod"); + SetFocus(); + break; + + default: + bRet = FALSE; + break; + } + + return bRet; +} + +//------------------------------------------------------------------------- +// +// OnKey +// +//------------------------------------------------------------------------- +PRBool nsWindow::OnKey(PRUint32 aEventType, PRUint32 aKeyCode) +{ + PRBool result = PR_TRUE; + + // call the event callback + if (mEventCallback) { + nsKeyEvent event; + event.widget = this; + + DWORD pos = ::GetMessagePos(); + POINT cpos; + + cpos.x = LOWORD(pos); + cpos.y = HIWORD(pos); + + ::ScreenToClient(mWnd, &cpos); + + event.point.x = cpos.x; + event.point.y = cpos.y; + + event.time = ::GetMessageTime(); + event.message = aEventType; + event.keyCode = aKeyCode; + event.isShift = mIsShiftDown; + event.isControl = mIsControlDown; + event.isAlt = mIsAltDown; + result = ConvertStatus((*mEventCallback)(&event)); + } + + return result; +} + + +//------------------------------------------------------------------------- +// +// Process all nsWindows messages +// +//------------------------------------------------------------------------- +PRBool nsWindow::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *aRetValue) +{ + PRBool result = PR_FALSE; // call the default nsWindow proc + + *aRetValue = 0; + + switch (msg) { + + case WM_DESTROY: + // clean up. + OnDestroy(); + result = PR_TRUE; + if (nsnull != mEventListener) { + printf("Destroy for window called\n"); + DispatchEvent(NS_DESTROY); + } + break; + + case WM_PAINT: + result = OnPaint(); + if (nsnull != mEventListener) { + DispatchEvent(NS_PAINT); + } + break; + + case WM_KEYUP: + if (wParam == NS_VK_SHIFT) { + mIsShiftDown = PR_FALSE; + } + if (wParam == NS_VK_CONTROL) { + mIsControlDown = PR_FALSE; + } + if (wParam == NS_VK_ALT) { + mIsAltDown = PR_FALSE; + } + result = OnKey(NS_KEY_UP, wParam); + break; + + case WM_KEYDOWN: + if (wParam == NS_VK_SHIFT) { + mIsShiftDown = PR_TRUE; + } + if (wParam == NS_VK_CONTROL) { + mIsControlDown = PR_TRUE; + } + if (wParam == NS_VK_ALT) { + mIsAltDown = PR_TRUE; + } + result = OnKey(NS_KEY_DOWN, wParam); + break; + + // say we've dealt with erase background + case WM_ERASEBKGND: + *aRetValue = 1; + result = PR_TRUE; + break; + + case WM_MOUSEMOVE: + result = DispatchMouseEvent(NS_MOUSE_MOVE); + break; + + case WM_LBUTTONDOWN: + result = DispatchMouseEvent(NS_MOUSE_LEFT_BUTTON_DOWN); + break; + + case WM_LBUTTONUP: + result = DispatchMouseEvent(NS_MOUSE_LEFT_BUTTON_UP); + break; + + case WM_LBUTTONDBLCLK: + result = DispatchMouseEvent(NS_MOUSE_LEFT_BUTTON_DOWN); + break; + + case WM_MBUTTONDOWN: + result = DispatchMouseEvent(NS_MOUSE_MIDDLE_BUTTON_DOWN); + break; + + case WM_MBUTTONUP: + result = DispatchMouseEvent(NS_MOUSE_MIDDLE_BUTTON_UP); + break; + + case WM_MBUTTONDBLCLK: + result = DispatchMouseEvent(NS_MOUSE_MIDDLE_BUTTON_DOWN); + break; + + case WM_RBUTTONDOWN: + result = DispatchMouseEvent(NS_MOUSE_RIGHT_BUTTON_DOWN); + break; + + case WM_RBUTTONUP: + result = DispatchMouseEvent(NS_MOUSE_RIGHT_BUTTON_UP); + break; + + case WM_RBUTTONDBLCLK: + result = DispatchMouseEvent(NS_MOUSE_RIGHT_BUTTON_DOWN); + break; + + case WM_HSCROLL: + case WM_VSCROLL: + // check for the incoming nsWindow handle to be null in which case + // we assume the message is coming from a horizontal scrollbar inside + // a listbox and we don't bother processing it (well, we don't have to) + if (lParam) { + nsWindow* scrollbar = (nsWindow*)::GetWindowLong((HWND)lParam, GWL_USERDATA); + + if (scrollbar) { + result = scrollbar->OnScroll(LOWORD(wParam), (short)HIWORD(wParam)); + } + } + break; + + case WM_CTLCOLORBTN: + case WM_CTLCOLOREDIT: + case WM_CTLCOLORLISTBOX: + case WM_CTLCOLORSCROLLBAR: + case WM_CTLCOLORSTATIC: + if (lParam) { + nsWindow* control = (nsWindow*)::GetWindowLong((HWND)lParam, GWL_USERDATA); + if (control) { + HDC hDC = (HDC)wParam; + ::SetBkColor (hDC, mBackground); + ::SetTextColor(hDC, mForeground); + *aRetValue = (LPARAM)control->OnControlColor(); + } + } + + result = PR_TRUE; + break; + + case WM_SETFOCUS: + result = DispatchFocus(NS_GOTFOCUS); + if (nsnull != mEventListener) { + DispatchEvent(NS_GOTFOCUS); + } + break; + + case WM_KILLFOCUS: + result = DispatchFocus(NS_LOSTFOCUS); + if (nsnull != mEventListener) { + DispatchEvent(NS_LOSTFOCUS); + } + break; + + case WM_WINDOWPOSCHANGED: + { + WINDOWPOS *wp = (LPWINDOWPOS)lParam; + nsRect rect(wp->x, wp->y, wp->cx, wp->cy); + result = OnResize(rect); + if (nsnull != mEventListener) { + DispatchEvent(NS_SIZE); + } + break; + } + case WM_QUERYNEWPALETTE: + if (mPalette) { + HDC hDC = ::GetDC(mWnd); + HPALETTE hOldPal = ::SelectPalette(hDC, mPalette, 0); + + int i = ::RealizePalette(hDC); + + ::SelectPalette(hDC, hOldPal, 0); + ::ReleaseDC(mWnd, hDC); + + if (i) { + ::InvalidateRect(mWnd, (LPRECT)(NULL), 1); + result = PR_TRUE; + } + else { + result = PR_FALSE; + } + } + else { + result = PR_FALSE; + } + break; + case WM_PALETTECHANGED: + if (mPalette && (HWND)wParam != mWnd) { + HDC hDC = ::GetDC(mWnd); + HPALETTE hOldPal = ::SelectPalette(hDC, mPalette, 0); + + int i = ::RealizePalette(hDC); + + if (i) { + ::InvalidateRect(mWnd, (LPRECT)(NULL), 1); + } + + ::SelectPalette(hDC, hOldPal, 0); + ::ReleaseDC(mWnd, hDC); + } + result = PR_TRUE; + break; + + } + + return result; +} + + + +//------------------------------------------------------------------------- +// +// return the window class name and initialize the class if needed +// +//------------------------------------------------------------------------- +LPCTSTR nsWindow::WindowClass() +{ + if (!nsWindow::sIsRegistered) { + WNDCLASS wc; + + wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; + wc.lpfnWndProc = ::DefWindowProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = nsToolkit::mDllInstance; + wc.hIcon = ::LoadIcon(NULL, IDI_APPLICATION); + wc.hCursor = NULL; + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = "NetscapeWindowClass"; + + nsWindow::sIsRegistered = ::RegisterClass(&wc); + } + + return "NetscapeWindowClass"; +} + + +//------------------------------------------------------------------------- +// +// return nsWindow styles +// +//------------------------------------------------------------------------- +DWORD nsWindow::WindowStyle() +{ + return WS_OVERLAPPEDWINDOW; +} + + +//------------------------------------------------------------------------- +// +// return nsWindow extended styles +// +//------------------------------------------------------------------------- +DWORD nsWindow::WindowExStyle() +{ + return WS_EX_CLIENTEDGE; +} + + +// ----------------------------------------------------------------------- +// +// Subclass (or remove the subclass from) this component's nsWindow +// +// ----------------------------------------------------------------------- +void nsWindow::SubclassWindow(BOOL bState) +{ + NS_PRECONDITION(::IsWindow(mWnd), "Invalid window handle"); + + if (bState) { + // change the nsWindow proc + mPrevWndProc = (WNDPROC)::SetWindowLong(mWnd, GWL_WNDPROC, + (LONG)nsWindow::WindowProc); + NS_ASSERTION(mPrevWndProc, "Null standard window procedure"); + // connect the this pointer to the nsWindow handle + ::SetWindowLong(mWnd, GWL_USERDATA, (LONG)this); + } + else { + (void) ::SetWindowLong(mWnd, GWL_WNDPROC, (LONG)mPrevWndProc); + mPrevWndProc = NULL; + } +} + + +//------------------------------------------------------------------------- +// +// WM_DESTROY has been called +// +//------------------------------------------------------------------------- +void nsWindow::OnDestroy() +{ + SubclassWindow(FALSE); + + if (mBrush) + ::DeleteObject(mBrush); + + // disconnect from the parent + /* + nsIWidget *parent = GetParent(); + if (parent) { + parent->RemoveChild(this); + }*/ + + mWnd = 0; + + // release children (I don't think we need this but...) + if (mChildren) { + NS_RELEASE(mChildren); + mChildren = NULL; + } + + // get the pixels to twips info before the device context is released + if (mContext) { + NS_RELEASE(mContext); + mContext = 0; + } + + if (NULL != mToolkit) { + NS_RELEASE(mToolkit); + mToolkit = NULL; + } + + // call the event callback + if (mEventCallback) { + nsGUIEvent event; + event.widget = this; + + DWORD pos = ::GetMessagePos(); + POINT cpos; + + cpos.x = LOWORD(pos); + cpos.y = HIWORD(pos); + + ::ScreenToClient(mWnd, &cpos); + + event.point.x = cpos.x; + event.point.y = cpos.y; + + event.time = ::GetMessageTime(); + event.message = NS_DESTROY; + + (*mEventCallback)(&event); + } + if (nsnull != mEventListener) { + DispatchEvent(NS_DESTROY); + } +} + + +//------------------------------------------------------------------------- +// +// Paint +// +//------------------------------------------------------------------------- +PRBool nsWindow::OnPaint() +{ + nsRect bounds; + PRBool result = PR_TRUE; + PAINTSTRUCT ps; + HDC hDC = ::BeginPaint(mWnd, &ps); + + if (ps.rcPaint.left || ps.rcPaint.right || ps.rcPaint.top || ps.rcPaint.bottom) { + + // call the event callback + if (mEventCallback) { + nsPaintEvent event; + event.widget = this; + + DWORD pos = ::GetMessagePos(); + POINT cpos; + + cpos.x = LOWORD(pos); + cpos.y = HIWORD(pos); + + ::ScreenToClient(mWnd, &cpos); + + event.point.x = cpos.x; + event.point.y = cpos.y; + + event.time = ::GetMessageTime(); + event.message = NS_PAINT; + + nsRect rect(ps.rcPaint.left, + ps.rcPaint.top, + ps.rcPaint.right - ps.rcPaint.left, + ps.rcPaint.bottom - ps.rcPaint.top); + event.rect = ▭ + + static NS_DEFINE_IID(kRenderingContextCID, NS_RENDERING_CONTEXT_CID); + static NS_DEFINE_IID(kRenderingContextIID, NS_IRENDERING_CONTEXT_IID); + + if (NS_OK == NSRepository::CreateInstance(kRenderingContextCID, nsnull, kRenderingContextIID, (void **)&event.renderingContext)) + { + event.renderingContext->Init(mContext, (nsDrawingSurface)hDC); + result = ConvertStatus((*mEventCallback)(&event)); + + NS_RELEASE(event.renderingContext); + } + else + result = PR_FALSE; + } + } + + ::EndPaint(mWnd, &ps); + + return result; +} + + +//------------------------------------------------------------------------- +// +// Send a resize message to the listener +// +//------------------------------------------------------------------------- +PRBool nsWindow::OnResize(nsRect &aWindowRect) +{ + // call the event callback + if (mEventCallback) { + nsSizeEvent event; + event.widget = this; + event.message = NS_SIZE; + + // get the message position in client coordinates and in twips + DWORD pos = ::GetMessagePos(); + POINT cpos; + + cpos.x = LOWORD(pos); + cpos.y = HIWORD(pos); + + ::ScreenToClient(mWnd, &cpos); + + event.point.x = cpos.x; + event.point.y = cpos.y; + + event.time = ::GetMessageTime(); + + event.windowSize = &aWindowRect; + return ConvertStatus((*mEventCallback)(&event)); + } + + return PR_FALSE; +} + +//------------------------------------------------------------------------- +// +// Invokes ProcessEvent method on Event Listener object +// +//------------------------------------------------------------------------- +PRBool nsWindow::DispatchEvent(PRUint32 aEventType) +{ + if (nsnull == mEventListener) { + return PR_FALSE; + } + + nsGUIEvent event; + event.widget = this; + + // get the message position in client coordinates and in twips + DWORD pos = ::GetMessagePos(); + POINT cpos; + + cpos.x = LOWORD(pos); + cpos.y = HIWORD(pos); + + ::ScreenToClient(mWnd, &cpos); + + event.point.x = cpos.x; + event.point.y = cpos.y; + + event.time = ::GetMessageTime(); + event.message = aEventType; + + return ConvertStatus(mEventListener->ProcessEvent(event)); +} + +//------------------------------------------------------------------------- +// +// Deal with all sort of mouse event +// +//------------------------------------------------------------------------- +PRBool nsWindow::DispatchMouseEvent(PRUint32 aEventType) +{ + PRBool result = PR_FALSE; + + if (nsnull == mEventCallback && nsnull == mMouseListener) { + return result; + } + + // nsMouseEvent event; + nsGUIEvent event; + event.widget = this; + + // get the message position in client coordinates and in twips + DWORD pos = ::GetMessagePos(); + POINT cpos; + + cpos.x = LOWORD(pos); + cpos.y = HIWORD(pos); + + ::ScreenToClient(mWnd, &cpos); + + event.point.x = cpos.x; + event.point.y = cpos.y; + event.time = ::GetMessageTime(); + event.message = aEventType; + + // call the event callback + if (nsnull != mEventCallback) { + result = ConvertStatus((*mEventCallback)(&event)); + + //printf("**result=%d%\n",result); + if (aEventType == NS_MOUSE_MOVE) { + + MouseTrailer * mouseTrailer = MouseTrailer::GetMouseTrailer(0); + MouseTrailer::SetMouseTrailerWindow(this); + mouseTrailer->CreateTimer(); + + nsRect rect; + GetBounds(rect); + rect.x = 0; + rect.y = 0; + //printf("Rect[%d, %d, %d, %d] Point[%d,%d]\n", rect.x, rect.y, rect.width, rect.height, event.position.x, event.position.y); + //printf("mCurrentWindow 0x%X\n", mCurrentWindow); + + if (rect.Contains(event.point.x, event.point.y)) { + if (mCurrentWindow == NULL || mCurrentWindow != this) { + if (nsnull != mCurrentWindow) { + mCurrentWindow->DispatchMouseEvent(NS_MOUSE_EXIT); + } + mCurrentWindow = this; + mCurrentWindow->DispatchMouseEvent(NS_MOUSE_ENTER); + } + } + } else if (aEventType == NS_MOUSE_EXIT) { + if (mCurrentWindow == this) { + mCurrentWindow = nsnull; + } + } + + return result; + } + + if (nsnull != mMouseListener) { + switch (aEventType) { + case NS_MOUSE_MOVE: { + result = ConvertStatus(mMouseListener->MouseMoved(event)); + nsRect rect; + GetBounds(rect); + if (rect.Contains(event.point.x, event.point.y)) { + if (mCurrentWindow == NULL || mCurrentWindow != this) { + printf("Mouse enter"); + mCurrentWindow = this; + } + } else { + printf("Mouse exit"); + } + + } break; + + case NS_MOUSE_LEFT_BUTTON_DOWN: + case NS_MOUSE_MIDDLE_BUTTON_DOWN: + case NS_MOUSE_RIGHT_BUTTON_DOWN: + result = ConvertStatus(mMouseListener->MousePressed(event)); + break; + + case NS_MOUSE_LEFT_BUTTON_UP: + case NS_MOUSE_MIDDLE_BUTTON_UP: + case NS_MOUSE_RIGHT_BUTTON_UP: + result = ConvertStatus(mMouseListener->MouseReleased(event)); + result = ConvertStatus(mMouseListener->MouseClicked(event)); + break; + } // switch + } + return result; +} + + +//------------------------------------------------------------------------- +// +// Deal with focus messages +// +//------------------------------------------------------------------------- +PRBool nsWindow::DispatchFocus(PRUint32 aEventType) +{ + // call the event callback + if (mEventCallback) { + nsGUIEvent event; + event.widget = this; + + DWORD pos = ::GetMessagePos(); + POINT cpos; + + cpos.x = LOWORD(pos); + cpos.y = HIWORD(pos); + + ::ScreenToClient(mWnd, &cpos); + + event.point.x = cpos.x; + event.point.y = cpos.y; + + event.time = ::GetMessageTime(); + event.message = aEventType; + + return ConvertStatus((*mEventCallback)(&event)); + } + + return PR_FALSE; +} + + +//------------------------------------------------------------------------- +// +// Deal with scrollbar messages (actually implemented only in nsScrollbar) +// +//------------------------------------------------------------------------- +PRBool nsWindow::OnScroll(UINT scrollCode, int cPos) +{ + return PR_FALSE; +} + + +//------------------------------------------------------------------------- +// +// Return the brush used to paint the background of this control +// +//------------------------------------------------------------------------- +HBRUSH nsWindow::OnControlColor() +{ + return mBrush; +} + + +//------------------------------------------------------------------------- +// +// Constructor +// +//------------------------------------------------------------------------- +#define INITIAL_SIZE 2 + +nsWindow::Enumerator::Enumerator() +{ + mRefCnt = 1; + mArraySize = INITIAL_SIZE; + mChildrens = (nsIWidget**)new DWORD[mArraySize]; + memset(mChildrens, 0, sizeof(DWORD) * mArraySize); + mCurrentPosition = 0; +} + + +//------------------------------------------------------------------------- +// +// Destructor +// +//------------------------------------------------------------------------- +nsWindow::Enumerator::~Enumerator() +{ + if (mChildrens) { + //for (int i = 0; mChildrens[i] && i < mArraySize; i++) { + // NS_RELEASE(mChildrens[i]); + //} + + delete[] mChildrens; + } +} + +// +// The evil triad +// +NS_IMPL_ISUPPORTS(nsWindow::Enumerator, NS_IENUMERATOR_IID); + +//------------------------------------------------------------------------- +// +// Get enumeration next element. Return null at the end +// +//------------------------------------------------------------------------- +nsISupports* nsWindow::Enumerator::Next() +{ + if (mCurrentPosition < mArraySize && mChildrens[mCurrentPosition]) { + mChildrens[mCurrentPosition]->AddRef(); + return mChildrens[mCurrentPosition++]; + } + + return NULL; +} + + +//------------------------------------------------------------------------- +// +// Reset enumerator internal pointer to the beginning +// +//------------------------------------------------------------------------- +void nsWindow::Enumerator::Reset() +{ + mCurrentPosition = 0; +} + + +//------------------------------------------------------------------------- +// +// Append an element +// +//------------------------------------------------------------------------- +void nsWindow::Enumerator::Append(nsIWidget* aWidget) +{ + NS_PRECONDITION(aWidget, "Null widget"); + if (aWidget) { + int pos; + for (pos = 0; pos < mArraySize && mChildrens[pos]; pos++); + if (pos == mArraySize) { + GrowArray(); + } + mChildrens[pos] = aWidget; + aWidget->AddRef(); + } +} + + +//------------------------------------------------------------------------- +// +// Remove an element +// +//------------------------------------------------------------------------- +void nsWindow::Enumerator::Remove(nsIWidget* aWidget) +{ + int pos; + for(pos = 0; mChildrens[pos] && (mChildrens[pos] != aWidget); pos++); + if (mChildrens[pos] == aWidget) { + NS_RELEASE(aWidget); + memcpy(mChildrens + pos, mChildrens + pos + 1, mArraySize - pos - 1); + } + +} + + +//------------------------------------------------------------------------- +// +// Grow the size of the children array +// +//------------------------------------------------------------------------- +void nsWindow::Enumerator::GrowArray() +{ + mArraySize <<= 1; + nsIWidget **newArray = (nsIWidget**)new DWORD[mArraySize]; + memset(newArray, 0, sizeof(DWORD) * mArraySize); + memcpy(newArray, mChildrens, (mArraySize>>1) * sizeof(DWORD)); + mChildrens = newArray; +} + + +//------------------------------------------------------------------------- +// +// return the style for a child nsWindow +// +//------------------------------------------------------------------------- +DWORD ChildWindow::WindowStyle() +{ + return WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN; +} + + +/** + * Processes a mouse pressed event + * + **/ +void nsWindow::AddMouseListener(nsIMouseListener * aListener) +{ + NS_PRECONDITION(mMouseListener == nsnull, "Null mouse listener"); + mMouseListener = aListener; +} + +/** + * Processes a mouse pressed event + * + **/ +void nsWindow::AddEventListener(nsIEventListener * aListener) +{ + NS_PRECONDITION(mEventListener == nsnull, "Null mouse listener"); + mEventListener = aListener; +} + diff --git a/mozilla/widget/src/windows/nsWindow.h b/mozilla/widget/src/windows/nsWindow.h new file mode 100644 index 00000000000..856f7caf2cb --- /dev/null +++ b/mozilla/widget/src/windows/nsWindow.h @@ -0,0 +1,352 @@ +/* -*- 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. + */ +#ifndef Window_h__ +#define Window_h__ + +#include "nsdefs.h" +#include "nsObject.h" +#include "nsSwitchToUIThread.h" +#include "nsToolkit.h" + +#include "nsIWidget.h" +#include "nsIEnumerator.h" + +#include "nsIMouseListener.h" +#include "nsIEventListener.h" + + +#define NSRGB_2_COLOREF(color) \ + RGB(NS_GET_R(color),NS_GET_G(color),NS_GET_B(color)) + +class nsWindow : public nsObject, + public nsIWidget, + public nsSwitchToUIThread +{ + +public: + nsWindow(nsISupports *aOuter); + virtual ~nsWindow(); + + // nsISupports. Forward to the nsObject base class + BASE_SUPPORT + + virtual nsresult QueryObject(const nsIID& aIID, void** aInstancePtr); + + // nsIWidget interface + virtual void Create(nsIWidget *aParent, + const nsRect &aRect, + EVENT_CALLBACK aHandleEventFunction, + nsIDeviceContext *aContext, + nsIToolkit *aToolkit = nsnull); + virtual void Create(nsNativeWindow aParent, + const nsRect &aRect, + EVENT_CALLBACK aHandleEventFunction, + nsIDeviceContext *aContext, + nsIToolkit *aToolkit = nsnull); + virtual void Destroy(); + virtual nsIWidget* GetParent(void); + virtual nsIEnumerator* GetChildren(); + virtual void AddChild(nsIWidget* aChild); + virtual void RemoveChild(nsIWidget* aChild); + virtual void Show(PRBool bState); + virtual void Move(PRUint32 aX, PRUint32 aY); + virtual void Resize(PRUint32 aWidth, + PRUint32 aHeight); + virtual void Resize(PRUint32 aX, + PRUint32 aY, + PRUint32 aWidth, + PRUint32 aHeight); + virtual void Enable(PRBool bState); + virtual void SetFocus(void); + virtual void GetBounds(nsRect &aRect); + virtual nscolor GetForegroundColor(void); + virtual void SetForegroundColor(const nscolor &aColor); + virtual nscolor GetBackgroundColor(void); + virtual void SetBackgroundColor(const nscolor &aColor); + virtual nsIFontMetrics* GetFont(void); + virtual void SetFont(const nsFont &aFont); + virtual nsCursor GetCursor(); + virtual void SetCursor(nsCursor aCursor); + virtual void Invalidate(PRBool aIsSynchronous); + virtual void* GetNativeData(PRUint32 aDataType); + virtual nsIRenderingContext* GetRenderingContext(); + virtual void SetColorMap(nsColorMap *aColorMap); + virtual nsIDeviceContext* GetDeviceContext(); + virtual void Scroll(PRInt32 aDx, PRInt32 aDy, nsRect *aClipRect); + virtual nsIToolkit* GetToolkit(); + + virtual void AddMouseListener(nsIMouseListener * aListener); + virtual void AddEventListener(nsIEventListener * aListener); + + // nsSwitchToUIThread interface + virtual BOOL CallMethod(MethodInfo *info); + + HWND GetWindowHandle() { return mWnd; } + WNDPROC GetPrevWindowProc() { return mPrevWndProc; } + + virtual PRBool DispatchMouseEvent(PRUint32 aEventType); + +protected: + + virtual PRBool ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *aRetValue); + + virtual LPCTSTR WindowClass(); + virtual DWORD WindowStyle(); + virtual DWORD WindowExStyle(); + + void SubclassWindow(BOOL bState); + + virtual void OnDestroy(); + virtual PRBool OnPaint(); + virtual PRBool OnResize(nsRect &aWindowRect); + virtual PRBool OnKey(PRUint32 aEventType, PRUint32 aKeyCode); + + virtual PRBool DispatchFocus(PRUint32 aEventType); + virtual PRBool DispatchEvent(PRUint32 aEventType); + + virtual PRBool OnScroll(UINT scrollCode, int cPos); + virtual HBRUSH OnControlColor(); + + static LRESULT CALLBACK WindowProc(HWND hWnd, + UINT msg, + WPARAM wParam, + LPARAM lParam); + + static PRBool ConvertStatus(nsEventStatus aStatus); + +protected: + HWND mWnd; + HPALETTE mPalette; + WNDPROC mPrevWndProc; + EVENT_CALLBACK mEventCallback; + nsIDeviceContext *mContext; + nsIFontMetrics *mFontMetrics; + nsToolkit *mToolkit; + + nsIMouseListener * mMouseListener; + nsIEventListener * mEventListener; + + nscolor mBackground; + HBRUSH mBrush; + nscolor mForeground; + nsCursor mCursor; + + PRBool mIsShiftDown; + PRBool mIsControlDown; + PRBool mIsAltDown; + + // keep the list of children + class Enumerator : public nsIEnumerator { + nsIWidget **mChildrens; + int mCurrentPosition; + int mArraySize; + + public: + NS_DECL_ISUPPORTS + + Enumerator(); + ~Enumerator(); + + NS_IMETHOD_(nsISupports*) Next(); + NS_IMETHOD_(void) Reset(); + + void Append(nsIWidget* aWidget); + void Remove(nsIWidget* aWidget); + + private: + void GrowArray(); + + } *mChildren; + + // Enumeration of the methods which are accessable on the "main GUI thread" + // via the CallMethod(...) mechanism... + // see nsSwitchToUIThread + enum { + CREATE = 0x0101, + CREATE_NATIVE, + DESTROY, + SET_FOCUS, + SET_CURSOR, + CREATE_HACK + }; + + static BOOL sIsRegistered; +}; + +// +// A child window is a window with different style +// +class ChildWindow : public nsWindow { + +public: + ChildWindow(nsISupports *aOuter) : nsWindow(aOuter) {} + +protected: + virtual DWORD WindowStyle(); + virtual DWORD WindowExStyle() { return 0; } +}; + +#define BASE_IWIDGET_IMPL BASE_INITIALIZE_IMPL BASE_WINDOWS_METHODS + + +#define BASE_INITIALIZE_IMPL \ + void Create(nsIWidget *aParent, \ + const nsRect &aRect, \ + EVENT_CALLBACK aHandleEventFunction, \ + nsIDeviceContext *aContext, \ + nsIToolkit *aToolkit = nsnull) \ + { \ + nsWindow::Create(aParent, aRect, aHandleEventFunction, aContext, aToolkit); \ + } \ + +#define BASE_WINDOWS_METHODS \ + void Create(nsNativeWindow aParent, \ + const nsRect &aRect, \ + EVENT_CALLBACK aHandleEventFunction, \ + nsIDeviceContext *aContext, \ + nsIToolkit *aToolkit = nsnull) \ + { \ + nsWindow::Create(aParent, aRect, aHandleEventFunction, aContext, aToolkit); \ + } \ + void Destroy(void) \ + { \ + nsWindow::Destroy(); \ + } \ + nsIWidget* GetParent(void) \ + { \ + return nsWindow::GetParent(); \ + } \ + nsIEnumerator* GetChildren(void) \ + { \ + return nsWindow::GetChildren(); \ + } \ + void AddChild(nsIWidget* aChild) \ + { \ + nsWindow::AddChild(aChild); \ + } \ + void RemoveChild(nsIWidget* aChild) \ + { \ + nsWindow::RemoveChild(aChild); \ + } \ + void Show(PRBool bState) \ + { \ + nsWindow::Show(bState); \ + } \ + void Move(PRUint32 aX, PRUint32 aY) \ + { \ + nsWindow::Move(aX, aY); \ + } \ + void Resize(PRUint32 aWidth, \ + PRUint32 aHeight) \ + { \ + nsWindow::Resize(aWidth, aHeight); \ + } \ + void Resize(PRUint32 aX, \ + PRUint32 aY, \ + PRUint32 aWidth, \ + PRUint32 aHeight) \ + { \ + nsWindow::Resize(aX, aY, aWidth, aHeight); \ + } \ + void Enable(PRBool bState) \ + { \ + nsWindow::Enable(bState); \ + } \ + void SetFocus(void) \ + { \ + nsWindow::SetFocus(); \ + } \ + void GetBounds(nsRect &aRect) \ + { \ + nsWindow::GetBounds(aRect); \ + } \ + nscolor GetForegroundColor(void) \ + { \ + return nsWindow::GetForegroundColor(); \ + } \ + void SetForegroundColor(const nscolor &aColor) \ + { \ + nsWindow::SetForegroundColor(aColor); \ + } \ + nscolor GetBackgroundColor(void) \ + { \ + return nsWindow::GetBackgroundColor(); \ + } \ + void SetBackgroundColor(const nscolor &aColor) \ + { \ + nsWindow::SetBackgroundColor(aColor); \ + } \ + nsIFontMetrics* GetFont(void) \ + { \ + return nsWindow::GetFont(); \ + } \ + void SetFont(const nsFont &aFont) \ + { \ + nsWindow::SetFont(aFont); \ + } \ + nsCursor GetCursor() \ + { \ + return nsWindow::GetCursor(); \ + } \ + void SetCursor(nsCursor aCursor) \ + { \ + nsWindow::SetCursor(aCursor); \ + } \ + void Invalidate(PRBool aIsSynchronous) \ + { \ + nsWindow::Invalidate(aIsSynchronous); \ + } \ + void* GetNativeData(PRUint32 aDataType) \ + { \ + return nsWindow::GetNativeData(aDataType); \ + } \ + nsIRenderingContext* GetRenderingContext() \ + { \ + return nsWindow::GetRenderingContext(); \ + } \ + nsIDeviceContext* GetDeviceContext() \ + { \ + return nsWindow::GetDeviceContext(); \ + } \ + void Scroll(PRInt32 aDx, PRInt32 aDy, nsRect *aClipRect) \ + { \ + nsWindow::Scroll(aDx, aDy, aClipRect); \ + } \ + nsIToolkit* GetToolkit() \ + { \ + return nsWindow::GetToolkit(); \ + } \ + void SetColorMap(nsColorMap *aColorMap) \ + { \ + nsWindow::SetColorMap(aColorMap); \ + } \ + void AddMouseListener(nsIMouseListener * aListener) \ + { \ + nsWindow::AddMouseListener(aListener); \ + } \ + void AddEventListener(nsIEventListener * aListener) \ + { \ + nsWindow::AddEventListener(aListener); \ + } \ + PRBool OnKey(PRUint32 aEventType, PRUint32 aKeyCode) \ + { \ + return nsWindow::OnKey(aEventType, aKeyCode); \ + } + + +#endif // Window_h__ diff --git a/mozilla/widget/src/windows/nsdefs.h b/mozilla/widget/src/windows/nsdefs.h new file mode 100644 index 00000000000..9ef00bb72b5 --- /dev/null +++ b/mozilla/widget/src/windows/nsdefs.h @@ -0,0 +1,38 @@ +/* -*- 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. + */ + +#ifndef NSDEFS_H +#define NSDEFS_H + +#include + +#ifdef _DEBUG + #define BREAK_TO_DEBUGGER DebugBreak() +#else + #define BREAK_TO_DEBUGGER +#endif + +#ifdef _DEBUG + #define VERIFY(exp) ((exp) ? 0: (GetLastError(), BREAK_TO_DEBUGGER)) +#else // !_DEBUG + #define VERIFY(exp) (exp) +#endif // !_DEBUG + +#endif // NSDEFS_H + + diff --git a/mozilla/widget/src/windows/res/select.cur b/mozilla/widget/src/windows/res/select.cur new file mode 100644 index 00000000000..5a88b3707ee Binary files /dev/null and b/mozilla/widget/src/windows/res/select.cur differ diff --git a/mozilla/widget/src/windows/resource.h b/mozilla/widget/src/windows/resource.h new file mode 100644 index 00000000000..0573a0dfe4b --- /dev/null +++ b/mozilla/widget/src/windows/resource.h @@ -0,0 +1,18 @@ +/* -*- 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. + */ +#define IDC_SELECTANCHOR 4100 diff --git a/mozilla/widget/src/windows/widget.rc b/mozilla/widget/src/windows/widget.rc new file mode 100644 index 00000000000..7273757ce1e --- /dev/null +++ b/mozilla/widget/src/windows/widget.rc @@ -0,0 +1,20 @@ +/* -*- 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 "resource.h" + +IDC_SELECTANCHOR CURSOR DISCARDABLE "res\\select.cur" diff --git a/mozilla/widget/tests/Makefile b/mozilla/widget/tests/Makefile new file mode 100644 index 00000000000..0725c58d807 --- /dev/null +++ b/mozilla/widget/tests/Makefile @@ -0,0 +1,22 @@ +#!gmake +# +# 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. + +DEPTH = ../.. + +include $(DEPTH)/config/config.mk + +include $(DEPTH)/config/rules.mk diff --git a/mozilla/widget/tests/Scribble.cpp b/mozilla/widget/tests/Scribble.cpp new file mode 100644 index 00000000000..2e6bb914ae7 --- /dev/null +++ b/mozilla/widget/tests/Scribble.cpp @@ -0,0 +1,547 @@ +/* -*- 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 +#include +#include + +#include "nsIButton.h" +#include "nsICheckButton.h" +#include "nsIRadioButton.h" +#include "nsIRadioGroup.h" +#include "nsITextWidget.h" +#include "nsIScrollbar.h" +#include "nsGUIEvent.h" +#include "nsIEnumerator.h" +#include "nsIRenderingContext.h" +#include "nsIPresContext.h" +#include "nsFont.h" +#include "nsUnitConversion.h" +#include "nsColor.h" +#include "nsString.h" +#include "Scribble.h" +#include "nsIDeviceContext.h" +#include "nsTransform2D.h" +#include "nsGfxCIID.h" +#include "nsWidgetsCID.h" + +ScribbleApp scribbleData; + + +static NS_DEFINE_IID(kIWidgetIID, NS_IWIDGET_IID); +static NS_DEFINE_IID(kIButtonIID, NS_IBUTTON_IID); +static NS_DEFINE_IID(kIScrollbarIID, NS_ISCROLLBAR_IID); +static NS_DEFINE_IID(kICheckButtonIID, NS_ICHECKBUTTON_IID); +static NS_DEFINE_IID(kITextWidgetIID, NS_ITEXTWIDGET_IID); +static NS_DEFINE_IID(kIRadioButtonIID, NS_IRADIOBUTTON_IID); +static NS_DEFINE_IID(kIRadioGroupIID, NS_IRADIOGROUP_IID); + + +// +// Main window events +// +nsEventStatus PR_CALLBACK HandleEventMain(nsGUIEvent *aEvent) +{ + + printf("aEvent->message %d on 0x%X\n", aEvent->message, aEvent->widget); + + nsEventStatus result = nsEventStatus_eConsumeNoDefault; + switch(aEvent->message) { + + case NS_SIZE: + { + nsIEnumerator *enumer = aEvent->widget->GetChildren(); + if (enumer) { + nsISupports *next; + next = enumer->Next(); + if (next) { + nsIWidget *widget; + if (NS_OK == next->QueryInterface(kIWidgetIID, (void**)&widget)) { + widget->Resize(0, 0, 200, ((nsSizeEvent*)aEvent)->windowSize->height - 26); + NS_RELEASE(widget); + } + } + + NS_RELEASE(enumer); + delete enumer; + } + + scribbleData.drawPane->Resize(200, + 0, + ((nsSizeEvent*)aEvent)->windowSize->width - 206, + ((nsSizeEvent*)aEvent)->windowSize->height - 26); + + break; + } + + case NS_DESTROY: + printf("Destroy Window...Release window\n"); + NS_RELEASE(scribbleData.red); + NS_RELEASE(scribbleData.green); + NS_RELEASE(scribbleData.blue); + NS_RELEASE(scribbleData.scribble); + NS_RELEASE(scribbleData.lines); + NS_RELEASE(scribbleData.group); + // NS_RELEASE(scribbleData.drawPane); + // NS_RELEASE(scribbleData.mainWindow); + + exit(0); // for now + break; + + default: + result = nsEventStatus_eIgnore; + } + + return result; +} + + +// +// Control pane events +// +nsEventStatus PR_CALLBACK HandleEventControlPane(nsGUIEvent *aEvent) +{ + printf("aEvent->message %d on 0x%X\n", aEvent->message, aEvent->widget); + + nsEventStatus result = nsEventStatus_eConsumeNoDefault; + switch(aEvent->message) { + case NS_PAINT: + { + // paint the background + nsIRenderingContext *drawCtx = ((nsPaintEvent*)aEvent)->renderingContext; + drawCtx->SetColor(aEvent->widget->GetBackgroundColor()); + drawCtx->FillRect(*(((nsPaintEvent*)aEvent)->rect)); + + // draw the line separating the two panes + drawCtx->SetColor(aEvent->widget->GetForegroundColor()); + drawCtx->DrawLine(198, 0, 198, 800); + drawCtx->DrawLine(199, 0, 199, 800); + drawCtx->DrawLine(200, 0, 200, 800); + + // draw the colors text + nsFont font("Times", NS_FONT_STYLE_NORMAL, + NS_FONT_VARIANT_NORMAL, + NS_FONT_WEIGHT_BOLD, + 0, + 12); + drawCtx->SetFont(font); + + nsString red("Red"); + drawCtx->SetColor(NS_RGB(255, 0, 0)); + drawCtx->DrawString(red, 50, 351, 50); + + nsString green("Green"); + drawCtx->SetColor(NS_RGB(0, 255, 0)); + drawCtx->DrawString(green, 50, 372, 50); + + nsString blue("Blue"); + drawCtx->SetColor(NS_RGB(0, 0, 255)); + drawCtx->DrawString(blue, 50, 393, 50); + + return nsEventStatus_eConsumeNoDefault; + } + } + + return nsEventStatus_eIgnore; +} + + +// +// Graphic pane events +// +nsEventStatus PR_CALLBACK HandleEventGraphicPane(nsGUIEvent *aEvent) +{ + printf("aEvent->message %d on 0x%X\n", aEvent->message, aEvent->widget); + + nsEventStatus result = nsEventStatus_eConsumeNoDefault; + switch(aEvent->message) { + + case NS_PAINT: + { + nsIRenderingContext *drawCtx = ((nsPaintEvent*)aEvent)->renderingContext; + drawCtx->SetColor(aEvent->widget->GetBackgroundColor()); + drawCtx->FillRect(*(((nsPaintEvent*)aEvent)->rect)); + + return nsEventStatus_eConsumeNoDefault; + } + + case NS_MOUSE_LEFT_BUTTON_DOWN: + aEvent->widget->SetFocus(); + scribbleData.isDrawing = PR_TRUE; + scribbleData.mousePos = ((nsGUIEvent*)aEvent)->point; + return nsEventStatus_eConsumeNoDefault; + + case NS_MOUSE_LEFT_BUTTON_UP: + scribbleData.isDrawing = PR_FALSE; + return nsEventStatus_eConsumeNoDefault; + + case NS_MOUSE_MOVE: + { + if (scribbleData.isDrawing) { + nsIRenderingContext *drawCtx = aEvent->widget->GetRenderingContext(); + drawCtx->SetColor(aEvent->widget->GetForegroundColor()); + drawCtx->DrawLine(scribbleData.mousePos.x, + scribbleData.mousePos.y, + ((nsGUIEvent*)aEvent)->point.x, + ((nsGUIEvent*)aEvent)->point.y); + + if (scribbleData.scribble->GetState()) + scribbleData.mousePos = ((nsGUIEvent*)aEvent)->point; + + + NS_RELEASE(drawCtx); + } + + return nsEventStatus_eConsumeNoDefault; + } + + } + + return nsEventStatus_eIgnore; +} + + +// +// Buttons events +// +nsEventStatus PR_CALLBACK HandleEventButton(nsGUIEvent *aEvent) +{ + printf("aEvent->message %d on 0x%X\n", aEvent->message, aEvent->widget); + + switch(aEvent->message) { + case NS_MOUSE_LEFT_BUTTON_UP: + scribbleData.drawPane->Invalidate(PR_TRUE); + } + + return nsEventStatus_eIgnore; +} + + + +// +// Handle events for the auto-mode (rectangles/circles) +// +nsEventStatus PR_CALLBACK HandleEventCheck(nsGUIEvent *aEvent) +{ + printf("aEvent->message %d on 0x%X\n", aEvent->message, aEvent->widget); + printf("aEvent->message %d == %d on 0x%X\n", aEvent->message, NS_MOUSE_LEFT_BUTTON_UP, aEvent->widget); + + switch(aEvent->message) { + case NS_MOUSE_LEFT_BUTTON_UP: + { + nsICheckButton *option; + + if (NS_OK == aEvent->widget->QueryInterface(kICheckButtonIID, (void**)&option)) { + // invert the two checkboxes state + PRBool state = option->GetState(); + option->SetState((state) ? PR_FALSE : PR_TRUE); + + if (state == PR_FALSE) { + nsAutoString buf; + option->GetLabel(buf); + + nsIRenderingContext *drawCtx = scribbleData.drawPane->GetRenderingContext(); + + // + srand(aEvent->time); + if (drawCtx) { + + // a sort of random rect + nsRect rect; + scribbleData.drawPane->GetBounds(rect); + nscoord width = rect.width; + nscoord height = rect.height; + + nsString circles("Circles"); + nsString rects("Rectangles"); + if (buf.Equals(circles)) { + for (int i = 0; i < 100; i++) { + drawCtx->SetColor((nscolor)rand()); + + rect.MoveTo(rand() % width, rand() % height); + rect.SizeTo(rand() % (width - rect.x), + rand() % (height - rect.y)); + drawCtx->DrawEllipse(rect); + } + } + else if (buf.Equals(rects)) { + for (int i = 0; i < 100; i++) { + drawCtx->SetColor((nscolor)rand()); + + rect.MoveTo(rand() % width, rand() % height); + rect.SizeTo(rand() % (width - rect.x), + rand() % (height - rect.y)); + drawCtx->DrawRect(rect); + } + } + + NS_RELEASE(drawCtx); + } + } + } + + } + } + + return nsEventStatus_eIgnore; +} + + +// +// Handle events for the text fields +// +nsEventStatus PR_CALLBACK HandleEventText(nsGUIEvent *aEvent) +{ + printf("aEvent->message %d on 0x%X\n", aEvent->message, aEvent->widget); + + switch(aEvent->message) { + case NS_LOSTFOCUS: + { + nscolor color = scribbleData.drawPane->GetForegroundColor(); + nsAutoString buf; + + nsITextWidget *text; + if (NS_OK == aEvent->widget->QueryInterface(kITextWidgetIID, (void**)&text)) { + if (text == scribbleData.red) { + scribbleData.red->GetText(buf, 0); + PRInt32 value, err; + value = buf.ToInteger(&err); + color = NS_RGB(value, NS_GET_G(color), NS_GET_B(color)); + } + else if (text == scribbleData.green) { + scribbleData.green->GetText(buf, 0); + PRInt32 value, err; + value = buf.ToInteger(&err); + color = NS_RGB(NS_GET_R(color), value, NS_GET_B(color)); + } + else if (text == scribbleData.blue) { + scribbleData.blue->GetText(buf, 0); + PRInt32 value, err; + value = buf.ToInteger(&err); + color = NS_RGB(NS_GET_R(color), NS_GET_G(color), value); + } + + NS_RELEASE(text); + } + + scribbleData.drawPane->SetForegroundColor(color); + + return nsEventStatus_eIgnore; + } + } + + return nsEventStatus_eIgnore; +} + +#define WIDGET_DLL "raptorwidget.dll" +#define GFXWIN_DLL "raptorgfxwin.dll" + +// +// Main application entry function +// +void CreateApplication() +{ + scribbleData.isDrawing = PR_FALSE; + + // register graphics classes + static NS_DEFINE_IID(kCRenderingContextIID, NS_RENDERING_CONTEXT_CID); + static NS_DEFINE_IID(kCDeviceContextIID, NS_DEVICE_CONTEXT_CID); + static NS_DEFINE_IID(kCFontMetricsIID, NS_FONT_METRICS_CID); + static NS_DEFINE_IID(kCImageIID, NS_IMAGE_CID); + + NSRepository::RegisterFactory(kCRenderingContextIID, GFXWIN_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCDeviceContextIID, GFXWIN_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCFontMetricsIID, GFXWIN_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCImageIID, GFXWIN_DLL, PR_FALSE, PR_FALSE); + + // register widget classes + static NS_DEFINE_IID(kCWindowCID, NS_WINDOW_CID); + static NS_DEFINE_IID(kCChildCID, NS_CHILD_CID); + static NS_DEFINE_IID(kCButtonCID, NS_BUTTON_CID); + static NS_DEFINE_IID(kCCheckButtonCID, NS_CHECKBUTTON_CID); + static NS_DEFINE_IID(kCComboBoxCID, NS_COMBOBOX_CID); + static NS_DEFINE_IID(kCFileWidgetCID, NS_FILEWIDGET_CID); + static NS_DEFINE_IID(kCListBoxCID, NS_LISTBOX_CID); + static NS_DEFINE_IID(kCRadioButtonCID, NS_RADIOBUTTON_CID); + static NS_DEFINE_IID(kCRadioGroupCID, NS_RADIOGROUP_CID); + static NS_DEFINE_IID(kCHorzScrollbarCID, NS_HORZSCROLLBAR_CID); + static NS_DEFINE_IID(kCVertScrollbarCID, NS_VERTSCROLLBAR_CID); + static NS_DEFINE_IID(kCTextAreaCID, NS_TEXTAREA_CID); + static NS_DEFINE_IID(kCTextFieldCID, NS_TEXTFIELD_CID); + + NSRepository::RegisterFactory(kCWindowCID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCChildCID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCButtonCID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCCheckButtonCID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCComboBoxCID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCFileWidgetCID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCListBoxCID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCRadioButtonCID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCRadioGroupCID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCHorzScrollbarCID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCVertScrollbarCID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCTextAreaCID, WIDGET_DLL, PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCTextFieldCID, WIDGET_DLL, PR_FALSE, PR_FALSE); + + //NS_InitToolkit(PR_GetCurrentThread()); + + nsresult res; + + static NS_DEFINE_IID(kDeviceContextCID, NS_DEVICE_CONTEXT_CID); + static NS_DEFINE_IID(kDeviceContextIID, NS_IDEVICE_CONTEXT_IID); + + res = NSRepository::CreateInstance(kDeviceContextCID, nsnull, kDeviceContextIID, (void **)&scribbleData.mContext); + + if (NS_OK == res) + scribbleData.mContext->Init(); + + // + // create the main window + // + NSRepository::CreateInstance(kCWindowCID, nsnull, kIWidgetIID, (LPVOID*)&(scribbleData.mainWindow)); + nsRect rect(100, 100, 600, 600); + scribbleData.mainWindow->Create((nsIWidget*)NULL, rect, HandleEventMain, NULL); + + // + // create the control pane + // + nsIWidget *controlPane; + rect.SetRect(0, 0, 200, 580); + NSRepository::CreateInstance(kCChildCID, nsnull, kIWidgetIID, (LPVOID*)&controlPane); + controlPane->Create(scribbleData.mainWindow, rect, HandleEventControlPane, NULL); + + // + // Add the scribble/lines section + // + + // + // create a Radio Group + // + NSRepository::CreateInstance(kCRadioGroupCID, nsnull, kIRadioGroupIID, (LPVOID*)&(scribbleData.group)); + scribbleData.group->SetName(nsString("Group1")); + + // create the "Scribble" check button + rect.SetRect(50, 50, 100, 25); + + NSRepository::CreateInstance(kCRadioButtonCID, nsnull, kIRadioButtonIID, (LPVOID*)&(scribbleData.scribble)); + scribbleData.scribble->SetRadioGroup(scribbleData.group); + scribbleData.scribble->Create(controlPane, rect, NULL, NULL); + nsString cbLabel("Scribble"); + scribbleData.scribble->SetLabel(cbLabel); + scribbleData.scribble->SetState(PR_FALSE); + //scribbleData.scribble->SetBackgroundColor(NS_RGB(255, 255, 255)); + scribbleData.scribble->Show(PR_TRUE); + + // create the "Lines" check button + rect.SetRect(50, 75, 100, 25); + + NSRepository::CreateInstance(kCRadioButtonCID, nsnull, kIRadioButtonIID, (LPVOID*)&(scribbleData.lines)); + scribbleData.lines->SetRadioGroup(scribbleData.group); + scribbleData.lines->Create(controlPane, rect, NULL, NULL); + nsString cbLabel1("Lines"); + scribbleData.lines->SetLabel(cbLabel1); + scribbleData.lines->SetState(PR_TRUE); + //scribbleData.lines->SetBackgroundColor(NS_RGB(255, 255, 255)); + scribbleData.lines->Show(PR_TRUE); + // + // Add the circle/rectangle section + // + + // create the "Circles" check button + nsICheckButton * checkButton; + rect.SetRect(50, 200, 100, 25); + + NSRepository::CreateInstance(kCCheckButtonCID, nsnull, kICheckButtonIID, (LPVOID*)&checkButton); + checkButton->Create(controlPane, rect, HandleEventCheck, NULL); + nsString cbLabel2("Circles"); + checkButton->SetLabel(cbLabel2); + checkButton->SetBackgroundColor(NS_RGB(255, 255, 255)); + checkButton->Show(PR_TRUE); + NS_RELEASE(checkButton); + + // create the "Rectangles" check button + rect.SetRect(50, 225, 100, 25); + + NSRepository::CreateInstance(kCCheckButtonCID, nsnull, kICheckButtonIID, (LPVOID*)&checkButton); + checkButton->Create(controlPane, rect, HandleEventCheck, NULL); + nsString cbLabel3("Rectangles"); + checkButton->SetLabel(cbLabel3); + checkButton->SetBackgroundColor(NS_RGB(255, 255, 255)); + checkButton->Show(PR_TRUE); + NS_RELEASE(checkButton); + + // + // Add the color section + // + + // create the "red" text widget + rect.SetRect(100, 350, 50, 22); + + NSRepository::CreateInstance(kCTextFieldCID, nsnull, kITextWidgetIID, (LPVOID*)&(scribbleData.red)); + scribbleData.red->Create(controlPane, rect, HandleEventText, NULL); + nsString initText("0"); + scribbleData.red->SetText(initText); + scribbleData.red->SetBackgroundColor(NS_RGB(0, 0, 255)); + scribbleData.red->Show(PR_TRUE); + + // create the "green" text widget + rect.SetRect(100, 371, 50, 22); + + NSRepository::CreateInstance(kCTextFieldCID, nsnull, kITextWidgetIID, (LPVOID*)&(scribbleData.green)); + scribbleData.green->Create(controlPane, rect, HandleEventText, NULL); + scribbleData.green->SetText(initText); + scribbleData.green->SetBackgroundColor(NS_RGB(255, 0, 0)); + scribbleData.green->Show(PR_TRUE); + + // create the "blue" text widget + rect.SetRect(100, 392, 50, 22); + + NSRepository::CreateInstance(kCTextFieldCID, nsnull, kITextWidgetIID, (LPVOID*)&(scribbleData.blue)); + scribbleData.blue->Create(controlPane, rect, HandleEventText, NULL); + scribbleData.blue->SetText(initText); + scribbleData.blue->SetBackgroundColor(NS_RGB(0, 255, 0)); + scribbleData.blue->Show(PR_TRUE); + + // + // create a button + // + nsIButton *button; + rect.SetRect(50, 500, 100, 25); + NSRepository::CreateInstance(kCButtonCID, nsnull, kIButtonIID, (LPVOID*)&button); + button->Create(controlPane, rect, HandleEventButton, NULL); + nsString label("Clear"); + button->SetLabel(label); + button->Show(PR_TRUE); + NS_RELEASE(button); + + NS_RELEASE(controlPane); // the parent keeps a reference on this child + + // + // create the draw pane + // + rect.SetRect(200, 0, 400, 580); + NSRepository::CreateInstance(kCChildCID, nsnull, kIWidgetIID, (LPVOID*)&scribbleData.drawPane); + scribbleData.drawPane->Create(scribbleData.mainWindow, rect, HandleEventGraphicPane, NULL); + + // + // show. We are in business... + // + scribbleData.mainWindow->Show(PR_TRUE); + +} + diff --git a/mozilla/widget/tests/Scribble.h b/mozilla/widget/tests/Scribble.h new file mode 100644 index 00000000000..47cdf47768e --- /dev/null +++ b/mozilla/widget/tests/Scribble.h @@ -0,0 +1,54 @@ +/* -*- 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. + */ + +#ifndef Scribble_h__ +#define Scribble_h__ + +#include "nsIWidget.h" +#include "nsIRadioButton.h" +#include "nsIRadioGroup.h" +#include "nsITextWidget.h" +#include "nsPoint.h" +#include "nsIDeviceContext.h" + +struct ScribbleApp { + nsIWidget *mainWindow; + nsIWidget *drawPane; + + nsITextWidget *red; + nsITextWidget *green; + nsITextWidget *blue; + + nsIRadioGroup *group; + nsIRadioButton *scribble; + nsIRadioButton *lines; + + PRBool isDrawing; + + nsPoint mousePos; + + nsIDeviceContext *mContext; +}; + + +void CreateApplication(); + +#endif + + + diff --git a/mozilla/widget/tests/main.cpp b/mozilla/widget/tests/main.cpp new file mode 100644 index 00000000000..f9b02d732a9 --- /dev/null +++ b/mozilla/widget/tests/main.cpp @@ -0,0 +1,46 @@ +/* -*- 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 "Scribble.h" + +#ifdef XP_PC + +#include + +int WINAPI WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpszCmdLine, + int nCmdShow) +{ + CreateApplication(); + + // Process messages + MSG msg; + while (GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return msg.wParam; +} + +void main(int argc, char **argv) +{ + WinMain(GetModuleHandle(NULL), NULL, 0, SW_SHOW); +} + +#endif + diff --git a/mozilla/widget/tests/makefile.win b/mozilla/widget/tests/makefile.win new file mode 100644 index 00000000000..fb157302d35 --- /dev/null +++ b/mozilla/widget/tests/makefile.win @@ -0,0 +1,52 @@ +#!nmake +# +# 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. + +DEPTH=..\.. +IGNORE_MANIFEST=1 + +DIRS = windows + +MAKE_OBJ_TYPE = EXE +PROGRAM = .\$(OBJDIR)\scribble.exe +#RESFILE = scribble.res + +OBJS = \ + .\$(OBJDIR)\main.obj \ + .\$(OBJDIR)\Scribble.obj \ + $(NULL) + +LINCS=-I$(PUBLIC)\raptor -I$(PUBLIC)\xpcom + +MYLIBS= \ + $(DIST)\lib\xpcom32.lib \ + $(LIBNSPR) \ + $(DIST)\lib\raptorbase.lib \ + $(DIST)\lib\raptorgfx.lib \ + $(NULL) + +LLIBS= $(MYLIBS) \ + -SUBSYSTEM:CONSOLE + +include <$(DEPTH)\config\rules.mak> + +install:: $(PROGRAM) + $(MAKE_INSTALL) $(PROGRAM) $(DIST)\bin + +clobber:: + rm -f $(DIST)\bin\scribble.exe + +$(PROGRAM):: $(OBJS) $(MYLIBS) diff --git a/mozilla/widget/tests/windows/makefile.win b/mozilla/widget/tests/windows/makefile.win new file mode 100644 index 00000000000..41ffcdf4372 --- /dev/null +++ b/mozilla/widget/tests/windows/makefile.win @@ -0,0 +1,49 @@ +#!nmake +# +# 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. + +DEPTH=..\..\.. + +MAKE_OBJ_TYPE = EXE +PROGRAM = .\$(OBJDIR)\widget.exe +#RESFILE = widget.res + +OBJS = \ + .\$(OBJDIR)\winmain.obj \ + $(NULL) + +LINCS=-I$(PUBLIC)\raptor \ + -I$(PUBLIC)\xpcom -I\ns\raptor\ui\src\windows + +MYLIBS= \ + $(DIST)\lib\xpcom32.lib \ + $(LIBNSPR) \ + $(DIST)\lib\raptorbase.lib \ + $(DIST)\lib\raptorgfx.lib \ + $(NULL) + +LLIBS= $(MYLIBS) \ + -SUBSYSTEM:CONSOLE + +include <$(DEPTH)\config\rules.mak> + +install:: $(PROGRAM) + $(MAKE_INSTALL) $(PROGRAM) $(DIST)\bin + +clobber:: + rm -f $(DIST)\bin\widget.exe + +$(PROGRAM):: $(OBJS) $(MYLIBS) diff --git a/mozilla/widget/tests/windows/winmain.cpp b/mozilla/widget/tests/windows/winmain.cpp new file mode 100644 index 00000000000..e9efa814150 --- /dev/null +++ b/mozilla/widget/tests/windows/winmain.cpp @@ -0,0 +1,1194 @@ +/* -*- 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 +#include +#include + +//---- Factory Includes & Stuff -----// +#include "nsIFactory.h" +#include "nsRepository.h" +#include "nsGfxCIID.h" + +#include "nsWidgetsCID.h" + + +#include "nsIWidget.h" +#include "nsIButton.h" +#include "nsICheckButton.h" +#include "nsIRadioButton.h" +#include "nsIRadioGroup.h" +#include "nsIScrollbar.h" +#include "nsITextWidget.h" +#include "nsITextAreaWidget.h" +#include "nsGUIEvent.h" +#include "nsIEnumerator.h" +#include "nsString.h" +#include "nsRect.h" +#include "nsIRenderingContext.h" +#include "nsIListBox.h" +#include "nsIComboBox.h" +#include "nsIFileWidget.h" +#include "nsIDeviceContext.h" +#include "nsFont.h" +#include "nsRepository.h" +#include "nsWidgetsCID.h" + +#include + +char * gLogFileName = "selftest.txt"; +FILE * gFD = nsnull; +PRInt32 gOverallStatus = 0; +PRInt32 gNonVisualStatus = 0; + +nsIWidget *window = NULL; +nsITextWidget *statusText = NULL; +nsITextWidget *textWidgetInstance = NULL; +nsITextWidget *passwordText = NULL; + +nsIListWidget *comboBox = NULL; +nsIListWidget *listBox = NULL; +nsIListBox *gMultiListBox = NULL; + +nsIWidget *movingWidget = NULL; +nsIScrollbar *scrollbar = NULL; + +char * gFailedMsg = NULL; + + + +#define WIDGET_DLL "raptorwidget.dll" +#define GFXWIN_DLL "raptorgfxwin.dll" + +#define DEBUG_MOUSE 0 + +#define NUM_COMBOBOX_ITEMS 8 +#define kSetCaret "Set Caret" +#define kGetCaret "Get Caret" +#define kSetSelection "Set Selection" +#define kRemoveSelection "Remove Selection" +#define kSetText "Set Text" +#define kGetText "Get Text" +#define kHideBtn "Hide Btn" +#define kShowBtn "Show Btn" +#define kBrowseBtn "Browse..." + +// class ids +static NS_DEFINE_IID(kCWindowCID, NS_WINDOW_CID); +static NS_DEFINE_IID(kCChildCID, NS_CHILD_CID); +static NS_DEFINE_IID(kCButtonCID, NS_BUTTON_CID); +static NS_DEFINE_IID(kCCheckButtonCID, NS_CHECKBUTTON_CID); +static NS_DEFINE_IID(kCComboBoxCID, NS_COMBOBOX_CID); +static NS_DEFINE_IID(kCFileWidgetCID, NS_FILEWIDGET_CID); +static NS_DEFINE_IID(kCListBoxCID, NS_LISTBOX_CID); +static NS_DEFINE_IID(kCRadioButtonCID, NS_RADIOBUTTON_CID); +static NS_DEFINE_IID(kCRadioGroupCID, NS_RADIOGROUP_CID); +static NS_DEFINE_IID(kCHorzScrollbarCID, NS_HORZSCROLLBAR_CID); +static NS_DEFINE_IID(kCVertScrollbarCID, NS_VERTSCROLLBAR_CID); +static NS_DEFINE_IID(kCTextAreaCID, NS_TEXTAREA_CID); +static NS_DEFINE_IID(kCTextFieldCID, NS_TEXTFIELD_CID); + +// interface ids +static NS_DEFINE_IID(kIWidgetIID, NS_IWIDGET_IID); +static NS_DEFINE_IID(kIButtonIID, NS_IBUTTON_IID); +static NS_DEFINE_IID(kIScrollbarIID, NS_ISCROLLBAR_IID); +static NS_DEFINE_IID(kICheckButtonIID, NS_ICHECKBUTTON_IID); +static NS_DEFINE_IID(kITextWidgetIID, NS_ITEXTWIDGET_IID); +static NS_DEFINE_IID(kITextAreaWidgetIID, NS_ITEXTAREAWIDGET_IID); +static NS_DEFINE_IID(kIRadioButtonIID, NS_IRADIOBUTTON_IID); +static NS_DEFINE_IID(kIRadioGroupIID, NS_IRADIOGROUP_IID); +static NS_DEFINE_IID(kIListBoxIID, NS_ILISTBOX_IID); +static NS_DEFINE_IID(kIComboBoxIID, NS_ICOMBOBOX_IID); +static NS_DEFINE_IID(kIFileWidgetIID, NS_IFILEWIDGET_IID); + + +char * eval(PRInt32 aVal) { + if (!aVal) { + gOverallStatus++; + } + return aVal? "PASSED":"FAILED"; +} + +char * eval(PRUint32 aVal) { + if (!aVal) { + gOverallStatus++; + } + + return aVal ? "PASSED":"FAILED"; +} + +char * eval(PRBool aVal) { + if (!aVal) { + gOverallStatus++; + } + return aVal ? "PASSED":"FAILED"; +} + +/**-------------------------------------------------------------------------------- + * Generic ListWidget Box Non-Visual Test + *-------------------------------------------------------------------------------- + */ +void listSelfTest(FILE * fd, char * aTitle, nsIListWidget * listBox) { + fprintf(fd, "\n\n-----------------------------\n"); + fprintf(fd, "%s self test\n", aTitle); + fprintf(fd, "-----------------------------\n\n"); + + int inx = 4; + char * item4 = "List Item 4"; + + fprintf(fd, "\nTesting GetItemCount\n\tItem count should be [%d] is [%d] Test: [%s]\n", NUM_COMBOBOX_ITEMS, listBox->GetItemCount(), + (NUM_COMBOBOX_ITEMS == (int)listBox->GetItemCount()?"PASSED":"FAILED")); + + listBox->SelectItem(inx); + nsAutoString buf; + listBox->GetSelectedItem(buf); + char * selStr = buf.ToNewCString(); + int sel = listBox->GetSelectedIndex(); + fprintf(fd, "\nTesting GetSelectedItem\n\tSelection should be %d item[%s] index[%d] Test: [%s]\n", inx, selStr, sel, + eval(inx == (int)sel)); + if (nsnull != selStr) delete selStr; + + listBox->GetItemAt(buf, 4); + selStr = buf.ToNewCString(); + fprintf(fd, "\nTesting GetItemAt\n\tItem %d should be [%s] is [%s] Test: [%s]\n", inx, item4, selStr, eval(strcmp(selStr, item4) == 0)); + if (nsnull != selStr) delete selStr; + + listBox->SelectItem(2); + inx = listBox->GetSelectedIndex(); + fprintf(fd, "\nTesting SelectItem && GetSelectedIndex\n\t Selected Item should be [%d] is [%d] Test: [%s]\n", 2, inx, eval(inx == 2)); + + for (int i=0;i<(int)listBox->GetItemCount();i++) { + nsAutoString buf; + listBox->GetItemAt(buf, i); + char * str = buf.ToNewCString(); + + fprintf(fd, "Item %d [%s]\n", i, str); + + if (nsnull != str) delete str; + } + fprintf(fd, "Removing Item #4\n"); + listBox->RemoveItemAt(4); + fprintf(fd, "\nTesting RemoveItemAt\n\tTest: [%s]\n", eval(-1 == (int)listBox->FindItem(nsString(item4), 0))); + + for (i=0;i<(int)listBox->GetItemCount();i++) { + nsAutoString buf; + listBox->GetItemAt(buf, i); + char * str = buf.ToNewCString(); + + fprintf(fd, "Item %d [%s]\n", i, str); + + if (nsnull != str) delete str; + } + listBox->Deselect(); + fprintf(fd, "\nTesting Deselect\n\t Selected Item [%d] Test:[%s]\n", (int)listBox->GetSelectedIndex(), (-1 == (int)listBox->GetSelectedIndex()?"PASSED":"FAILED")); + +} + +/**-------------------------------------------------------------------------------- + * Generic ListWidget Box Non-Visual Test + *-------------------------------------------------------------------------------- + */ +void textShelfTest(FILE * fd, char * aTitle, nsITextWidget * aTextWidget) { + fprintf(fd, "\n\n-----------------------------\n"); + fprintf(fd, "%s self test\n", aTitle); + fprintf(fd, "-----------------------------\n\n"); + + aTextWidget->SetText(nsString("1234567890")); + PRUint32 start = 1; + PRUint32 end = 5; + aTextWidget->SetSelection(start, end); + + PRUint32 start2 = 0; + PRUint32 end2 = 0; + aTextWidget->GetSelection(&start2, &end2); + + fprintf(fd, "Tested SetSelection and GetSelection Test %s\n", eval(start == start2 && end == end2)); + + start = 5; + aTextWidget->SetCaretPosition(start); + + start2 = aTextWidget->GetCaretPosition(); + + fprintf(fd, "Tested SetCaretPosition and GetCaretPosition Test %s\n", eval(start == start2)); + aTextWidget->InsertText(nsString("xxx"),1,3); + nsString str; + aTextWidget->GetText(str,256); + //fprintf(fd, "Tested InsertText Test %s\n", eval(start == start2)); + char * s = str.ToNewCString(); + fprintf(fd, "Tested InsertText Test %s\n", s); + delete s; + +} + +/**-------------------------------------------------------------------------------- + * Generic MultiListWidget Box Non-Visual Test + *-------------------------------------------------------------------------------- + */ +void multiListSelfTest(FILE * fd, char * aTitle, nsIListWidget * listBox) { + fprintf(fd, "\n\n-----------------------------\n"); + fprintf(fd, "%s self test\n", aTitle); + fprintf(fd, "-----------------------------\n\n"); + + nsIListBox * multi = (nsIListBox*)listBox; + + int inx = 4; + char * item4 = "List Item 4"; + + nsAutoString buf; + char * selStr; + + multi->GetItemAt(buf, 4); + selStr = buf.ToNewCString(); + fprintf(fd, "\nTesting GetItemAt\n\tItem %d should be [%s] is [%s] Test: [%s]\n", inx, item4, selStr, + eval(strcmp(selStr, item4) == 0)); + if (nsnull != selStr) delete selStr; + + + multi->Deselect(); + int count = multi->GetSelectedCount(); + fprintf(fd, "\nTesting Deselect\n\tCount %d Test: [%s]\n", count, eval(0 == count)); + + PRInt32 inxs[] = {0,2,4}; + PRInt32 len = 3; + + for (int i=0;iSelectItem(inxs[i]); + } + + int status = 1; + count = multi->GetSelectedCount(); + fprintf(fd, "\nTesting GetSelectedCount\n\tCount [%d] should be [%d] Test: [%s]\n", count, len, + eval(len == count)); + + if (count == len) { + PRInt32 indices[256]; + multi->GetSelectedIndices(indices, 256); + for (i=0;iGetSelectedCount())); + } + + for (i=0;i<(int)multi->GetItemCount();i++) { + nsAutoString buf; + multi->GetItemAt(buf, i); + char * str = buf.ToNewCString(); + + fprintf(fd, "Item %d [%s]\n", i, str); + + if (nsnull != str) delete str; + } + fprintf(fd, "Removing Item #4\n"); + multi->RemoveItemAt(4); + fprintf(fd, "\nTesting RemoveItemAt\n\tTest: [%s]\n", eval(-1 == (int)multi->FindItem(nsString(item4), 0))); + + for (i=0;i<(int)multi->GetItemCount();i++) { + nsAutoString buf; + multi->GetItemAt(buf, i); + char * str = buf.ToNewCString(); + + fprintf(fd, "Item %d [%s]\n", i, str); + + if (nsnull != str) delete str; + } + +} + +/**-------------------------------------------------------------------------------- + * + */ +int createTestButton(nsIWidget * aWin, + char * aTitle, + int aX, + int aY, + int aWidth, + EVENT_CALLBACK aHandleEventFunction) { + nsIButton *button; + nsRect rect(aX, aY, aWidth, 25); + NSRepository::CreateInstance(kCButtonCID, nsnull, kIButtonIID, (LPVOID*)&button); + button->Create(window, rect, aHandleEventFunction, NULL); + nsString label(aTitle); + button->SetLabel(label); + button->Show(PR_TRUE); + NS_RELEASE(button); + return aX + aWidth; +} + +/**-------------------------------------------------------------------------------- + * List Test Handler + *-------------------------------------------------------------------------------- + */ +nsEventStatus PR_CALLBACK GenericListHandleEvent(nsGUIEvent *aEvent, char * aTitle, nsIListWidget * aListWidget) +{ + + nsIButton * btn; + if (aEvent->message != NS_MOUSE_LEFT_BUTTON_UP) { + return nsEventStatus_eIgnore; + } + nsString str(aTitle); + fprintf(gFD, "\nVisually tested nsIListWidget\n"); + + if (NS_OK == aEvent->widget->QueryInterface(kIButtonIID, (void**)&btn)) { + nsAutoString strBuf; + btn->GetLabel(strBuf); + char * title = strBuf.ToNewCString(); + //fprintf(gFD, "Title is [%s]\n", title); + + if (!strcmp(title, kSetSelection)) { + aListWidget->SelectItem(2); + fprintf(gFD, "\tTested SelectItem(2)\n"); + str.Append(" should show 'List Item 2'"); + statusText->SetText(str); + gFailedMsg = "List::SelectItem"; + } else if (!strcmp(title, kRemoveSelection)) { + PRInt32 inx = aListWidget->FindItem(nsString("List Item 2"), 0); + + if (inx > -1) { + aListWidget->RemoveItemAt(inx); + } + fprintf(gFD, "\tTested FindItem(...)\n"); + str.Append(" should show empty"); + statusText->SetText(str); + gFailedMsg = "List::RemoveItemAt && FindItem"; + } + delete title; + NS_RELEASE(btn); + } + return nsEventStatus_eIgnore; +} + +/**-------------------------------------------------------------------------------- + * Combox Test Handler + *-------------------------------------------------------------------------------- + */ +nsEventStatus PR_CALLBACK ComboTestHandleEvent(nsGUIEvent *aEvent) +{ + return GenericListHandleEvent(aEvent, "ComboBox", comboBox); +} + + +/**-------------------------------------------------------------------------------- + * ListBox Test Handler + *-------------------------------------------------------------------------------- + */ +nsEventStatus PR_CALLBACK ListBoxTestHandleEvent(nsGUIEvent *aEvent) +{ + return GenericListHandleEvent(aEvent, "ListBox", listBox); +} + +/**-------------------------------------------------------------------------------- + * Multi-ListBox Test Handler + *-------------------------------------------------------------------------------- + */ +nsEventStatus PR_CALLBACK MultiListBoxTestHandleEvent(nsGUIEvent *aEvent) +{ + nsIButton * btn; + if (aEvent->message != NS_MOUSE_LEFT_BUTTON_UP) { + return nsEventStatus_eIgnore; + } + nsString str("Multi-ListBox"); + fprintf(gFD, "\nVisually tested Multi-List Box\n"); + + if (NS_OK == aEvent->widget->QueryInterface(kIButtonIID, (void**)&btn)) { + nsAutoString strBuf; + btn->GetLabel(strBuf); + char * title = strBuf.ToNewCString(); + //fprintf(gFD, "Title is [%s]\n", title); + + if (!strcmp(title, kSetSelection)) { + gMultiListBox->Deselect(); + + PRInt32 inxs[] = {0,2,4}; + PRInt32 len = 3; + + for (int i=0;iSelectItem(inxs[i]); + } + fprintf(gFD, "\tTested SelectItem()\n"); + str.Append(" should show 'List Item 0,2,5'"); + statusText->SetText(str); + gFailedMsg = "Multi-List::SelectItem"; + } else if (!strcmp(title, kRemoveSelection)) { + PRInt32 inx = gMultiListBox->FindItem(nsString("List Item 2"), 0); + + if (inx > -1) { + gMultiListBox->RemoveItemAt(inx); + } + fprintf(gFD, "\tTested FindItem(...)\n"); + str.Append(" should show 0,5"); + statusText->SetText(str); + gFailedMsg = "Multi-List::FindItem && RemoveItemAt"; + } + delete title; + NS_RELEASE(btn); + } + return nsEventStatus_eIgnore; + +} + +/**-------------------------------------------------------------------------------- + * Checkbutton Test Handler + *-------------------------------------------------------------------------------- + */ +nsEventStatus PR_CALLBACK CheckButtonTestHandleEvent(nsGUIEvent *aEvent) +{ + nsICheckButton * chkBtn; + if (aEvent->message != NS_MOUSE_LEFT_BUTTON_UP) { + return nsEventStatus_eIgnore; + } + fprintf(gFD, "\nVisually tested CheckBox\n"); + + if (NS_OK == aEvent->widget->QueryInterface(kICheckButtonIID, (void**)&chkBtn)) { + fprintf(gFD, "\tGetState and SetState tested.\n"); + chkBtn->SetState((PRBool)!chkBtn->GetState()); + NS_RELEASE(chkBtn); + gFailedMsg = "CheckButton::SetState & GetState"; + } + return nsEventStatus_eIgnore; +} + +/**-------------------------------------------------------------------------------- + * Failed Button Handler + *-------------------------------------------------------------------------------- + */ +nsEventStatus PR_CALLBACK FailedButtonHandleEvent(nsGUIEvent *aEvent) +{ + nsIButton * btn; + if (aEvent->message != NS_MOUSE_LEFT_BUTTON_UP) { + return nsEventStatus_eIgnore; + } + //fprintf(gFD, "\nVisually tested CheckBox\n"); + + if (NS_OK == aEvent->widget->QueryInterface(kIButtonIID, (void**)&btn)) { + gOverallStatus++; + if (gFailedMsg == nsnull) { + fprintf(gFD, "\n*** Something failed but the msg wan't set correctly in the code!\n"); + } else { + fprintf(gFD, "Method [%s] FAILED!\n", gFailedMsg); + gFailedMsg = nsnull; + } + + } + return nsEventStatus_eIgnore; +} + +/**-------------------------------------------------------------------------------- + * Succeeded Button Handler + *-------------------------------------------------------------------------------- + */ +nsEventStatus PR_CALLBACK SucceededButtonHandleEvent(nsGUIEvent *aEvent) +{ + nsIButton * btn; + if (aEvent->message != NS_MOUSE_LEFT_BUTTON_UP) { + return nsEventStatus_eIgnore; + } + //fprintf(gFD, "\nVisually tested CheckBox\n"); + + if (NS_OK == aEvent->widget->QueryInterface(kIButtonIID, (void**)&btn)) { + if (gFailedMsg == nsnull) { + fprintf(gFD, "\n*** Something Succeeded but the msg wan't set correctly in the code!\n"); + } else { + fprintf(gFD, "Method [%s] SUCCEEDED!\n", gFailedMsg); + gFailedMsg = nsnull; + } + + } + return nsEventStatus_eIgnore; +} + +/**-------------------------------------------------------------------------------- + * TextWidget Test Handler + *-------------------------------------------------------------------------------- + */ +nsEventStatus PR_CALLBACK GenericTextTestHandleEvent(char *aTitle, + nsGUIEvent *aEvent, + nsITextWidget *aTextWidget, + const nsString &aTestStr, + const nsString &aStrToShow) +{ + nsIButton * btn; + if (aEvent->message != NS_MOUSE_LEFT_BUTTON_UP) { + return nsEventStatus_eIgnore; + } + + + if (NS_OK == aEvent->widget->QueryInterface(kIButtonIID, (void**)&btn)) { + nsAutoString strBuf; + nsString str; + btn->GetLabel(strBuf); + char * title = strBuf.ToNewCString(); + + if (!strcmp(title, kSetText)) { + aTextWidget->SetText(aTestStr); + + fprintf(gFD, "\nVisually Testing Text\n"); + + str.Append(" should show["); + str.Append(aStrToShow); + str.Append("]"); + + statusText->SetText(str); + gFailedMsg = "nsITextWidget::SetText"; + } else if (!strcmp(title, kGetText)) { + nsString getStr; + aTextWidget->GetText(getStr, 256); + + fprintf(gFD, "\tTested GetText(...) \n"); + + if (aTestStr.Equals(getStr)) { + str.Append(" Test PASSED"); + fprintf(gFD, "Test PASSED"); + } else { + str.Append(" Test FAILED"); + fprintf(gFD, "Test FAILED"); + } + statusText->SetText(str); + gFailedMsg = "nsITextWidget::GetText"; + } else if (!strcmp(title, kSetCaret)) { + nsString getStr; + aTextWidget->SetCaretPosition(1); + fprintf(gFD, "\tTested SetCaretPosition(1) \n"); + str.Append(" should show caret in position 1"); + statusText->SetText(str); + gFailedMsg = "nsITextWidget::SetCaretPosition"; + } else if (!strcmp(title, kGetCaret)) { + nsString getStr; + PRUint32 pos = aTextWidget->GetCaretPosition(); + + fprintf(gFD, "Visually tested GetCaretPosition(1) \n"); + + if (pos == 1) { + str.Append(" Test PASSED"); + fprintf(gFD, "Test PASSED\n"); + } else { + str.Append(" Test FAILED"); + fprintf(gFD, "Test FAILED\n"); + } + statusText->SetText(str); + gFailedMsg = "nsITextWidget::GetCaretPosition"; + } else if (!strcmp(title, kSetSelection)) { + nsString getStr; + aTextWidget->SetSelection(1,5); + + fprintf(gFD, "\tTested SetSelection(1,5) \n"); + + str.Append(" should show selection from 1 to 5"); + statusText->SetText(str); + gFailedMsg = "nsITextWidget::SetSelection"; + } + delete title; + NS_RELEASE(btn); + } + return nsEventStatus_eIgnore; +} + + +/**-------------------------------------------------------------------------------- + * Button Test Handler + *-------------------------------------------------------------------------------- + */ +nsEventStatus PR_CALLBACK ButtonTestHandleEvent(nsGUIEvent *aEvent) +{ + + nsIButton * btn; + if (aEvent->message != NS_MOUSE_LEFT_BUTTON_UP) { + return nsEventStatus_eIgnore; + } + + if (NS_OK == aEvent->widget->QueryInterface(kIButtonIID, (void**)&btn)) { + nsAutoString strBuf; + nsString str("Tesing "); + btn->GetLabel(strBuf); + char * title = strBuf.ToNewCString(); + + if (!strcmp(title, kHideBtn)) { + movingWidget->Show(PR_FALSE); + str.Append("nsIWidget::Show(FALSE)"); + statusText->SetText(str); + gFailedMsg = "nsIWidget::Show(FALSE)"; + } else if (!strcmp(title, kShowBtn)) { + movingWidget->Show(PR_TRUE); + str.Append("nsIWidget::Show(TRUE)"); + statusText->SetText(str); + gFailedMsg = "nsIWidget::Show(TRUE)"; + } + + delete title; + NS_RELEASE(btn); + + } + return nsEventStatus_eIgnore; +} + +/**-------------------------------------------------------------------------------- + * TextWidget Test Handler + *-------------------------------------------------------------------------------- + */ +nsEventStatus PR_CALLBACK PasswordTextTestHandleEvent(nsGUIEvent *aEvent) +{ + return GenericTextTestHandleEvent("Password", aEvent, passwordText, nsString("123"), nsString("***")); +} + +/**-------------------------------------------------------------------------------- + * Dumps the size of the main window and all child windows + *-------------------------------------------------------------------------------- + */ + +void DumpRects() +{ + nsRect rect; + // print the main window position + window->GetBounds(rect); + printf("Bounds(%d, %d, %d, %d)\n", rect.x, rect.y, rect.width, rect.height); + + // print all children's position + nsIEnumerator *enumerator = window->GetChildren(); + nsISupports * widget; + while (widget = enumerator->Next()) { + nsIWidget *child; + if (NS_OK == widget->QueryInterface(kIWidgetIID, (void**)&child)) { + // + child->GetBounds(rect); + printf("Bounds(%d, %d, %d, %d)\n", rect.x, rect.y, rect.width, rect.height); + NS_RELEASE(child); + } + NS_RELEASE(widget); + } + + NS_RELEASE(enumerator); + delete enumerator; +} + + +/**-------------------------------------------------------------------------------- + * Main Handler + *-------------------------------------------------------------------------------- + */ +nsEventStatus PR_CALLBACK HandleEvent(nsGUIEvent *aEvent) +{ + //printf("aEvent->message %d\n", aEvent->message); + nsEventStatus result = nsEventStatus_eIgnore; + switch(aEvent->message) { + + case NS_MOUSE_ENTER: + if (DEBUG_MOUSE) printf("NS_MOUSE_ENTER 0x%X\n", aEvent->widget); + break; + + case NS_MOUSE_EXIT: + if (DEBUG_MOUSE) printf("NS_MOUSE_EXIT 0x%X\n", aEvent->widget); + break; + + case NS_MOUSE_MOVE: + if (DEBUG_MOUSE) printf("NS_MOUSE_MOVE\n"); + break; + + case NS_MOUSE_LEFT_BUTTON_UP: + if (DEBUG_MOUSE) printf("NS_MOUSE_LEFT_BUTTON_UP\n"); + break; + + + case NS_MOUSE_LEFT_BUTTON_DOWN: + if (DEBUG_MOUSE) printf("NS_MOUSE_LEFT_BUTTON_DOWN\n"); + break; + + case NS_CREATE: + printf("Window Created\n"); + break; + + case NS_PAINT: + // paint the background + if (aEvent->widget == window) { + nsIRenderingContext *drawCtx = ((nsPaintEvent*)aEvent)->renderingContext; + drawCtx->SetColor(aEvent->widget->GetBackgroundColor()); + drawCtx->FillRect(*(((nsPaintEvent*)aEvent)->rect)); + + return nsEventStatus_eIgnore; + } + break; + + case NS_DESTROY: + printf("Destroy Window...Release window\n"); + fprintf(gFD, "\n\n--------------------------------------------------\n"); + fprintf(gFD, "Summary of non-visual tests, Number of Failures %d\n", gNonVisualStatus); + fprintf(gFD, "Summary of visual tests, Number of Failures %d\n", gOverallStatus-gNonVisualStatus); + fprintf(gFD, "Summary of all tests, Number of Failures %d\n", gOverallStatus); + fprintf(gFD, "--------------------------------------------------\n"); + fflush(gFD); + fclose(gFD); + + exit(0); // for now + + break; + + case NS_SCROLLBAR_POS: + case NS_SCROLLBAR_PAGE_NEXT: + case NS_SCROLLBAR_PAGE_PREV: + case NS_SCROLLBAR_LINE_NEXT: + case NS_SCROLLBAR_LINE_PREV: + if (nsnull != movingWidget) { + PRUint32 pos = scrollbar->GetPosition(); + movingWidget->Move(10, pos); + } + break; + + case NS_KEY_UP: { + nsKeyEvent * ke = (nsKeyEvent*)aEvent; + char str[256]; + sprintf(str, "Key Event Key Code[%d] Key [%c] Shift [%s] Control [%s] Alt [%s]", + ke->keyCode, ke->keyCode, + (ke->isShift?"Pressed":"Released"), + (ke->isControl?"Pressed":"Released"), + (ke->isAlt?"Pressed":"Released")); + printf("%s\n", str); + statusText->SetText(nsString(str)); + } + break; + + + default: + result = nsEventStatus_eIgnore; + } + //printf("result: %d = %d\n", result, PR_FALSE); + + return result; +} + + + +nsEventStatus PR_CALLBACK HandleFileButtonEvent(nsGUIEvent *aEvent) +{ + switch(aEvent->message) { + + case NS_MOUSE_LEFT_BUTTON_UP: + // create a FileWidget + // + nsIFileWidget *fileWidget; + + nsString title("FileWidget Title mode = save"); + NSRepository::CreateInstance(kCFileWidgetCID, nsnull, kIFileWidgetIID, (LPVOID*)&fileWidget); + + nsString titles[] = {"all files","html","executables" }; + nsString filters[] = {"*.*", "*.html", "*.exe" }; + fileWidget->SetFilterList(3, titles, filters); + fileWidget->Create(nsnull, + title, + eMode_save, + nsnull, + nsnull); + + PRUint32 result = fileWidget->Show(); + if (result) { + nsString file; + fileWidget->GetFile(file); + printf("file widget contents %s\n", file.ToNewCString()); + statusText->SetText(file.ToNewCString()); + } + else + statusText->SetText("Cancel selected"); + + + NS_RELEASE(fileWidget); + break; + } + + return(nsEventStatus_eConsumeDoDefault); +} + + +/**-------------------------------------------------------------------------------- + * + */ +int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, + int nCmdShow) +{ + // Open global test log file + gFD = fopen(gLogFileName, "w"); + if (gFD == nsnull) { + fprintf(stderr, "Couldn't open file[%s]\n", gLogFileName); + exit(1); + } + + // register widget classes + NSRepository::RegisterFactory(kCWindowCID, "raptorwidget.dll", PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCChildCID, "raptorwidget.dll", PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCButtonCID, "raptorwidget.dll", PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCCheckButtonCID, "raptorwidget.dll", PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCComboBoxCID, "raptorwidget.dll", PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCFileWidgetCID, "raptorwidget.dll", PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCListBoxCID, "raptorwidget.dll", PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCRadioButtonCID, "raptorwidget.dll", PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCRadioGroupCID, "raptorwidget.dll", PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCHorzScrollbarCID, "raptorwidget.dll", PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCVertScrollbarCID, "raptorwidget.dll", PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCTextAreaCID, "raptorwidget.dll", PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCTextFieldCID, "raptorwidget.dll", PR_FALSE, PR_FALSE); + + static NS_DEFINE_IID(kCRenderingContextIID, NS_RENDERING_CONTEXT_CID); + static NS_DEFINE_IID(kCDeviceContextIID, NS_DEVICE_CONTEXT_CID); + static NS_DEFINE_IID(kCFontMetricsIID, NS_FONT_METRICS_CID); + static NS_DEFINE_IID(kCImageIID, NS_IMAGE_CID); + + + NSRepository::RegisterFactory(kCRenderingContextIID, "raptorgfxwin.dll", PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCDeviceContextIID, "raptorgfxwin.dll", PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCFontMetricsIID, "raptorgfxwin.dll", PR_FALSE, PR_FALSE); + NSRepository::RegisterFactory(kCImageIID, "raptorgfxwin.dll", PR_FALSE, PR_FALSE); + + nsIDeviceContext* deviceContext = 0; + + // Create a device context for the widgets + nsresult res; + + static NS_DEFINE_IID(kDeviceContextCID, NS_DEVICE_CONTEXT_CID); + static NS_DEFINE_IID(kDeviceContextIID, NS_IDEVICE_CONTEXT_IID); + + res = NSRepository::CreateInstance(kDeviceContextCID, nsnull, kDeviceContextIID, (void **)&deviceContext); + + if (NS_OK == res) + { + deviceContext->Init(); + NS_ADDREF(deviceContext); + } + + // + // create the main window + // + NSRepository::CreateInstance(kCWindowCID, nsnull, kIWidgetIID, (LPVOID*)&window); + nsRect rect(100, 100, 600, 700); + window->Create((nsIWidget*)NULL, rect, HandleEvent, NULL); + + // + // create a child + // + nsIWidget *child; + // + // create another child + // + + int x = 10; + int y = 10; + rect.SetRect(x, y, 50, 50); + NSRepository::CreateInstance(kCChildCID, nsnull, kIWidgetIID, (LPVOID*)&child); + child->Create(window, rect, HandleEvent, NULL); + // child->SetBackgroundColor(NS_RGB(100, 200,200)); + // child->SetForegroundColor(NS_RGB(100, 200,200)); + NS_RELEASE(child); // the parent keeps a reference on this child + + y += rect.height + 5; + + + // + // create a button + // + nsIButton *button; + rect.SetRect(x, y, 60, 25); + NSRepository::CreateInstance(kCButtonCID, nsnull, kIButtonIID, (LPVOID*)&button); + button->Create(window, rect, HandleEvent, NULL); + nsString label("Slider"); + button->SetLabel(label); + + nsAutoString strBuf; + button->GetLabel(strBuf); + button->Show(PR_TRUE); + + movingWidget = button; + + x = createTestButton(window, kHideBtn, x+180, y, 75, ButtonTestHandleEvent); + x = createTestButton(window, kShowBtn, x+5, y, 75, ButtonTestHandleEvent); + x = 10; + y += rect.height + 5; + + // Create browse button + x = createTestButton(window, kBrowseBtn, x, y, 75, HandleFileButtonEvent); + x = 10; + y += rect.height + 5; + + // + // create a check button + // + nsICheckButton * checkButton; + rect.SetRect(x, y, 100, 25); + + NSRepository::CreateInstance(kCCheckButtonCID, nsnull, kICheckButtonIID, (LPVOID*)&checkButton); + checkButton->Create(window, rect, CheckButtonTestHandleEvent, NULL); + nsString cbLabel("CheckButton"); + checkButton->SetLabel(cbLabel); + NS_RELEASE(checkButton); + y += rect.height + 5; + + // + // create a text widget + // + + nsITextWidget * textWidget; + rect.SetRect(x, y, 100, 25); + + NSRepository::CreateInstance(kCTextFieldCID, nsnull, kITextWidgetIID, (LPVOID*)&textWidget); + textWidget->Create(window, rect, HandleEvent, deviceContext); + + + nsFont font("Times", NS_FONT_STYLE_NORMAL, + NS_FONT_VARIANT_NORMAL, + NS_FONT_WEIGHT_BOLD, + 0, + 12); + + textWidget->SetFont(font); + nsString initialText("0123456789"); + textWidget->SetText(initialText); + + NS_RELEASE(textWidget); + y += rect.height + 5; + + // + // create a text password widget + // + + nsITextWidget * ptextWidget; + rect.SetRect(x, y, 100, 25); + NSRepository::CreateInstance(kCTextFieldCID, nsnull, kITextWidgetIID, (LPVOID*)&ptextWidget); + ptextWidget->SetPassword(PR_TRUE); + ptextWidget->Create(window, rect, HandleEvent, NULL); + nsString pinitialText("password text"); + ptextWidget->SetText(pinitialText); + passwordText = ptextWidget; + + textShelfTest(gFD, "Password Text", passwordText); + + x = createTestButton(window, kSetCaret, x+180, y, 75, PasswordTextTestHandleEvent); + x = createTestButton(window, kGetCaret, x+5, y, 75, PasswordTextTestHandleEvent); + x = createTestButton(window, kSetText, x+5, y, 75, PasswordTextTestHandleEvent); + x = createTestButton(window, kGetText, x+5, y, 75, PasswordTextTestHandleEvent); + x = createTestButton(window, kSetSelection, x+5, y, 100, PasswordTextTestHandleEvent); + x = 10; + y += rect.height + 5; + + // + // create a readonly text widget + // + + nsITextWidget * rtextWidget; + rect.SetRect(x, y, 100, 25); + NSRepository::CreateInstance(kCTextFieldCID, nsnull, kITextWidgetIID, (LPVOID*)&rtextWidget); + rtextWidget->SetReadOnly(PR_TRUE); + rtextWidget->Create(window, rect, HandleEvent, NULL); + nsString rinitialText("This is readonly"); + rtextWidget->SetText(rinitialText); + NS_RELEASE(rtextWidget); + y += rect.height + 5; + + // + // create a text area widget + // + + nsITextAreaWidget * textAreaWidget; + rect.SetRect(x, y, 150, 100); + NSRepository::CreateInstance(kCTextAreaCID, nsnull, kITextAreaWidgetIID, (LPVOID*)&textAreaWidget); + textAreaWidget->Create(window, rect, HandleEvent, NULL); + nsString textAreaInitialText("Text Area Widget"); + textWidgetInstance = textAreaWidget; + textAreaWidget->SetText(textAreaInitialText); + NS_RELEASE(textAreaWidget); + y += rect.height + 5; + + x += rect.width + 5; + + // + // create a scrollbar + // + rect.SetRect(x, 10, 25, 300); + NSRepository::CreateInstance(kCVertScrollbarCID, nsnull, kIScrollbarIID, (LPVOID*)&scrollbar); + scrollbar->Create(window, rect, HandleEvent, NULL); + scrollbar->SetMaxRange(300); + scrollbar->SetThumbSize(50); + scrollbar->SetPosition(100); + + // + // create a Status Text + // + + rect.SetRect(x+25, 10, 350, 25); + NSRepository::CreateInstance(kCTextFieldCID, nsnull, kITextWidgetIID, (LPVOID*)&statusText); + statusText->Create(window, rect, HandleEvent, deviceContext); + + // + // create a Failed Button + // + rect.SetRect(x+25, 38, 60, 25); + NSRepository::CreateInstance(kCButtonCID, nsnull, kIButtonIID, (LPVOID*)&button); + button->Create(window, rect, FailedButtonHandleEvent, NULL); + nsString failedLabel("Failed"); + button->SetLabel(failedLabel); + button->Show(PR_TRUE); + NS_RELEASE(button); + y += rect.height + 5; + + // + // create a Succeeded Button + // + rect.SetRect(x+100, 38, 80, 25); + NSRepository::CreateInstance(kCButtonCID, nsnull, kIButtonIID, (LPVOID*)&button); + button->Create(window, rect, SucceededButtonHandleEvent, NULL); + nsString succeededLabel("Succeeded"); + button->SetLabel(succeededLabel); + button->Show(PR_TRUE); + NS_RELEASE(button); + y += rect.height + 5; + + x = 10; + + + // + // create a listbox widget + // + + rect.SetRect(x, y, 150, 100); + NSRepository::CreateInstance(kCListBoxCID, nsnull, kIListBoxIID, (LPVOID*)&listBox); + listBox->Create(window, rect, HandleEvent, NULL); + char str[256]; + for (int i=0;iAddItemAt(listStr1, i); + } + listSelfTest(gFD, "ListBox", listBox); + + x = createTestButton(window, kSetSelection, x+150, y, 125, ListBoxTestHandleEvent); + x = createTestButton(window, kRemoveSelection, x+5, y, 125, ListBoxTestHandleEvent); + x = 10; + y += rect.height + 5; + + + // + // create a multi-selection listbox widget + // + + rect.SetRect(x, y, 150, 100); + NSRepository::CreateInstance(kCListBoxCID, nsnull, kIListBoxIID, (LPVOID*)&gMultiListBox); + // Notice the extra agrument PR_TRUE below which indicates that + // the list widget is multi-select + gMultiListBox->SetMultipleSelection(PR_TRUE); + gMultiListBox->Create(window, rect, HandleEvent, NULL); + for (i=0;iAddItemAt(listStr1, i); + } + multiListSelfTest(gFD, "Multi-ListBox", gMultiListBox); + + x = createTestButton(window, kSetSelection, x+150, y, 125, MultiListBoxTestHandleEvent); + x = createTestButton(window, kRemoveSelection, x+5, y, 125, MultiListBoxTestHandleEvent); + + y += rect.height + 5; + x = 10; + + // + // create a Radio Group + // + nsIRadioGroup * radioGroup; + NSRepository::CreateInstance(kCRadioGroupCID, nsnull, kIRadioGroupIID, (LPVOID*)&radioGroup); + radioGroup->SetName(nsString("Group1")); + + // + // create a Radio button + // + nsIRadioButton * radioButton; + rect.SetRect(x, y, 120, 25); + + NSRepository::CreateInstance(kCRadioButtonCID, nsnull, kIRadioButtonIID, (LPVOID*)&radioButton); + radioButton->SetRadioGroup(radioGroup); + radioButton->Create(window, rect, HandleEvent, NULL); + nsString rbLabel("RadioButton1"); + radioButton->SetLabel(rbLabel); + radioButton->Show(PR_TRUE); + NS_RELEASE(radioButton); + y += rect.height + 5; + + // + // create a Radio button + // + rect.SetRect(x, y, 120, 25); + + NSRepository::CreateInstance(kCRadioButtonCID, nsnull, kIRadioButtonIID, (LPVOID*)&radioButton); + radioButton->SetRadioGroup(radioGroup); + radioButton->Create(window, rect, HandleEvent, NULL); + nsString rbLabel2("RadioButton2"); + radioButton->SetLabel(rbLabel2); + radioButton->Show(PR_TRUE); + NS_RELEASE(radioButton); + y += rect.height + 5; + + // [TODO] implement a test here to see if the radio group exists + // radioGroup = NULL; + + //window->SetBackgroundColor(NS_RGB(0,255,0)); + + // + // create a ComboBox + // + rect.SetRect(x, y, 120, 100); + + NSRepository::CreateInstance(kCComboBoxCID, nsnull, kIComboBoxIID, (LPVOID*)&comboBox); + comboBox->Create(window, rect, HandleEvent, NULL); + for (i=0;iAddItemAt(listStr1, 1); + } + listSelfTest(gFD, "ComboBox", comboBox); + NS_RELEASE(comboBox); + + x = createTestButton(window, kSetSelection, x+125, y, 125, ComboTestHandleEvent); + x = createTestButton(window, kRemoveSelection, x+5, y, 125, ComboTestHandleEvent); + + x = 10; + y += 30; + + + nsString status("The non-visual tests: "); + status.Append(eval(gOverallStatus)); + gNonVisualStatus = gOverallStatus; + + statusText->SetText(status); + + // show + window->Show(PR_TRUE); + + window->SetCursor(eCursor_hyperlink); + + // Process messages + MSG msg; + while (GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return msg.wParam; +} + +void main(int argc, char **argv) +{ + WinMain(GetModuleHandle(NULL), NULL, 0, SW_SHOW); +} + diff --git a/mozilla/xpcom/ds/nsArena.cpp b/mozilla/xpcom/ds/nsArena.cpp new file mode 100644 index 00000000000..a38ef687f58 --- /dev/null +++ b/mozilla/xpcom/ds/nsArena.cpp @@ -0,0 +1,80 @@ +/* -*- 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 "nsIArena.h" +#include "nsCRT.h" + +#define PL_ARENA_CONST_ALIGN_MASK 7 +#include "plarena.h" + +static NS_DEFINE_IID(kArenaIID, NS_IARENA_IID); + +// Simple arena implementation layered on plarena +class ArenaImpl : public nsIArena { +public: + ArenaImpl(PRInt32 aBlockSize); + + NS_DECL_ISUPPORTS + + virtual void* Alloc(PRInt32 aSize); + +protected: + ~ArenaImpl(); + + PLArenaPool mPool; + PRInt32 mBlockSize; +}; + +ArenaImpl::ArenaImpl(PRInt32 aBlockSize) +{ + NS_INIT_REFCNT(); + if (aBlockSize < NS_MIN_ARENA_BLOCK_SIZE) { + aBlockSize = NS_DEFAULT_ARENA_BLOCK_SIZE; + } + PL_INIT_ARENA_POOL(&mPool, "nsIArena", aBlockSize); + mBlockSize = aBlockSize; +} + +NS_IMPL_ISUPPORTS(ArenaImpl,kArenaIID) + +ArenaImpl::~ArenaImpl() +{ + PL_FinishArenaPool(&mPool); +} + +void* ArenaImpl::Alloc(PRInt32 size) +{ + // Adjust size so that it's a multiple of sizeof(double) + PRInt32 align = size & (sizeof(double) - 1); + if (0 != align) { + size += sizeof(double) - align; + } + + void* p; + PL_ARENA_ALLOCATE(p, &mPool, size); + return p; +} + +NS_BASE nsresult NS_NewHeapArena(nsIArena** aInstancePtrResult, + PRInt32 aArenaBlockSize) +{ + ArenaImpl* it = new ArenaImpl(aArenaBlockSize); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kArenaIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/xpcom/ds/nsAtomTable.cpp b/mozilla/xpcom/ds/nsAtomTable.cpp new file mode 100644 index 00000000000..75998008cb5 --- /dev/null +++ b/mozilla/xpcom/ds/nsAtomTable.cpp @@ -0,0 +1,144 @@ +/* -*- 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 "nsIAtom.h" +#include "nsString.h" +#include "nsCRT.h" +#include "plhash.h" + +/** + * The shared hash table for atom lookups. + */ +static nsrefcnt gAtoms; +static struct PLHashTable* gAtomHashTable; + +class AtomImpl : public nsIAtom { +public: + AtomImpl(); + ~AtomImpl(); + + NS_DECL_ISUPPORTS + + void* operator new(size_t size, const PRUnichar* us, PRInt32 uslen); + + virtual void ToString(nsString& aBuf) const; + + virtual const PRUnichar* GetUnicode() const; + + // Actually more; 0 terminated. This slot is reserved for the + // terminating zero. + PRUnichar mString[1]; +}; + +AtomImpl::AtomImpl() +{ + NS_INIT_REFCNT(); + // Every live atom holds a reference on the atom hashtable + gAtoms++; +} + +AtomImpl::~AtomImpl() +{ + NS_PRECONDITION(nsnull != gAtomHashTable, "null atom hashtable"); + if (nsnull != gAtomHashTable) { + PL_HashTableRemove(gAtomHashTable, mString); + nsrefcnt cnt = --gAtoms; + if (0 == cnt) { + // When the last atom is destroyed, the atom arena is destroyed + NS_ASSERTION(0 == gAtomHashTable->nentries, "bad atom table"); + PL_HashTableDestroy(gAtomHashTable); + gAtomHashTable = nsnull; + } + } +} + +static NS_DEFINE_IID(kIAtomIID, NS_IATOM_IID); +NS_IMPL_ISUPPORTS(AtomImpl, kIAtomIID); + +void* AtomImpl::operator new(size_t size, const PRUnichar* us, PRInt32 uslen) +{ + size = size + uslen * sizeof(PRUnichar); + AtomImpl* ii = (AtomImpl*) new char[size]; + nsCRT::memcpy(ii->mString, us, uslen * sizeof(PRUnichar)); + ii->mString[uslen] = 0; + return ii; +} + +void AtomImpl::ToString(nsString& aBuf) const +{ + aBuf.SetLength(0); + aBuf.Append(mString, nsCRT::strlen(mString)); +} + +const PRUnichar* AtomImpl::GetUnicode() const +{ + return mString; +} + +//---------------------------------------------------------------------- + +static PLHashNumber HashKey(const PRUnichar* k) +{ + return (PLHashNumber) nsCRT::HashCode(k); +} + +static PRIntn CompareKeys(const PRUnichar* k1, const PRUnichar* k2) +{ + return nsCRT::strcmp(k1, k2) == 0; +} + +NS_BASE nsIAtom* NS_NewAtom(const char* isolatin1) +{ + nsAutoString tmp(isolatin1); + return NS_NewAtom(tmp.GetUnicode()); +} + +NS_BASE nsIAtom* NS_NewAtom(const nsString& aString) +{ + return NS_NewAtom(aString.GetUnicode()); +} + +NS_BASE nsIAtom* NS_NewAtom(const PRUnichar* us) +{ + if (nsnull == gAtomHashTable) { + gAtomHashTable = PL_NewHashTable(8, (PLHashFunction) HashKey, + (PLHashComparator) CompareKeys, + (PLHashComparator) nsnull, + nsnull, nsnull); + } + PRInt32 uslen; + PRInt32 hashCode = nsCRT::HashCode(us, &uslen); + PLHashEntry** hep = PL_HashTableRawLookup(gAtomHashTable, hashCode, us); + PLHashEntry* he = *hep; + if (nsnull != he) { + nsIAtom* id = (nsIAtom*) he->value; + NS_ADDREF(id); + return id; + } + AtomImpl* id = new(us, uslen) AtomImpl(); + PL_HashTableRawAdd(gAtomHashTable, hep, hashCode, id->mString, id); + NS_ADDREF(id); + return id; +} + +NS_BASE nsrefcnt NS_GetNumberOfAtoms(void) +{ + if (nsnull != gAtomHashTable) { + NS_PRECONDITION(nsrefcnt(gAtomHashTable->nentries) == gAtoms, "bad atom table"); + } + return gAtoms; +} diff --git a/mozilla/xpcom/ds/nsByteBuffer.cpp b/mozilla/xpcom/ds/nsByteBuffer.cpp new file mode 100644 index 00000000000..a27f8cbf2c9 --- /dev/null +++ b/mozilla/xpcom/ds/nsByteBuffer.cpp @@ -0,0 +1,135 @@ +/* -*- 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 "nsIByteBuffer.h" +#include "nsIInputStream.h" +#include "nsCRT.h" + +#define MIN_BUFFER_SIZE 32 + +class ByteBufferImpl : public nsIByteBuffer { +public: + ByteBufferImpl(PRInt32 aBufferSize); + ~ByteBufferImpl(); + + NS_DECL_ISUPPORTS + virtual PRInt32 GetLength() const; + virtual PRInt32 GetBufferSize() const; + virtual char* GetBuffer() const; + virtual PRBool Grow(PRInt32 aNewSize); + virtual PRInt32 Fill(PRInt32* aErrorCode, nsIInputStream* aStream, + PRInt32 aKeep); + + char* mBuffer; + PRInt32 mSpace; + PRInt32 mLength; +}; + +ByteBufferImpl::ByteBufferImpl(PRInt32 aBufferSize) +{ + if (PRUint32(aBufferSize) < MIN_BUFFER_SIZE) { + aBufferSize = MIN_BUFFER_SIZE; + } + mSpace = aBufferSize; + mBuffer = new char[aBufferSize]; + mLength = 0; + NS_INIT_REFCNT(); +} + +NS_DEFINE_IID(kByteBufferIID,NS_IBYTE_BUFFER_IID); +NS_IMPL_ISUPPORTS(ByteBufferImpl,kByteBufferIID) + +ByteBufferImpl::~ByteBufferImpl() +{ + if (nsnull != mBuffer) { + delete mBuffer; + mBuffer = nsnull; + } + mLength = 0; +} + +PRInt32 ByteBufferImpl::GetLength() const +{ + return mLength; +} + +PRInt32 ByteBufferImpl::GetBufferSize() const +{ + return mSpace; +} + +char* ByteBufferImpl::GetBuffer() const +{ + return mBuffer; +} + +PRBool ByteBufferImpl::Grow(PRInt32 aNewSize) +{ + if (PRUint32(aNewSize) < MIN_BUFFER_SIZE) { + aNewSize = MIN_BUFFER_SIZE; + } + char* newbuf = new char[aNewSize]; + if (nsnull != newbuf) { + if (0 != mLength) { + nsCRT::memcpy(newbuf, mBuffer, mLength); + } + delete mBuffer; + mBuffer = newbuf; + return PR_TRUE; + } + return PR_FALSE; +} + +PRInt32 ByteBufferImpl::Fill(PRInt32* aErrorCode, nsIInputStream* aStream, + PRInt32 aKeep) +{ + NS_PRECONDITION(nsnull != aStream, "null stream"); + NS_PRECONDITION(PRUint32(aKeep) <= PRUint32(mLength), "illegal keep count"); + if ((nsnull == aStream) || (PRUint32(aKeep) > PRUint32(mLength))) { + // whoops + *aErrorCode = NS_INPUTSTREAM_ILLEGAL_ARGS; + return -1; + } + + if (0 != aKeep) { + // Slide over kept data + nsCRT::memmove(mBuffer, mBuffer + (mLength - aKeep), aKeep); + } + + // Read in some new data + mLength = aKeep; + PRInt32 amount = mSpace - aKeep; + PRInt32 nb = aStream->Read(aErrorCode, mBuffer, aKeep, amount); + if (nb > 0) { + mLength += nb; + } + return nb; +} + +NS_BASE nsresult NS_NewByteBuffer(nsIByteBuffer** aInstancePtrResult, + nsISupports* aOuter, + PRInt32 aBufferSize) +{ + if (nsnull != aOuter) { + return NS_ERROR_NO_AGGREGATION; + } + ByteBufferImpl* it = new ByteBufferImpl(aBufferSize); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kByteBufferIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/xpcom/ds/nsCRT.cpp b/mozilla/xpcom/ds/nsCRT.cpp new file mode 100644 index 00000000000..c4ac141a2ad --- /dev/null +++ b/mozilla/xpcom/ds/nsCRT.cpp @@ -0,0 +1,290 @@ +/* -*- 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 "nsCRT.h" + +// XXX Bug: These tables don't lowercase the upper 128 characters properly + +// This table maps uppercase characters to lower case characters; +// characters that are neither upper nor lower case are unaffected. +static const unsigned char kUpper2Lower[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, + + // upper band mapped to lower [A-Z] => [a-z] + 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122, + + 91, 92, 93, 94, 95, + 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 +}; + +static const unsigned char kLower2Upper[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, + + // lower band mapped to upper [a-z] => [A-Z] + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + + 123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 +}; + +static const PRUnichar kIsoLatin1ToUCS2[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 +}; + +//---------------------------------------------------------------------- + +#define TOLOWER(_ucs2) \ + (((_ucs2) < 256) ? PRUnichar(kUpper2Lower[_ucs2]) : _ToLower(_ucs2)) + +#define TOUPPER(_ucs2) \ + (((_ucs2) < 256) ? PRUnichar(kLower2Upper[_ucs2]) : _ToUpper(_ucs2)) + +static PRUnichar _ToLower(PRUnichar aChar) +{ + // XXX need i18n code here + return aChar; +} + +static PRUnichar _ToUpper(PRUnichar aChar) +{ + // XXX need i18n code here + return aChar; +} + +//---------------------------------------------------------------------- + +PRUnichar nsCRT::ToUpper(PRUnichar aChar) +{ + return TOUPPER(aChar); +} + +PRUnichar nsCRT::ToLower(PRUnichar aChar) +{ + return TOLOWER(aChar); +} + +PRInt32 nsCRT::strlen(const PRUnichar* s) +{ + PRInt32 len = 0; + while (*s++ != 0) { + len++; + } + return len; +} + +PRInt32 nsCRT::strcmp(const PRUnichar* s1, const PRUnichar* s2) +{ + for (;;) { + PRUnichar c1 = *s1++; + PRUnichar c2 = *s2++; + if (c1 != c2) { + if (c1 < c2) return -1; + return 1; + } + if (c1 == 0) break; + } + return 0; +} + +// characters following a null character are not compared +PRInt32 nsCRT::strncmp(const PRUnichar* s1, const PRUnichar* s2, PRInt32 n) +{ + while (--n >= 0) { + PRUnichar c1 = *s1++; + PRUnichar c2 = *s2++; + if (c1 != c2) { + if (c1 < c2) return -1; + return 1; + } + if (c1 == 0) break; + } + return 0; +} + +PRInt32 nsCRT::strcasecmp(const PRUnichar* s1, const PRUnichar* s2) +{ + for (;;) { + PRUnichar c1 = *s1++; + PRUnichar c2 = *s2++; + if (c1 != c2) { + c1 = TOLOWER(c1); + c2 = TOLOWER(c2); + if (c1 != c2) { + if (c1 < c2) return -1; + return 1; + } + } + if (c1 == 0) break; + } + return 0; +} + +PRInt32 nsCRT::strncasecmp(const PRUnichar* s1, const PRUnichar* s2, PRInt32 n) +{ + while (--n >= 0) { + PRUnichar c1 = *s1++; + PRUnichar c2 = *s2++; + if (c1 != c2) { + c1 = TOLOWER(c1); + c2 = TOLOWER(c2); + if (c1 != c2) { + if (c1 < c2) return -1; + return 1; + } + } + if (c1 == 0) break; + } + return 0; +} + +PRInt32 nsCRT::strcmp(const PRUnichar* s1, const char* s2) +{ + for (;;) { + PRUnichar c1 = *s1++; + PRUnichar c2 = kIsoLatin1ToUCS2[*(const unsigned char*)s2++]; + if (c1 != c2) { + if (c1 < c2) return -1; + return 1; + } + if (c1 == 0) break; + } + return 0; +} + +PRInt32 nsCRT::strncmp(const PRUnichar* s1, const char* s2, PRInt32 n) +{ + while (--n >= 0) { + PRUnichar c1 = *s1++; + PRUnichar c2 = kIsoLatin1ToUCS2[*(const unsigned char*)s2++]; + if (c1 != c2) { + if (c1 < c2) return -1; + return 1; + } + if (c1 == 0) break; + } + return 0; +} + +PRInt32 nsCRT::strcasecmp(const PRUnichar* s1, const char* s2) +{ + for (;;) { + PRUnichar c1 = *s1++; + PRUnichar c2 = kIsoLatin1ToUCS2[*(const unsigned char*)s2++]; + if (c1 != c2) { + c1 = TOLOWER(c1); + c2 = TOLOWER(c2); + if (c1 != c2) { + if (c1 < c2) return -1; + return 1; + } + } + if (c1 == 0) break; + } + return 0; +} + +PRInt32 nsCRT::strncasecmp(const PRUnichar* s1, const char* s2, PRInt32 n) +{ + while (--n >= 0) { + PRUnichar c1 = *s1++; + PRUnichar c2 = kIsoLatin1ToUCS2[*(const unsigned char*)s2++]; + if (c1 != c2) { + c1 = TOLOWER(c1); + c2 = TOLOWER(c2); + if (c1 != c2) { + if (c1 < c2) return -1; + return 1; + } + } + if (c1 == 0) break; + } + return 0; +} + +PRInt32 nsCRT::HashCode(const PRUnichar* us) +{ + PRInt32 rv = 0; + PRUnichar ch; + while ((ch = *us++) != 0) { + // FYI: rv = rv*37 + ch + rv = ((rv << 5) + (rv << 2) + rv) + ch; + } + return rv; +} + +PRInt32 nsCRT::HashCode(const PRUnichar* us, PRInt32* uslenp) +{ + PRInt32 rv = 0; + PRInt32 len = 0; + PRUnichar ch; + while ((ch = *us++) != 0) { + // FYI: rv = rv*37 + ch + rv = ((rv << 5) + (rv << 2) + rv) + ch; + len++; + } + *uslenp = len; + return rv; +} + +PRInt32 nsCRT::atoi( const PRUnichar *string ) +{ + return atoi(string); +} + diff --git a/mozilla/xpcom/ds/nsCRT.h b/mozilla/xpcom/ds/nsCRT.h new file mode 100644 index 00000000000..a14ed2bbcb5 --- /dev/null +++ b/mozilla/xpcom/ds/nsCRT.h @@ -0,0 +1,110 @@ +/* -*- 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. + */ +#ifndef nsCRT_h___ +#define nsCRT_h___ + +#include +#include +#include "plstr.h" +#include "nscore.h" + +/// This is a wrapper class around all the C runtime functions. + +class NS_BASE nsCRT { +public: + /** Copy bytes from aSrc to aDest. + @param aDest the destination address + @param aSrc the source address + @param aCount the number of bytes to copy + */ + static void memcpy(void* aDest, const void* aSrc, PRInt32 aCount) { + ::memcpy(aDest, aSrc, (size_t)aCount); + } + + static void memmove(void* aDest, const void* aSrc, PRInt32 aCount) { + ::memmove(aDest, aSrc, (size_t)aCount); + } + + static void memset(void* aDest, PRUint8 aByte, PRInt32 aCount) { + ::memset(aDest, aByte, aCount); + } + + static void zero(void* aDest, PRInt32 aCount) { + ::memset(aDest, 0, (size_t)aCount); + } + + /** Compute the string length of s + @param s the string in question + @return the length of s + */ + static PRInt32 strlen(const char* s) { + return PRInt32(::strlen(s)); + } + + /// Compare s1 and s2. + static PRInt32 strcmp(const char* s1, const char* s2) { + return PRInt32(PL_strcmp(s1, s2)); + } + + /// Case-insensitive string comparison. + static PRInt32 strcasecmp(const char* s1, const char* s2) { + return PRInt32(PL_strcasecmp(s1, s2)); + } + + /// Like strlen except for ucs2 strings + static PRInt32 strlen(const PRUnichar* s); + + /// Like strcmp except for ucs2 strings + static PRInt32 strcmp(const PRUnichar* s1, const PRUnichar* s2); + /// Like strcmp except for ucs2 strings + static PRInt32 strncmp(const PRUnichar* s1, const PRUnichar* s2, + PRInt32 aMaxLen); + + /// Like strcasecmp except for ucs2 strings + static PRInt32 strcasecmp(const PRUnichar* s1, const PRUnichar* s2); + /// Like strncasecmp except for ucs2 strings + static PRInt32 strncasecmp(const PRUnichar* s1, const PRUnichar* s2, + PRInt32 aMaxLen); + + /// Like strcmp with a char* and a ucs2 string + static PRInt32 strcmp(const PRUnichar* s1, const char* s2); + /// Like strncmp with a char* and a ucs2 string + static PRInt32 strncmp(const PRUnichar* s1, const char* s2, + PRInt32 aMaxLen); + + /// Like strcasecmp with a char* and a ucs2 string + static PRInt32 strcasecmp(const PRUnichar* s1, const char* s2); + /// Like strncasecmp with a char* and a ucs2 string + static PRInt32 strncasecmp(const PRUnichar* s1, const char* s2, + PRInt32 aMaxLen); + + /// Compute a hashcode for a ucs2 string + static PRInt32 HashCode(const PRUnichar* s1); + + /// Same as above except that we return the length in s1len + static PRInt32 HashCode(const PRUnichar* s1, PRInt32* s1len); + + /// String to integer. + static PRInt32 atoi( const PRUnichar *string ); + + static PRUnichar ToUpper(PRUnichar aChar); + + static PRUnichar ToLower(PRUnichar aChar); +}; + +#endif /* nsCRT_h___ */ diff --git a/mozilla/xpcom/ds/nsIArena.h b/mozilla/xpcom/ds/nsIArena.h new file mode 100644 index 00000000000..c530f914631 --- /dev/null +++ b/mozilla/xpcom/ds/nsIArena.h @@ -0,0 +1,51 @@ +/* -*- 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. + */ +#ifndef nsIArena_h___ +#define nsIArena_h___ + +#include "nscore.h" +#include "nsISupports.h" + +#define NS_MIN_ARENA_BLOCK_SIZE 64 +#define NS_DEFAULT_ARENA_BLOCK_SIZE 4096 + +/// Interface IID for nsIArena +#define NS_IARENA_IID \ +{ 0xa24fdad0, 0x93b4, 0x11d1, \ + {0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } + +/** Interface to a memory arena abstraction. Arena's use large blocks + * of memory to allocate smaller objects. Arena's provide no free + * operator; instead, all of the objects in the arena are deallocated + * by deallocating the arena (e.g. when it's reference count goes to + * zero) + */ +class nsIArena : public nsISupports { +public: + virtual void* Alloc(PRInt32 size) = 0; +}; + +/** + * Create a new arena using the desired block size for allocating the + * underlying memory blocks. The underlying memory blocks are allocated + * using the PR heap. + */ +extern NS_BASE nsresult NS_NewHeapArena(nsIArena** aInstancePtrResult, + PRInt32 aArenaBlockSize = 0); + +#endif /* nsIArena_h___ */ diff --git a/mozilla/xpcom/ds/nsIAtom.h b/mozilla/xpcom/ds/nsIAtom.h new file mode 100644 index 00000000000..59e13f2035e --- /dev/null +++ b/mozilla/xpcom/ds/nsIAtom.h @@ -0,0 +1,71 @@ +/* -*- 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. + */ +#ifndef nsIAtom_h___ +#define nsIAtom_h___ + +#include "nscore.h" +#include "nsISupports.h" +class nsString; + +#define NS_IATOM_IID \ +{ 0x3d1b15b0, 0x93b4, 0x11d1, \ + {0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } + +/** + * A globally unique identfier. nsIAtom's can be compared for + * equality by using operator '=='. These objects are reference + * counted like other nsISupports objects. When you are done with + * the atom, NS_RELEASE it. + */ +class nsIAtom : public nsISupports { +public: + /** + * Translate the unicode string into the stringbuf. + */ + virtual void ToString(nsString& aString) const = 0; + + /** + * Return a pointer to a zero terminated unicode string. + */ + virtual const PRUnichar* GetUnicode() const = 0; +}; + +/** + * Find an atom that matches the given iso-latin1 C string. The + * C string is translated into it's unicode equivalent. + */ +extern NS_BASE nsIAtom* NS_NewAtom(const char* isolatin1); + +/** + * Find an atom that matches the given unicode string. The string is assumed + * to be zero terminated. + */ +extern NS_BASE nsIAtom* NS_NewAtom(const PRUnichar* unicode); + +/** + * Find an atom that matches the given string. + */ +extern NS_BASE nsIAtom* NS_NewAtom(const nsString& aString); + +/** + * Return a count of the total number of atoms currently + * alive in the system. + */ +extern NS_BASE nsrefcnt NS_GetNumberOfAtoms(void); + +#endif /* nsIAtom_h___ */ diff --git a/mozilla/xpcom/ds/nsIByteBuffer.h b/mozilla/xpcom/ds/nsIByteBuffer.h new file mode 100644 index 00000000000..74561b69a47 --- /dev/null +++ b/mozilla/xpcom/ds/nsIByteBuffer.h @@ -0,0 +1,56 @@ +/* -*- 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. + */ +#ifndef nsIByteBuffer_h___ +#define nsIByteBuffer_h___ + +#include "nscore.h" +#include "nsISupports.h" + +class nsIInputStream; + +#define NS_IBYTE_BUFFER_IID \ +{ 0xe4a6e4b0, 0x93b4, 0x11d1, \ + {0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } + +/** Interface to a buffer that holds bytes */ +class nsIByteBuffer : public nsISupports { +public: + /** @return length of buffer, i.e. how many bytes are currently in it. */ + virtual PRInt32 GetLength() const = 0; + + /** @return number of bytes allocated in the buffer */ + virtual PRInt32 GetBufferSize() const = 0; + + /** @return the buffer */ + virtual char* GetBuffer() const = 0; + + /** Grow buffer to aNewSize bytes. */ + virtual PRBool Grow(PRInt32 aNewSize) = 0; + + /** Fill the buffer with data from aStream. Don't grow the buffer, only + * read until length of buffer equals buffer size. */ + virtual PRInt32 Fill(PRInt32* aErrorCode, nsIInputStream* aStream, + PRInt32 aKeep) = 0; +}; + +/** Create a new byte buffer using the given buffer size. */ +extern NS_BASE nsresult NS_NewByteBuffer(nsIByteBuffer** aInstancePtrResult, + nsISupports* aOuter, + PRInt32 aBufferSize = 0); + +#endif /* nsIByteBuffer_h___ */ diff --git a/mozilla/xpcom/ds/nsIUnicharBuffer.h b/mozilla/xpcom/ds/nsIUnicharBuffer.h new file mode 100644 index 00000000000..17bf8e74a3a --- /dev/null +++ b/mozilla/xpcom/ds/nsIUnicharBuffer.h @@ -0,0 +1,46 @@ +/* -*- 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. + */ +#ifndef nsIUnicharBuffer_h___ +#define nsIUnicharBuffer_h___ + +#include "nscore.h" +#include "nsISupports.h" +class nsIUnicharInputStream; + +#define NS_IUNICHAR_BUFFER_IID \ +{ 0x14cf6970, 0x93b5, 0x11d1, \ + {0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } + +/// Interface to a buffer that holds unicode characters +class nsIUnicharBuffer : public nsISupports { +public: + virtual PRInt32 GetLength() const = 0; + virtual PRInt32 GetBufferSize() const = 0; + virtual PRUnichar* GetBuffer() const = 0; + virtual PRBool Grow(PRInt32 aNewSize) = 0; + virtual PRInt32 Fill(PRInt32* aErrorCode, nsIUnicharInputStream* aStream, + PRInt32 aKeep) = 0; +}; + +/// Factory method for nsIUnicharBuffer. +extern NS_BASE nsresult + NS_NewUnicharBuffer(nsIUnicharBuffer** aInstancePtrResult, + nsISupports* aOuter, + PRInt32 aBufferSize = 0); + +#endif /* nsIUnicharBuffer_h___ */ diff --git a/mozilla/xpcom/ds/nsString.cpp b/mozilla/xpcom/ds/nsString.cpp new file mode 100644 index 00000000000..9f5ada26569 --- /dev/null +++ b/mozilla/xpcom/ds/nsString.cpp @@ -0,0 +1,1979 @@ +/* -*- 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 +#include +#include +#include +#include "nsString.h" +#include "nsCRT.h" +#include "nsDebug.h" +#include "prprf.h" +#include "prdtoa.h" + + +const PRInt32 kGrowthDelta = 8; +const PRInt32 kNotFound = -1; +PRUnichar gBadChar = 0; +const char* kOutOfBoundsError = "Error: out of bounds"; +const char* kNullPointerError = "Error: unexpected null ptr"; + +//********************************************** +//NOTE: Our buffer always hold capacity+1 bytes. +//********************************************** + + +PRInt32 nsString::mInstanceCount=0; + +/**------------------------------------------------------- + * Default constructor + * + * @update gess 3/31/98 + * @param + * @return + *------------------------------------------------------*/ +nsString::nsString(const char* anISOLatin1/*=""*/) { + mLength=mCapacity=0; + mStr=0; + PRInt32 len=strlen(anISOLatin1); + EnsureCapacityFor(len); + this->SetString(anISOLatin1,len); + if(++mInstanceCount==1) + SelfTest(); +} + +/*------------------------------------------------------- + * constructor from string + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsString::nsString(const nsString &aString) { + mLength=mCapacity=0; + mStr=0; + EnsureCapacityFor(aString.mLength); + this->SetString(aString.mStr,aString.mLength); + if(++mInstanceCount==1) + SelfTest(); +} + +/*------------------------------------------------------- + * constructor from unicode string + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsString::nsString(const PRUnichar* aUnicodeStr){ + mLength=mCapacity=0; + mStr=0; + PRInt32 len=(aUnicodeStr) ? nsCRT::strlen(aUnicodeStr) : 0; + EnsureCapacityFor(len); + this->SetString(aUnicodeStr,len); + if(++mInstanceCount==1) + SelfTest(); +} + +/*------------------------------------------------------- + * standard destructor + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsString::~nsString() +{ + delete [] mStr; + mStr=0; + mCapacity=mLength=0; +} + +/*------------------------------------------------------- + * This method gets called when the internal buffer needs + * to grow to a given size. + * @update gess 3/30/98 + * @param aNewLength -- new capacity of string + * @return void + *------------------------------------------------------*/ +void nsString::EnsureCapacityFor(PRInt32 aNewLength) +{ + PRInt32 newCapacity; + + if (mCapacity > 64) { + // When the string starts getting large, double the capacity as we + // grow. + newCapacity = mCapacity * 2; + if (newCapacity < aNewLength) { + newCapacity = mCapacity + aNewLength; + } + } else { + // When the string is small, keep it's capacity a multiple of + // kGrowthDelta + PRInt32 size =aNewLength+kGrowthDelta; + newCapacity=size-(size % kGrowthDelta); + } + + if(mCapacity 0) { + nsCRT::memcpy(temp, mStr, mLength * sizeof(chartype)); + } + if(mStr) + delete [] mStr; + mStr = temp; + mStr[mLength]=0; + } +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +void nsString::SetLength(PRInt32 aLength) { +// NS_WARNING("Depricated method -- not longer required with dynamic strings. Use Truncate() instead."); + EnsureCapacityFor(aLength); + if (aLength > mLength) { + nsCRT::zero(mStr + mLength, (aLength - mLength) * sizeof(chartype)); + } + mLength=aLength; +} + +/*------------------------------------------------------- + * This method truncates this string to given length. + * + * @update gess 3/27/98 + * @param anIndex -- new length of string + * @return nada + *------------------------------------------------------*/ +void nsString::Truncate(PRInt32 anIndex) { + if((anIndex>-1) && (anIndex= 'A') && (ch <= 'Z')) { + *cp = 'a' + (ch - 'A'); + } + cp++; + } +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +void nsString::ToUpperCase() +{ + chartype* cp = mStr; + chartype* end = cp + mLength; + while (cp < end) { + chartype ch = *cp; + if ((ch >= 'a') && (ch <= 'z')) { + *cp = 'A' + (ch - 'a'); + } + cp++; + } +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +void nsString::ToLowerCase(nsString& aOut) const +{ + aOut.SetLength(mLength); + chartype* to = aOut.mStr; + chartype* from = mStr; + chartype* end = from + mLength; + while (from < end) { + chartype ch = *from++; + if ((ch >= 'A') && (ch <= 'Z')) { + ch = 'a' + (ch - 'A'); + } + *to++ = ch; + } + *to = 0; +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +void nsString::ToUpperCase(nsString& aOut) const +{ + aOut.SetLength(mLength); + chartype* to = aOut.mStr; + chartype* from = mStr; + chartype* end = from + mLength; + while (from < end) { + chartype ch = *from++; + if ((ch >= 'a') && (ch <= 'z')) { + ch = 'A' + (ch - 'a'); + } + *to++ = ch; + } + *to = 0; +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsString* nsString::ToNewString() const { + return new nsString(mStr); +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +char* nsString::ToNewCString() const +{ + char* rv = new char[mLength + 1]; + return ToCString(rv,mLength+1); +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRUnichar* nsString::ToNewUnicode() const +{ + PRInt32 len = mLength; + chartype* rv = new chartype[len + 1]; + chartype* to = rv; + chartype* from = mStr; + while (--len >= 0) { + *to++ = *from++; + } + *to++ = 0; + return rv; +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +void nsString::ToString(nsString& aString) const +{ + aString.SetLength(0); + aString.Append(mStr, mLength); +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +char* nsString::ToCString(char* aBuf, PRInt32 aBufLength) const +{ + aBufLength--; // leave room for the \0 + PRInt32 len = mLength; + if (len > aBufLength) { + len = aBufLength; + } + char* to = aBuf; + chartype* from = mStr; + while (--len >= 0) { + *to++ = char(*from++); + } + *to++ = '\0'; + return aBuf; +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +float nsString::ToFloat(PRInt32* aErrorCode) const +{ + char buf[40]; + if (mLength > sizeof(buf)-1) { + *aErrorCode = NS_ERROR_ILLEGAL_VALUE; + return 0.0f; + } + char* cp = ToCString(buf, sizeof(buf)); + float f = (float) PR_strtod(cp, &cp); + if (*cp != 0) { + *aErrorCode = NS_ERROR_ILLEGAL_VALUE; + } + return f; +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::ToInteger(PRInt32* aErrorCode) const { + PRInt32 rv = 0; + PRUnichar* cp = mStr; + PRUnichar* end = mStr + mLength; + + // Skip leading whitespace + while (cp < end) { + PRUnichar ch = *cp; + if (!IsSpace(ch)) { + break; + } + cp++; + } + if (cp == end) { + *aErrorCode = NS_ERROR_ILLEGAL_VALUE; + return rv; + } + + // Check for sign + PRUnichar sign = '+'; + if ((*cp == '+') || (*cp == '-')) { + sign = *cp++; + } + if (cp == end) { + *aErrorCode = NS_ERROR_ILLEGAL_VALUE; + return rv; + } + + // Convert the number + while (cp < end) { + PRUnichar ch = *cp++; + if ((ch < '0') || (ch > '9')) { + *aErrorCode = NS_ERROR_ILLEGAL_VALUE; + break; + } + rv = rv * 10 + (ch - '0'); + } + + if (sign == '-') { + rv = -rv; + } + return rv; +} + + +/*------------------------------------------------------- + * assign given string to this one + * @update gess 3/27/98 + * @param aString: string to be added to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator=(const nsString& aString) { + return this->SetString(aString.mStr,aString.mLength); +} + + +/*------------------------------------------------------- + * assign given char* to this string + * @update gess 3/27/98 + * @param anISOLatin1: buffer to be assigned to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator=(const char* anISOLatin1) { + return SetString(anISOLatin1); +} + + +/*------------------------------------------------------- + * assign given char to this string + * @update gess 3/27/98 + * @param aChar: char to be assignd to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator=(char aChar) { + return Append(PRUnichar(aChar)); +} + +/*------------------------------------------------------- + * assign given PRUnichar* to this string + * @update gess 3/27/98 + * @param anISOLatin1: buffer to be assigned to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::SetString(const PRUnichar* aStr,PRInt32 aLength) { + if(aStr!=0) { + PRInt32 len=(kNotFound==aLength) ? nsCRT::strlen(aStr) : aLength; + if(mCapacity< len ) + EnsureCapacityFor(len); + nsCRT::memcpy(mStr,aStr,len*sizeof(chartype)); + mLength=len; + mStr[mLength]=0; + } + else { + mLength=0; //This little bit of code handles the case + mStr[0]=0; //where some blockhead hands us a null string + } + return *this; +} + + +/*------------------------------------------------------- + * assign given char* to this string + * @update gess 3/27/98 + * @param anISOLatin1: buffer to be assigned to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::SetString(const char* anISOLatin1,PRInt32 aLength) { + if(anISOLatin1!=0) { + PRInt32 len=(kNotFound==aLength) ? nsCRT::strlen(anISOLatin1) : aLength; + if(mCapacitySetString(aStr); +} + + +/*------------------------------------------------------- + * assign given char to this string + * @update gess 3/27/98 + * @param aChar: char to be assignd to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator=(PRUnichar aChar) { + mLength=1; + if(mCapacity<1) + EnsureCapacityFor(kGrowthDelta); + mStr[0]=aChar; + mStr[1]=0; + return *this; +} + +/*------------------------------------------------------- + * append given string to this string + * @update gess 3/27/98 + * @param aString : string to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::Append(const nsString& aString,PRInt32 aLength) { + return Append(aString.mStr,aString.mLength); +} + +/*------------------------------------------------------- + * append given string to this string + * @update gess 3/27/98 + * @param aString : string to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::Append(const char* anISOLatin1,PRInt32 aLength) { + if(anISOLatin1!=0) { + PRInt32 len=(kNotFound==aLength) ? strlen(anISOLatin1) : aLength; + if(mLength+len > mCapacity) { + EnsureCapacityFor(mLength+len); + } + for(int i=0;i mCapacity) { + EnsureCapacityFor(mLength+len); + } + if(len>0) + nsCRT::memcpy(&mStr[mLength],aString,len*sizeof(chartype)); + mLength+=len; + mStr[mLength]=0; + } + return *this; +} + +/*------------------------------------------------------- + * append given string to this string + * @update gess 3/27/98 + * @param aString : string to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::Append(PRUnichar aChar) { + if(mLength < mCapacity) { + mStr[mLength++]=aChar; // the new string len < capacity, so just copy + mStr[mLength]=0; + } + else { // The new string exceeds our capacity + EnsureCapacityFor(mLength+1); + mStr[mLength++]=aChar; + mStr[mLength]=0; + } + return *this; +} + + +/*------------------------------------------------------- + * append given string to this string + * @update gess 3/27/98 + * @param aString : string to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator+=(const nsString &aString) { + return this->Append(aString.mStr,aString.mLength); +} + + +/*------------------------------------------------------- + * append given buffer to this string + * @update gess 3/27/98 + * @param anISOLatin1: buffer to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator+=(const char* anISOLatin1) { + return Append(anISOLatin1); +} + + +/*------------------------------------------------------- + * append given buffer to this string + * @update gess 3/27/98 + * @param aBuffer: buffer to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator+=(const PRUnichar* aBuffer) { + return Append(aBuffer); +} + + +/*------------------------------------------------------- + * append given char to this string + * @update gess 3/27/98 + * @param aChar: char to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator+=(PRUnichar aChar) { + return Append(aChar); +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsString& nsString::Append(PRInt32 aInteger,PRInt32 aRadix) { + char* fmt = "%d"; + if (8 == aRadix) { + fmt = "%o"; + } else if (16 == aRadix) { + fmt = "%x"; + } + char buf[40]; + PR_snprintf(buf, sizeof(buf), fmt, aInteger); + Append(buf); + return *this; +} + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsString& nsString::Append(float aFloat){ + char buf[40]; + PR_snprintf(buf, sizeof(buf), "%g", aFloat); + Append(buf); + return *this; +} + + + +/**------------------------------------------------------- + * Copies n characters from this string to given string, + * starting at the leftmost offset. + * + * + * @update gess 4/1/98 + * @param aCopy -- Receiving string + * @param aCount -- number of chars to copy + * @return number of chars copied + *------------------------------------------------------*/ +PRInt32 nsString::Left(nsString& aCopy,PRInt32 aCount) { + return Mid(aCopy,0,aCount); +} + +/**------------------------------------------------------- + * Copies n characters from this string to given string, + * starting at the given offset. + * + * + * @update gess 4/1/98 + * @param aCopy -- Receiving string + * @param aCount -- number of chars to copy + * @param anOffset -- position where copying begins + * @return number of chars copied + *------------------------------------------------------*/ +PRInt32 nsString::Mid(nsString& aCopy,PRInt32 anOffset,PRInt32 aCount) { + if(anOffsetaCopy.mLength) ? aCopy.mLength : aCount; //don't try to copy more than you are given + if(aCount>0) { + + //1st optimization: If you're inserting at end, then simply append! + if(anOffset>=mLength){ + Append(aCopy,aCopy.mLength); + return aCopy.mLength; + } + + if(mLength+aCount > mCapacity) { + EnsureCapacityFor(mLength+aCount); + } + + PRUnichar* last = mStr + mLength; + PRUnichar* first = mStr + anOffset-1; + PRUnichar* next = mStr + mLength + aCount; + + //Copy rightmost chars, up to offset+aCount... + while(first=0) && (anOffset= 'A') && (ch <= 'Z')) || ((ch >= 'a') && (ch <= 'z'))) { + return PR_TRUE; + } + return PR_FALSE; +} + +/**------------------------------------------------------- + * + * + * @update gess 3/31/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool nsString::IsSpace(PRUnichar ch) { + // XXX i18n + if ((ch == ' ') || (ch == '\r') || (ch == '\n') || (ch == '\t')) { + return PR_TRUE; + } + return PR_FALSE; +} + +/**------------------------------------------------------- + * This method trims characters found in aTrimSet from + * either end of the underlying string. + * + * @update gess 3/31/98 + * @param aTrimSet -- contains chars to be trimmed from + * both ends + * @return this + *------------------------------------------------------*/ +nsString& nsString::Trim(const char* aTrimSet, + PRBool aEliminateLeading, + PRBool aEliminateTrailing) +{ + PRUnichar* from = mStr; + PRUnichar* end = mStr + mLength-1; + PRUnichar* to = mStr; + + //begin by find the first char not in aTrimSet + if(aEliminateLeading) { + while (from < end) { + PRUnichar ch = *from; + if(!strchr(aTrimSet,char(ch))) { + break; + } + from++; + } + } + + //Now, find last char not in aTrimSet + if(aEliminateTrailing) { + while(end> from) { + PRUnichar ch = *end; + if(!strchr(aTrimSet,char(ch))) { + break; + } + end--; + } + } + + //now rewrite your string without unwanted + //leading or trailing characters. + while (from <= end) { + *to++ = *from++; + } + + *to = '\0'; + mLength = to - mStr; + return *this; +} + +/**------------------------------------------------------- + * + * + * @update gess 3/31/98 + * @param + * @return + *------------------------------------------------------*/ +nsString& nsString::CompressWhitespace( PRBool aEliminateLeading, + PRBool aEliminateTrailing) +{ + PRUnichar* from = mStr; + PRUnichar* end = mStr + mLength; + PRUnichar* to = from; + + Trim(" \r\n\t",aEliminateLeading,aEliminateTrailing); + + //this code converts /n, /t, /r into normal space ' '; + //it also eliminates runs of whitespace... + while (from < end) { + PRUnichar ch = *from++; + if (IsSpace(ch)) { + *to++ = ' '; + while (from < end) { + ch = *from++; + if (!IsSpace(ch)) { + *to++ = ch; + break; + } + } + } else { + *to++ = ch; + } + } + + *to = '\0'; + mLength = to - mStr; + return *this; +} + +/**------------------------------------------------------- + * XXX This is used by bina all over the place; not sure + * it belongs here though + * + * @update gess 3/31/98 + * @param + * @return + *------------------------------------------------------*/ +nsString& nsString::StripWhitespace() +{ + Trim(" \r\n\t"); + return StripChars("\r\t\n"); +} + + +/**------------------------------------------------------- + * Search for given buffer within this string + * + * @update gess 3/25/98 + * @param anISOLatin1Buf - charstr to be found + * @return offset in string, or -1 (kNotFound) + *------------------------------------------------------*/ +PRInt32 nsString::Find(const char* anISOLatin1Buf) const{ + NS_ASSERTION(0!=anISOLatin1Buf,kNullPointerError); + PRInt32 result=-1; + if(anISOLatin1Buf) { + PRInt32 len=strlen(anISOLatin1Buf); + if(len<=mLength) { //only enter if abuffer length is <= mStr length. + for(PRInt32 offset=0;offset0;i--){ + char* pos=strchr(anISOLatin1Set,char(mStr[i])); + if(pos) + return i; + } + } + return kNotFound; +} + +/**------------------------------------------------------- + * + * + * @update gess 3/25/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::FindLastCharInSet(nsString& aSet,PRInt32 anOffset) const{ + if(aSet.Length()) { + for(PRInt32 i=mLength-1;i>0;i--){ + PRInt32 pos=aSet.Find(mStr[i]); + if(kNotFound!=pos) + return i; + } + } + return kNotFound; +} + +/**------------------------------------------------------- + * + * + * @update gess 3/25/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::RFind(const PRUnichar* aString,PRBool aIgnoreCase) const{ + NS_ASSERTION(0!=aString,kNullPointerError); + + if(aString) { + PRInt32 len=nsCRT::strlen(aString); + if((len) && (len<=mLength)) { //only enter if abuffer length is <= mStr length. + for(PRInt32 offset=mLength-len;offset>=0;offset--) { + PRInt32 result=0; + if(aIgnoreCase) + result=nsCRT::strncasecmp(&mStr[offset],aString,len); + else result=nsCRT::strncmp(&mStr[offset],aString,len); + if(0==result) + return offset; //in this case, 0 means they match + } + } + } + return kNotFound; +} + +/**------------------------------------------------------- + * + * + * @update gess 3/25/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::RFind(const nsString& aString,PRBool aIgnoreCase) const{ + PRInt32 len=aString.mLength; + if((len) && (len<=mLength)) { //only enter if abuffer length is <= mStr length. + for(PRInt32 offset=mLength-len;offset>=0;offset--) { + PRInt32 result=0; + if(aIgnoreCase) + result=nsCRT::strncasecmp(&mStr[offset],aString.mStr,len); + else result=nsCRT::strncmp(&mStr[offset],aString.mStr,len); + if(0==result) + return offset; //in this case, 0 means they match + } + } + return kNotFound; +} + +/**------------------------------------------------------- + * + * + * @update gess 3/25/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::RFind(const char* anISOLatin1Set,PRBool aIgnoreCase) const{ + NS_ASSERTION(0!=anISOLatin1Set,kNullPointerError); + + if(anISOLatin1Set) { + PRInt32 len=strlen(anISOLatin1Set); + if((len) && (len<=mLength)) { //only enter if abuffer length is <= mStr length. + for(PRInt32 offset=mLength-len;offset>=0;offset--) { + PRInt32 result=0; + if(aIgnoreCase) + result=nsCRT::strncasecmp(&mStr[offset],anISOLatin1Set,len); + else result=nsCRT::strncmp(&mStr[offset],anISOLatin1Set,len); + if(0==result) + return offset; //in this case, 0 means they match + } + } + } + return kNotFound; +} + + +/**------------------------------------------------------- + * Scans this string backwards for first occurance of + * the given char. + * + * @update gess 3/25/98 + * @param + * @return offset of char in string, or -1 (kNotFound) + *------------------------------------------------------*/ +PRInt32 nsString::RFind(PRUnichar aChar,PRBool aIgnoreCase) const{ + chartype uc=nsCRT::ToUpper(aChar); + for(PRInt32 offset=mLength-1;offset>0;offset--) + if(aIgnoreCase) { + if(nsCRT::ToUpper(mStr[offset])==uc) + return offset; + } + else if(mStr[offset]==aChar) + return offset; //in this case, 0 means they match + return kNotFound; + +} + + //****** comparision methods... ******* + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::Compare(const char *anISOLatin1,PRBool aIgnoreCase) const { + if (aIgnoreCase) { + return nsCRT::strcasecmp(mStr,anISOLatin1); + } + return nsCRT::strcmp(mStr,anISOLatin1); +} + +/*------------------------------------------------------- + * LAST MODS: gess + * + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::Compare(const nsString &S,PRBool aIgnoreCase) const { + if (aIgnoreCase) { + return nsCRT::strcasecmp(mStr,S.mStr); + } + return nsCRT::strcmp(mStr,S.mStr); +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::Compare(const PRUnichar* aString,PRBool aIgnoreCase) const { + if (aIgnoreCase) { + return nsCRT::strcasecmp(mStr,aString); + } + return nsCRT::strcmp(mStr,aString); +} + + +PRInt32 nsString::operator==(const nsString &S) const {return Compare(S)==0;} +PRInt32 nsString::operator==(const char *s) const {return Compare(s)==0;} +PRInt32 nsString::operator==(const PRUnichar *s) const {return Compare(s)==0;} +PRInt32 nsString::operator!=(const nsString &S) const {return Compare(S)!=0;} +PRInt32 nsString::operator!=(const char *s ) const {return Compare(s)!=0;} +PRInt32 nsString::operator!=(const PRUnichar *s) const {return Compare(s)==0;} +PRInt32 nsString::operator<(const nsString &S) const {return Compare(S)<0;} +PRInt32 nsString::operator<(const char *s) const {return Compare(s)<0;} +PRInt32 nsString::operator<(const PRUnichar *s) const {return Compare(s)==0;} +PRInt32 nsString::operator>(const nsString &S) const {return Compare(S)>0;} +PRInt32 nsString::operator>(const char *s) const {return Compare(s)>0;} +PRInt32 nsString::operator>(const PRUnichar *s) const {return Compare(s)==0;} +PRInt32 nsString::operator<=(const nsString &S) const {return Compare(S)<=0;} +PRInt32 nsString::operator<=(const char *s) const {return Compare(s)<=0;} +PRInt32 nsString::operator<=(const PRUnichar *s) const {return Compare(s)==0;} +PRInt32 nsString::operator>=(const nsString &S) const {return Compare(S)>=0;} +PRInt32 nsString::operator>=(const char *s) const {return Compare(s)>=0;} +PRInt32 nsString::operator>=(const PRUnichar *s) const {return Compare(s)==0;} + + + +/*------------------------------------------------------- + * Compare this to given string + * @update gess 3/27/98 + * @param aString -- string to compare to this + * @return TRUE if equal + *------------------------------------------------------*/ +PRBool nsString::Equals(const nsString& aString) const { + PRInt32 result=nsCRT::strcmp(mStr,aString.mStr); + return PRBool(0==result); +} + + +/*------------------------------------------------------- + * Compare this to given string + * @update gess 3/27/98 + * @param aCString -- Cstr to compare to this + * @return TRUE if equal + *------------------------------------------------------*/ +PRBool nsString::Equals(const char* aCString) const{ + NS_ASSERTION(0!=aCString,kNullPointerError); + PRInt32 result=nsCRT::strcmp(mStr,aCString); + return PRBool(0==result); +} + + +/*------------------------------------------------------- + * Compare this to given atom + * @update gess 3/27/98 + * @param aAtom -- atom to compare to this + * @return TRUE if equal + *------------------------------------------------------*/ +PRBool nsString::Equals(const nsIAtom* aAtom) const +{ + NS_ASSERTION(0!=aAtom,kNullPointerError); + PRInt32 result=nsCRT::strcmp(mStr,aAtom->GetUnicode()); + return PRBool(0==result); +} + + +/*------------------------------------------------------- + * Compare given strings + * @update gess 3/27/98 + * @param s1 -- first string to be compared + * @param s2 -- second string to be compared + * @return TRUE if equal + *------------------------------------------------------*/ +PRBool nsString::Equals(const PRUnichar* s1, const PRUnichar* s2) const { + NS_ASSERTION(0!=s1,kNullPointerError); + NS_ASSERTION(0!=s2,kNullPointerError); + PRBool result=PR_FALSE; + if((s1) && (s2)){ + PRInt32 cmp=nsCRT::strcmp(s1,s2); + result=PRBool(0==cmp); + } + return result; +} + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool nsString::EqualsIgnoreCase(const nsString& aString) const{ + PRInt32 result=nsCRT::strcasecmp(mStr,aString.mStr); + return PRBool(0==result); +} + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool nsString::EqualsIgnoreCase(const nsIAtom *aAtom) const{ + NS_ASSERTION(0!=aAtom,kNullPointerError); + PRBool result=PR_FALSE; + if(aAtom){ + PRInt32 cmp=nsCRT::strcasecmp(mStr,aAtom->GetUnicode()); + result=PRBool(0==cmp); + } + return result; +} + + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool nsString::EqualsIgnoreCase(const PRUnichar* s1, const PRUnichar* s2) const { + NS_ASSERTION(0!=s1,kNullPointerError); + NS_ASSERTION(0!=s2,kNullPointerError); + PRBool result=PR_FALSE; + if((s1) && (s2)){ + PRInt32 cmp=nsCRT::strcasecmp(s1,s2); + result=PRBool(0==cmp); + } + return result; +} + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool nsString::EqualsIgnoreCase(const char* aCString) const { + NS_ASSERTION(0!=aCString,kNullPointerError); + PRBool result=PR_FALSE; + if(aCString){ + PRInt32 cmp=nsCRT::strcasecmp(mStr,aCString); + result=PRBool(0==cmp); + } + return result; +} + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +void nsString::DebugDump(ostream& aStream) const { + for(int i=0;itemp3.Length(),"constructor error!"); //should be char longer + + nsString* es1=temp2.ToNewString(); //this should make us a new string + char* es2=temp2.ToNewCString(); + for(i=0;itemp8,"Error: Comparision (>) routine"); + NS_ASSERTION(temp9>aaaa,"Error: Comparision (>) routine"); + + NS_ASSERTION(temp8<=temp8,"Error: Comparision (<=) routine"); + NS_ASSERTION(temp8<=temp9,"Error: Comparision (<=) routine"); + NS_ASSERTION(temp8<=bbbb,"Error: Comparision (<=) routine"); + + NS_ASSERTION(temp9>=temp9,"Error: Comparision (<=) routine"); + NS_ASSERTION(temp9>=temp8,"Error: Comparision (<=) routine"); + NS_ASSERTION(temp9>=aaaa,"Error: Comparision (<=) routine"); + + NS_ASSERTION(temp8.Equals(temp8),"Equals error"); + NS_ASSERTION(temp8.Equals(aaaa),"Equals error"); + + nsString temp10(temp8); + temp10.ToUpperCase(); + NS_ASSERTION(temp8.EqualsIgnoreCase(temp10),"Equals error"); + NS_ASSERTION(temp8.EqualsIgnoreCase("AAAA"),"Equals error"); + + + //********************************************** + //Now let's test a few string MANIPULATORS... + //********************************************** + + nsAutoString ab("ab"); + nsString abcde("cde"); + abcde.Insert(ab,0,2); + nsAutoString xxx("xxx"); + abcde.Insert(xxx,2,3); + + temp2.ToUpperCase(); + for(i=0;i mCapacity) { + PRInt32 size = mCapacity * 2; + if (size < aNewLength) { + size = mCapacity + aNewLength; + } + mCapacity=size; + chartype* temp = new chartype[mCapacity+1]; + if (mLength > 0) { + nsCRT::memcpy(temp, mStr, mLength * sizeof(chartype)); + } + mStr = temp; + } +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsAutoString::nsAutoString(const PRUnichar* unicode, PRInt32 uslen) { + mStr = mBuf; + mCapacity = sizeof(mBuf) / sizeof(chartype); + if (0 == uslen) { + uslen = nsCRT::strlen(unicode); + } + Append(unicode, uslen); +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsAutoString::~nsAutoString() +{ + if (mStr == mBuf) { + // Force to null so that baseclass dtor doesn't do damage + mStr = nsnull; + } +} + + +/**------------------------------------------------------- + * + * + * @update gess 3/31/98 + * @param + * @return + *------------------------------------------------------*/ +void nsAutoString::SelfTest(){ + nsAutoString xas("Hello there"); + xas.Append("this string exceeds the max size"); + xas.DebugDump(cout); +} + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +NS_BASE int fputs(const nsString& aString, FILE* out) +{ + char buf[100]; + char* cp = buf; + PRInt32 len = aString.Length(); + if (len >= sizeof(buf)) { + cp = aString.ToNewCString(); + } else { + aString.ToCString(cp, len + 1); + } + ::fwrite(cp, 1, len, out); + if (cp != buf) { + delete cp; + } + return (int) len; +} + diff --git a/mozilla/xpcom/ds/nsString.h b/mozilla/xpcom/ds/nsString.h new file mode 100644 index 00000000000..dc26545c53b --- /dev/null +++ b/mozilla/xpcom/ds/nsString.h @@ -0,0 +1,233 @@ +/* -*- 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. + */ + +/** + * MODULE NOTES: + * LAST MODS: gess 28Feb98 + * + * This very simple string class that knows how to do + * efficient (dynamic) resizing. It offers almost no + * i18n support, and will undoubtedly have to be replaced. + * + */ + +#ifndef _NSSTRING +#define _NSSTRING + + +#include "prtypes.h" +#include "nscore.h" +#include "nsIAtom.h" +#include +#include + + +class NS_BASE nsString { + public: + + nsString(const char* anISOLatin1=""); + nsString(const nsString&); + nsString(const PRUnichar* aUnicode); + virtual ~nsString(); + + PRInt32 Length() const { return mLength; } + + void SetLength(PRInt32 aLength); + void Truncate(PRInt32 anIndex=0); + virtual void EnsureCapacityFor(PRInt32 aNewLength); + + ///accessor methods + //@{ + PRUnichar* GetUnicode(void) const; + operator PRUnichar*() const; + +#if 0 + // This is NOT allowed because it has to do a malloc to + // create the iso-latin-1 version of the unicode string + operator char*() const; +#endif + + PRUnichar* operator()() const; + PRUnichar operator()(PRInt32 i) const; + PRUnichar& operator[](PRInt32 i) const; + PRUnichar& CharAt(PRInt32 anIndex) const; + PRUnichar& First() const; + PRUnichar& Last() const; + + //string creation methods... + nsString operator+(const nsString& aString); + nsString operator+(const char* anISOLatin1); + nsString operator+(char aChar); + nsString operator+(const PRUnichar* aBuffer); + nsString operator+(PRUnichar aChar); + + void ToLowerCase(); + void ToLowerCase(nsString& aString) const; + void ToUpperCase(); + void ToUpperCase(nsString& aString) const; + + nsString* ToNewString() const; + char* ToNewCString() const; + + char* ToCString(char* aBuf,PRInt32 aBufLength) const; + void ToString(nsString& aString) const; + + PRUnichar* ToNewUnicode() const; + float ToFloat(PRInt32* aErrorCode) const; + PRInt32 ToInteger(PRInt32* aErrorCode) const; + //@} + + ///string manipulation methods... + //@{ + nsString& operator=(const nsString& aString); + nsString& operator=(const char* anISOLatin1); + nsString& operator=(char aChar); + nsString& operator=(const PRUnichar* aBuffer); + nsString& operator=(PRUnichar aChar); + nsString& SetString(const PRUnichar* aStr,PRInt32 aLength=-1); + nsString& SetString(const char* anISOLatin1,PRInt32 aLength=-1); + + nsString& operator+=(const nsString& aString); + nsString& operator+=(const char* anISOLatin1); + nsString& operator+=(const PRUnichar* aBuffer); + nsString& operator+=(PRUnichar aChar); + nsString& Append(const nsString& aString,PRInt32 aLength=-1); + nsString& Append(const char* anISOLatin1,PRInt32 aLength=-1); + nsString& Append(char aChar); + nsString& Append(const PRUnichar* aBuffer,PRInt32 aLength=-1); + nsString& Append(PRUnichar aChar); + nsString& Append(PRInt32 aInteger,PRInt32 aRadix); //radix=8,10 or 16 + nsString& Append(float aFloat); + + PRInt32 Left(nsString& aCopy,PRInt32 aCount); + PRInt32 Mid(nsString& aCopy,PRInt32 anOffset,PRInt32 aCount); + PRInt32 Right(nsString& aCopy,PRInt32 aCount); + PRInt32 Insert(nsString& aCopy,PRInt32 anOffset,PRInt32 aCount=-1); + + nsString& Cut(PRInt32 anOffset,PRInt32 aCount); + nsString& StripChars(const char* aSet); + nsString& StripWhitespace(); + nsString& Trim( const char* aSet, + PRBool aEliminateLeading=PR_TRUE, + PRBool aEliminateTrailing=PR_TRUE); + nsString& CompressWhitespace( PRBool aEliminateLeading=PR_TRUE, + PRBool aEliminateTrailing=PR_TRUE); + static PRBool IsSpace(PRUnichar ch); + static PRBool IsAlpha(PRUnichar ch); + //@} + + ///searching methods... + //@{ + PRInt32 Find(const char* anISOLatin1) const; + PRInt32 Find(const PRUnichar* aString) const; + PRInt32 Find(PRUnichar aChar,PRInt32 offset=0) const; + PRInt32 Find(const nsString& aString) const; + PRInt32 FindFirstCharInSet(const char* anISOLatin1Set,PRInt32 offset=0) const; + PRInt32 FindFirstCharInSet(nsString& aString,PRInt32 offset=0) const; + PRInt32 FindLastCharInSet(const char* anISOLatin1Set,PRInt32 offset=0) const; + PRInt32 FindLastCharInSet(nsString& aString,PRInt32 offset=0) const; + PRInt32 RFind(const char* anISOLatin1,PRBool aIgnoreCase=PR_FALSE) const; + PRInt32 RFind(const PRUnichar* aString,PRBool aIgnoreCase=PR_FALSE) const; + PRInt32 RFind(const nsString& aString,PRBool aIgnoreCase=PR_FALSE) const; + PRInt32 RFind(PRUnichar aChar,PRBool aIgnoreCase=PR_FALSE) const; + //@} + + ///comparision methods... + //@{ + virtual PRInt32 Compare(const nsString &S,PRBool aIgnoreCase=PR_FALSE) const; + virtual PRInt32 Compare(const char *anISOLatin1,PRBool aIgnoreCase=PR_FALSE) const; + virtual PRInt32 Compare(const PRUnichar *aString,PRBool aIgnoreCase=PR_FALSE) const; + + PRInt32 operator==(const nsString &S) const; + PRInt32 operator==(const char *anISOLatin1) const; + PRInt32 operator==(const PRUnichar* aString) const; + PRInt32 operator!=(const nsString &S) const; + PRInt32 operator!=(const char *anISOLatin1) const; + PRInt32 operator!=(const PRUnichar* aString) const; + PRInt32 operator<(const nsString &S) const; + PRInt32 operator<(const char *anISOLatin1) const; + PRInt32 operator<(const PRUnichar* aString) const; + PRInt32 operator>(const nsString &S) const; + PRInt32 operator>(const char *anISOLatin1) const; + PRInt32 operator>(const PRUnichar* aString) const; + PRInt32 operator<=(const nsString &S) const; + PRInt32 operator<=(const char *anISOLatin1) const; + PRInt32 operator<=(const PRUnichar* aString) const; + PRInt32 operator>=(const nsString &S) const; + PRInt32 operator>=(const char *anISOLatin1) const; + PRInt32 operator>=(const PRUnichar* aString) const; + + PRBool Equals(const nsString& aString) const; + PRBool Equals(const char* anISOLatin1) const; + PRBool Equals(const nsIAtom *aAtom) const; + PRBool Equals(const PRUnichar* s1, const PRUnichar* s2) const; + + PRBool EqualsIgnoreCase(const nsString& aString) const; + PRBool EqualsIgnoreCase(const char* anISOLatin1) const; + PRBool EqualsIgnoreCase(const nsIAtom *aAtom) const; + PRBool EqualsIgnoreCase(const PRUnichar* s1, const PRUnichar* s2) const; + //@} + + static void SelfTest(); + virtual void DebugDump(ostream& aStream) const; + + protected: + +typedef PRUnichar chartype; + + chartype* mStr; + PRInt32 mLength; + PRInt32 mCapacity; + static PRInt32 mInstanceCount; +}; + +extern NS_BASE int fputs(const nsString& aString, FILE* out); + +//---------------------------------------------------------------------- + +/** + * A version of nsString which is designed to be used as an automatic + * variable. It attempts to operate out of a fixed size internal + * buffer until too much data is added; then a dynamic buffer is + * allocated and grown as necessary. + */ +// XXX template this with a parameter for the size of the buffer? +class NS_BASE nsAutoString : public nsString { +public: + nsAutoString(); + nsAutoString(const nsString& other); + nsAutoString(const nsAutoString& other); + nsAutoString(PRUnichar aChar); + nsAutoString(const char* isolatin1); + nsAutoString(const PRUnichar* us, PRInt32 uslen = -1); + virtual ~nsAutoString(); + + static void SelfTest(); + +protected: + virtual void EnsureCapacityFor(PRInt32 aNewLength); + + PRUnichar mBuf[32]; + +private: + // XXX these need writing I suppose + nsAutoString& operator=(const nsAutoString& other); +}; + +#endif + diff --git a/mozilla/xpcom/ds/nsUnicharBuffer.cpp b/mozilla/xpcom/ds/nsUnicharBuffer.cpp new file mode 100644 index 00000000000..8c001afe069 --- /dev/null +++ b/mozilla/xpcom/ds/nsUnicharBuffer.cpp @@ -0,0 +1,137 @@ +/* -*- 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 "nsIUnicharBuffer.h" +#include "nsIUnicharInputStream.h" +#include "nsCRT.h" + +#define MIN_BUFFER_SIZE 32 + +class UnicharBufferImpl : public nsIUnicharBuffer { +public: + UnicharBufferImpl(PRInt32 aBufferSize); + ~UnicharBufferImpl(); + + NS_DECL_ISUPPORTS + virtual PRInt32 GetLength() const; + virtual PRInt32 GetBufferSize() const; + virtual PRUnichar* GetBuffer() const; + virtual PRBool Grow(PRInt32 aNewSize); + virtual PRInt32 Fill(PRInt32* aErrorCode, nsIUnicharInputStream* aStream, + PRInt32 aKeep); + + PRUnichar* mBuffer; + PRInt32 mSpace; + PRInt32 mLength; +}; + +UnicharBufferImpl::UnicharBufferImpl(PRInt32 aBufferSize) +{ + if (PRUint32(aBufferSize) < MIN_BUFFER_SIZE) { + aBufferSize = MIN_BUFFER_SIZE; + } + mSpace = aBufferSize; + mBuffer = new PRUnichar[aBufferSize]; + mLength = 0; + NS_INIT_REFCNT(); +} + +NS_DEFINE_IID(kUnicharBufferIID, NS_IUNICHAR_BUFFER_IID); +NS_IMPL_ISUPPORTS(UnicharBufferImpl,kUnicharBufferIID) + +UnicharBufferImpl::~UnicharBufferImpl() +{ + if (nsnull != mBuffer) { + delete mBuffer; + mBuffer = nsnull; + } + mLength = 0; +} + +PRInt32 UnicharBufferImpl::GetLength() const +{ + return mLength; +} + +PRInt32 UnicharBufferImpl::GetBufferSize() const +{ + return mSpace; +} + +PRUnichar* UnicharBufferImpl::GetBuffer() const +{ + return mBuffer; +} + +PRBool UnicharBufferImpl::Grow(PRInt32 aNewSize) +{ + if (PRUint32(aNewSize) < MIN_BUFFER_SIZE) { + aNewSize = MIN_BUFFER_SIZE; + } + PRUnichar* newbuf = new PRUnichar[aNewSize]; + if (nsnull != newbuf) { + if (0 != mLength) { + nsCRT::memcpy(newbuf, mBuffer, mLength * sizeof(PRUnichar)); + } + delete mBuffer; + mBuffer = newbuf; + return PR_TRUE; + } + return PR_FALSE; +} + +PRInt32 UnicharBufferImpl::Fill(PRInt32* aErrorCode, + nsIUnicharInputStream* aStream, + PRInt32 aKeep) +{ + NS_PRECONDITION(nsnull != aStream, "null stream"); + NS_PRECONDITION(PRUint32(aKeep) < PRUint32(mLength), "illegal keep count"); + if ((nsnull == aStream) || (PRUint32(aKeep) >= PRUint32(mLength))) { + // whoops + *aErrorCode = NS_INPUTSTREAM_ILLEGAL_ARGS; + return -1; + } + + if (0 != aKeep) { + // Slide over kept data + nsCRT::memmove(mBuffer, mBuffer + (mLength - aKeep), + aKeep * sizeof(PRUnichar)); + } + + // Read in some new data + mLength = aKeep; + PRInt32 amount = mSpace - aKeep; + PRInt32 nb = aStream->Read(aErrorCode, mBuffer, aKeep, amount); + if (nb > 0) { + mLength += nb; + } + return nb; +} + +NS_BASE nsresult NS_NewUnicharBuffer(nsIUnicharBuffer** aInstancePtrResult, + nsISupports* aOuter, + PRInt32 aBufferSize) +{ + if (nsnull != aOuter) { + return NS_ERROR_NO_AGGREGATION; + } + UnicharBufferImpl* it = new UnicharBufferImpl(aBufferSize); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kUnicharBufferIID, (void **) aInstancePtrResult); +} diff --git a/mozilla/xpcom/ds/nsUnitConversion.h b/mozilla/xpcom/ds/nsUnitConversion.h new file mode 100644 index 00000000000..14a579326f2 --- /dev/null +++ b/mozilla/xpcom/ds/nsUnitConversion.h @@ -0,0 +1,71 @@ +/* -*- 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. + */ +#ifndef nsUnitConversion_h__ +#define nsUnitConversion_h__ + +#include "nscore.h" +#include + +/// Unit conversion macros +//@{ +#define TWIPS_CONST 20 +#define TWIPS_CONST_FLOAT 20.0f + +#define NS_POINTS_TO_TWIPS_INT(x) ((PRInt32)(TWIPS_CONST * (x))) +#define NS_TWIPS_TO_POINTS_INT(x) ((PRInt32)((x) / TWIPS_CONST)) + +#define NS_POINTS_TO_TWIPS_FLOAT(x) (TWIPS_CONST_FLOAT * (x)) +#define NS_TWIPS_TO_POINTS_FLOAT(x) ((x) / TWIPS_CONST_FLOAT) + +#define NS_INCHES_TO_TWIPS(x) (72.0f * TWIPS_CONST_FLOAT * (x)) // 72 points per inch +#define NS_FEET_TO_TWIPS(x) (72.0f * 12.0f * TWIPS_CONST_FLOAT * (x)) +#define NS_MILES_TO_TWIPS(x) (72.0f * 12.0f * 5280.0f * TWIPS_CONST_FLOAT * (x)) + +#define NS_MILLIMETERS_TO_TWIPS(x) (72.0f * 0.03937f * TWIPS_CONST_FLOAT * (x)) +#define NS_CENTIMETERS_TO_TWIPS(x) (72.0f * 0.3937f * TWIPS_CONST_FLOAT * (x)) +#define NS_METERS_TO_TWIPS(x) (72.0f * 39.37f * TWIPS_CONST_FLOAT * (x)) +#define NS_KILOMETERS_TO_TWIPS(x) (72.0f * 39370.0f * TWIPS_CONST_FLOAT * (x)) + +#define NS_PICAS_TO_TWIPS(x) (12.0f * TWIPS_CONST_FLOAT * (x)) // 12 points per pica +#define NS_DIDOTS_TO_TWIPS(x) ((16.0f / 15.0f) * TWIPS_CONST_FLOAT * (x)) // 15 didots per 16 points +#define NS_CICEROS_TO_TWIPS(x) ((12.0f * 16.0f / 15.0f) * TWIPS_CONST_FLOAT * (x)) // 12 didots per cicero + +#define NS_TWIPS_TO_INCHES(x) ((1.0f / (72.0f * TWIPS_CONST_FLOAT)) * (x)) +#define NS_TWIPS_TO_FEET(x) ((1.0f / (72.0f * 12.0f * TWIPS_CONST_FLOAT)) * (x)) +#define NS_TWIPS_TO_MILES(x) ((1.0f / (72.0f * 12.0f * 5280.0f * TWIPS_CONST_FLOAT)) * (x)) + +#define NS_TWIPS_TO_MILLIMETERS(x) ((1.0f / (72.0f * 0.03937f * TWIPS_CONST_FLOAT)) * (x)) +#define NS_TWIPS_TO_CENTIMETERS(x) ((1.0f / (72.0f * 0.3937f * TWIPS_CONST_FLOAT)) * (x)) +#define NS_TWIPS_TO_METERS(x) ((1.0f / (72.0f * 39.37f * TWIPS_CONST_FLOAT)) * (x)) +#define NS_TWIPS_TO_KILOMETERS(x) ((1.0f / (72.0f * 39370.0f * TWIPS_CONST_FLOAT)) * (x)) + +#define NS_TWIPS_TO_PICAS(x) ((1.0f / (12.0f * TWIPS_CONST_FLOAT)) * (x)) +#define NS_TWIPS_TO_DIDOTS(x) ((1.0f / ((16.0f / 15.0f) * TWIPS_CONST_FLOAT)) * (x)) +#define NS_TWIPS_TO_CICEROS(x) ((1.0f / ((12.0f * 16.0f / 15.0f) * TWIPS_CONST_FLOAT)) * (x)) +//@} + + +/// use these for all of your rounding needs... +//@{ + +#define NS_TO_INT_FLOOR(x) ((PRInt32)floor(x)) +#define NS_TO_INT_CEIL(x) ((PRInt32)ceil(x)) +#define NS_TO_INT_ROUND(x) ((PRInt32)floor((x) + 0.5)) +#define NS_TO_INT_ROUND_EXCLUSIVE(x) ((PRInt32)floor((x) + 0.4999999999999999)) +//@} +#endif diff --git a/mozilla/xpcom/ds/nsVoidArray.cpp b/mozilla/xpcom/ds/nsVoidArray.cpp new file mode 100644 index 00000000000..7f52d1fe1c1 --- /dev/null +++ b/mozilla/xpcom/ds/nsVoidArray.cpp @@ -0,0 +1,172 @@ +/* -*- 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 "nsVoidArray.h" +#include "nsCRT.h" + +static PRInt32 kGrowArrayBy = 8; + +nsVoidArray::nsVoidArray() +{ + mArray = nsnull; + mArraySize = 0; + mCount = 0; +} + +nsVoidArray& nsVoidArray::operator=(const nsVoidArray& other) +{ + if (nsnull != mArray) { + delete mArray; + } + PRInt32 otherCount = other.mCount; + mArraySize = otherCount; + mCount = otherCount; + if (otherCount != 0) { + mArray = new void*[otherCount]; + nsCRT::memcpy(mArray, other.mArray, otherCount * sizeof(void*)); + } else { + mArray = nsnull; + } + return *this; +} + +nsVoidArray::~nsVoidArray() +{ + if (nsnull != mArray) { + delete mArray; + } +} + +void* nsVoidArray::ElementAt(PRInt32 aIndex) const +{ + if (PRUint32(aIndex) >= PRUint32(mCount)) { + return nsnull; + } + return mArray[aIndex]; +} + +PRInt32 nsVoidArray::IndexOf(void* aPossibleElement) const +{ + void** ap = mArray; + void** end = ap + mCount; + while (ap < end) { + if (*ap == aPossibleElement) { + return ap - mArray; + } + ap++; + } + return -1; +} + +PRBool nsVoidArray::InsertElementAt(void* aElement, PRInt32 aIndex) +{ + PRInt32 oldCount = mCount; + if (PRUint32(aIndex) > PRUint32(oldCount)) { + // An invalid index causes the insertion to fail + return PR_FALSE; + } + + if (oldCount + 1 > mArraySize) { + // We have to grow the array + PRInt32 newCount = oldCount + kGrowArrayBy; + void** newArray = new void*[newCount]; + if (mArray != nsnull && aIndex != 0) + nsCRT::memcpy(newArray, mArray, aIndex * sizeof(void*)); + PRInt32 slide = oldCount - aIndex; + if (0 != slide) { + // Slide data over to make room for the insertion + nsCRT::memcpy(newArray + aIndex + 1, mArray + aIndex, + slide * sizeof(void*)); + } + if (mArray != nsnull) + delete mArray; + mArray = newArray; + mArraySize = newCount; + } else { + // The array is already large enough + PRInt32 slide = oldCount - aIndex; + if (0 != slide) { + // Slide data over to make room for the insertion + nsCRT::memmove(mArray + aIndex + 1, mArray + aIndex, + slide * sizeof(void*)); + } + } + mArray[aIndex] = aElement; + mCount++; + + return PR_TRUE; +} + +PRBool nsVoidArray::ReplaceElementAt(void* aElement, PRInt32 aIndex) +{ + if (PRUint32(aIndex) >= PRUint32(mCount)) { + // An invalid index causes the replace to fail + return PR_FALSE; + } + mArray[aIndex] = aElement; + return PR_TRUE; +} + +PRBool nsVoidArray::RemoveElementAt(PRInt32 aIndex) +{ + PRInt32 oldCount = mCount; + if (PRUint32(aIndex) >= PRUint32(oldCount)) { + // An invalid index causes the replace to fail + return PR_FALSE; + } + + // We don't need to move any elements if we're removing the + // last element in the array + if (aIndex < (oldCount - 1)) { + nsCRT::memmove(mArray + aIndex, mArray + aIndex + 1, + (oldCount - 1 - aIndex) * sizeof(void*)); + } + + mCount--; + return PR_TRUE; +} + +PRBool nsVoidArray::RemoveElement(void* aElement) +{ + void** ep = mArray; + void** end = ep + mCount; + while (ep < end) { + void* e = *ep++; + if (e == aElement) { + ep--; + return RemoveElementAt(PRInt32(ep - mArray)); + } + } + return PR_FALSE; +} + +void nsVoidArray::Clear() +{ + mCount = 0; +} + +void nsVoidArray::Compact() +{ + PRInt32 count = mCount; + if (mArraySize != count) { + void** newArray = new void*[count]; + nsCRT::memcpy(newArray, mArray, count * sizeof(void*)); + delete mArray; + mArray = newArray; + mArraySize = count; + } +} diff --git a/mozilla/xpcom/ds/nsVoidArray.h b/mozilla/xpcom/ds/nsVoidArray.h new file mode 100644 index 00000000000..40394ff3b3e --- /dev/null +++ b/mozilla/xpcom/ds/nsVoidArray.h @@ -0,0 +1,64 @@ +/* -*- 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. + */ +#ifndef nsVoidArray_h___ +#define nsVoidArray_h___ + +#include "nscore.h" + +/// A basic zero-based array of void*'s that manages its own memory +class NS_BASE nsVoidArray { +public: + nsVoidArray(); + ~nsVoidArray(); + + nsVoidArray& operator=(const nsVoidArray& other); + + PRInt32 Count() const { + return mCount; + } + + void* ElementAt(PRInt32 aIndex) const; + void* operator[](PRInt32 aIndex) const { return ElementAt(aIndex); } + + PRInt32 IndexOf(void* aPossibleElement) const; + + PRBool InsertElementAt(void* aElement, PRInt32 aIndex); + + PRBool ReplaceElementAt(void* aElement, PRInt32 aIndex); + + PRBool AppendElement(void* aElement) { + return InsertElementAt(aElement, mCount); + } + + PRBool RemoveElement(void* aElement); + PRBool RemoveElementAt(PRInt32 aIndex); + void Clear(); + + void Compact(); + +protected: + void** mArray; + PRInt32 mArraySize; + PRInt32 mCount; + +private: + /// Copy constructors are not allowed + nsVoidArray(const nsVoidArray& other); +}; + +#endif /* nsVoidArray_h___ */ diff --git a/mozilla/xpcom/glue/nsVoidArray.cpp b/mozilla/xpcom/glue/nsVoidArray.cpp new file mode 100644 index 00000000000..7f52d1fe1c1 --- /dev/null +++ b/mozilla/xpcom/glue/nsVoidArray.cpp @@ -0,0 +1,172 @@ +/* -*- 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 "nsVoidArray.h" +#include "nsCRT.h" + +static PRInt32 kGrowArrayBy = 8; + +nsVoidArray::nsVoidArray() +{ + mArray = nsnull; + mArraySize = 0; + mCount = 0; +} + +nsVoidArray& nsVoidArray::operator=(const nsVoidArray& other) +{ + if (nsnull != mArray) { + delete mArray; + } + PRInt32 otherCount = other.mCount; + mArraySize = otherCount; + mCount = otherCount; + if (otherCount != 0) { + mArray = new void*[otherCount]; + nsCRT::memcpy(mArray, other.mArray, otherCount * sizeof(void*)); + } else { + mArray = nsnull; + } + return *this; +} + +nsVoidArray::~nsVoidArray() +{ + if (nsnull != mArray) { + delete mArray; + } +} + +void* nsVoidArray::ElementAt(PRInt32 aIndex) const +{ + if (PRUint32(aIndex) >= PRUint32(mCount)) { + return nsnull; + } + return mArray[aIndex]; +} + +PRInt32 nsVoidArray::IndexOf(void* aPossibleElement) const +{ + void** ap = mArray; + void** end = ap + mCount; + while (ap < end) { + if (*ap == aPossibleElement) { + return ap - mArray; + } + ap++; + } + return -1; +} + +PRBool nsVoidArray::InsertElementAt(void* aElement, PRInt32 aIndex) +{ + PRInt32 oldCount = mCount; + if (PRUint32(aIndex) > PRUint32(oldCount)) { + // An invalid index causes the insertion to fail + return PR_FALSE; + } + + if (oldCount + 1 > mArraySize) { + // We have to grow the array + PRInt32 newCount = oldCount + kGrowArrayBy; + void** newArray = new void*[newCount]; + if (mArray != nsnull && aIndex != 0) + nsCRT::memcpy(newArray, mArray, aIndex * sizeof(void*)); + PRInt32 slide = oldCount - aIndex; + if (0 != slide) { + // Slide data over to make room for the insertion + nsCRT::memcpy(newArray + aIndex + 1, mArray + aIndex, + slide * sizeof(void*)); + } + if (mArray != nsnull) + delete mArray; + mArray = newArray; + mArraySize = newCount; + } else { + // The array is already large enough + PRInt32 slide = oldCount - aIndex; + if (0 != slide) { + // Slide data over to make room for the insertion + nsCRT::memmove(mArray + aIndex + 1, mArray + aIndex, + slide * sizeof(void*)); + } + } + mArray[aIndex] = aElement; + mCount++; + + return PR_TRUE; +} + +PRBool nsVoidArray::ReplaceElementAt(void* aElement, PRInt32 aIndex) +{ + if (PRUint32(aIndex) >= PRUint32(mCount)) { + // An invalid index causes the replace to fail + return PR_FALSE; + } + mArray[aIndex] = aElement; + return PR_TRUE; +} + +PRBool nsVoidArray::RemoveElementAt(PRInt32 aIndex) +{ + PRInt32 oldCount = mCount; + if (PRUint32(aIndex) >= PRUint32(oldCount)) { + // An invalid index causes the replace to fail + return PR_FALSE; + } + + // We don't need to move any elements if we're removing the + // last element in the array + if (aIndex < (oldCount - 1)) { + nsCRT::memmove(mArray + aIndex, mArray + aIndex + 1, + (oldCount - 1 - aIndex) * sizeof(void*)); + } + + mCount--; + return PR_TRUE; +} + +PRBool nsVoidArray::RemoveElement(void* aElement) +{ + void** ep = mArray; + void** end = ep + mCount; + while (ep < end) { + void* e = *ep++; + if (e == aElement) { + ep--; + return RemoveElementAt(PRInt32(ep - mArray)); + } + } + return PR_FALSE; +} + +void nsVoidArray::Clear() +{ + mCount = 0; +} + +void nsVoidArray::Compact() +{ + PRInt32 count = mCount; + if (mArraySize != count) { + void** newArray = new void*[count]; + nsCRT::memcpy(newArray, mArray, count * sizeof(void*)); + delete mArray; + mArray = newArray; + mArraySize = count; + } +} diff --git a/mozilla/xpcom/glue/nsVoidArray.h b/mozilla/xpcom/glue/nsVoidArray.h new file mode 100644 index 00000000000..40394ff3b3e --- /dev/null +++ b/mozilla/xpcom/glue/nsVoidArray.h @@ -0,0 +1,64 @@ +/* -*- 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. + */ +#ifndef nsVoidArray_h___ +#define nsVoidArray_h___ + +#include "nscore.h" + +/// A basic zero-based array of void*'s that manages its own memory +class NS_BASE nsVoidArray { +public: + nsVoidArray(); + ~nsVoidArray(); + + nsVoidArray& operator=(const nsVoidArray& other); + + PRInt32 Count() const { + return mCount; + } + + void* ElementAt(PRInt32 aIndex) const; + void* operator[](PRInt32 aIndex) const { return ElementAt(aIndex); } + + PRInt32 IndexOf(void* aPossibleElement) const; + + PRBool InsertElementAt(void* aElement, PRInt32 aIndex); + + PRBool ReplaceElementAt(void* aElement, PRInt32 aIndex); + + PRBool AppendElement(void* aElement) { + return InsertElementAt(aElement, mCount); + } + + PRBool RemoveElement(void* aElement); + PRBool RemoveElementAt(PRInt32 aIndex); + void Clear(); + + void Compact(); + +protected: + void** mArray; + PRInt32 mArraySize; + PRInt32 mCount; + +private: + /// Copy constructors are not allowed + nsVoidArray(const nsVoidArray& other); +}; + +#endif /* nsVoidArray_h___ */ diff --git a/mozilla/xpcom/io/nsIInputStream.h b/mozilla/xpcom/io/nsIInputStream.h new file mode 100644 index 00000000000..d9459267f1e --- /dev/null +++ b/mozilla/xpcom/io/nsIInputStream.h @@ -0,0 +1,74 @@ +/* -*- 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. + */ +#ifndef nsIInputStream_h___ +#define nsIInputStream_h___ + +#include "nscore.h" +#include "nsISupports.h" + +#define NS_IINPUTSTREAM_IID \ +{ 0x022396f0, 0x93b5, 0x11d1, \ + {0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } + +/** Abstract byte input stream */ +class nsIInputStream : public nsISupports { +public: + /** Read data from the stream. + * @param aErrorCode the error code if an error occurs + * @param aBuf the buffer into which the data is read + * @param aOffset the start offset of the data + * @param aCount the maximum number of bytes to read + * @return number of bytes read or -1 if error + */ + virtual PRInt32 Read(PRInt32* aErrorCode, + char* aBuf, + PRInt32 aOffset, + PRInt32 aCount) = 0; + + /** Close the stream. */ + virtual void Close() = 0; +}; + +/** Error codes */ +//@{ +// XXX fix up the values to work with nsqresult +/// End of file +#define NS_INPUTSTREAM_EOF 1 +/// Stream closed +#define NS_INPUTSTREAM_CLOSED 2 +/// Error from the operating system +#define NS_INPUTSTREAM_OSERROR 3 +/// Illegal arguments +#define NS_INPUTSTREAM_ILLEGAL_ARGS 4 +/// For unichar streams +#define NS_INPUTSTREAM_NO_CONVERTER 5 +/// For unichar streams +#define NS_INPUTSTREAM_BAD_CONVERSION 6 +//@} + +/** Open a file using a local file name. Return an input stream that + can read the file. Use an implementation of nsIByteBuffer to do + buffered reading of the stream. */ +extern NS_BASE nsresult NS_OpenFile(nsIInputStream** aInstancePtrResult, + const char* aLocalFileName); + +/** Open a stream from a resource file name. Need two sents? */ +extern NS_BASE nsresult NS_OpenResource(nsIInputStream** aInstancePtrResult, + const char* aResourceFileName); + +#endif /* nsInputStream_h___ */ diff --git a/mozilla/xpcom/io/nsIUnicharInputStream.h b/mozilla/xpcom/io/nsIUnicharInputStream.h new file mode 100644 index 00000000000..4d892e5a7aa --- /dev/null +++ b/mozilla/xpcom/io/nsIUnicharInputStream.h @@ -0,0 +1,98 @@ +/* -*- 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. + */ +#ifndef nsIUnicharInputStream_h___ +#define nsIUnicharInputStream_h___ + +#include "nsIInputStream.h" +class nsString; + +#define NS_IUNICHAR_INPUT_STREAM_IID \ +{ 0x2d97fbf0, 0x93b5, 0x11d1, \ + {0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } + +#define NS_IB2UCONVERTER_IID \ +{ 0x35e40290, 0x93b5, 0x11d1, \ + {0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } + +/// Enumeration of character set ids. +enum nsCharSetID { + eCharSetID_IsoLatin1 = 0, + eCharSetID_UTF8, + eCharSetID_ShiftJis, + // XXX more i'm sure... +}; + +/** Abstract unicode character input stream + * @see nsIInputStream + */ +class nsIUnicharInputStream : public nsISupports { +public: + virtual PRInt32 Read(PRInt32* aErrorCode, + PRUnichar* aBuf, + PRInt32 aOffset, + PRInt32 aCount) = 0; + virtual void Close() = 0; +}; + +/** + * Create a nsIUnicharInputStream that wraps up a string. Data is fed + * from the string out until the done. When this object is destroyed + * it destroyes the string (so make a copy if you don't want it doing + * that) + */ +extern NS_BASE nsresult + NS_NewStringUnicharInputStream(nsIUnicharInputStream** aInstancePtrResult, + nsString* aString); + +/// Abstract interface for converting from bytes to unicode characters +class nsIB2UConverter : public nsISupports { +public: + /** aDstLen is updated to indicate how much data was translated into + * aDst; aSrcLen is updated to indicate how much data was used in + * the source buffer. + */ + virtual PRInt32 Convert(PRUnichar* aDst, + PRInt32 aDstOffset, + PRInt32& aDstLen, + const char* aSrc, + PRInt32 aSrcOffset, + PRInt32& aSrcLen) = 0; +}; + +/** Create a new nsUnicharInputStream that provides a converter for the + * byte input stream aStreamToWrap. If no converter can be found then + * nsnull is returned and the error code is set to + * NS_INPUTSTREAM_NO_CONVERTER. + */ +extern NS_BASE nsresult + NS_NewConverterStream(nsIUnicharInputStream** aInstancePtrResult, + nsISupports* aOuter, + nsIInputStream* aStreamToWrap, + PRInt32 aBufferSize = 0, + nsCharSetID aCharSet = eCharSetID_IsoLatin1); + +/** Create a new nsB2UConverter for the given character set. When given + * nsnull, the converter for iso-latin1 to unicode is provided. If no + * converter can be found, nsnull is returned. + */ +extern NS_BASE nsresult + NS_NewB2UConverter(nsIB2UConverter** aInstancePtrResult, + nsISupports* aOuter, + nsCharSetID aCharSet = eCharSetID_IsoLatin1); + +#endif /* nsUnicharInputStream_h___ */ diff --git a/mozilla/xpcom/io/nsUnicharInputStream.cpp b/mozilla/xpcom/io/nsUnicharInputStream.cpp new file mode 100644 index 00000000000..24a7ec84981 --- /dev/null +++ b/mozilla/xpcom/io/nsUnicharInputStream.cpp @@ -0,0 +1,328 @@ +/* -*- 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 "nsIUnicharInputStream.h" +#include "nsIByteBuffer.h" +#include "nsIUnicharBuffer.h" +#include "nsString.h" +#include "nsCRT.h" +#include +#ifdef NS_WIN32 +#include +#else +#include +#endif + +static NS_DEFINE_IID(kIUnicharInputStreamIID, NS_IUNICHAR_INPUT_STREAM_IID); + +class StringUnicharInputStream : public nsIUnicharInputStream { +public: + StringUnicharInputStream(nsString* aString); + ~StringUnicharInputStream(); + + NS_DECL_ISUPPORTS + + virtual PRInt32 Read(PRInt32* aErrorCode, + PRUnichar* aBuf, + PRInt32 aOffset, + PRInt32 aCount); + virtual void Close(); + + nsString* mString; + PRInt32 mPos; + PRInt32 mLen; +}; + +StringUnicharInputStream::StringUnicharInputStream(nsString* aString) +{ + mString = aString; + mPos = 0; + mLen = aString->Length(); +} + +StringUnicharInputStream::~StringUnicharInputStream() +{ + if (nsnull != mString) { + delete mString; + } +} + +PRInt32 StringUnicharInputStream::Read(PRInt32* aErrorCode, + PRUnichar* aBuf, + PRInt32 aOffset, + PRInt32 aCount) +{ + if (mPos >= mLen) { + return -1; + } + const PRUnichar* us = mString->GetUnicode(); + PRInt32 amount = mLen - mPos; + if (amount > aCount) { + amount = aCount; + } + nsCRT::memcpy(aBuf + aOffset, us + mPos, sizeof(PRUnichar) * amount); + mPos += amount; + return amount; +} + +void StringUnicharInputStream::Close() +{ + mPos = mLen; + if (nsnull != mString) { + delete mString; + } +} + +NS_IMPL_ISUPPORTS(StringUnicharInputStream, kIUnicharInputStreamIID); + +NS_BASE nsresult +NS_NewStringUnicharInputStream(nsIUnicharInputStream** aInstancePtrResult, + nsString* aString) +{ + NS_PRECONDITION(nsnull != aString, "null ptr"); + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if ((nsnull == aString) || (nsnull == aInstancePtrResult)) { + return NS_ERROR_NULL_POINTER; + } + + StringUnicharInputStream* it = new StringUnicharInputStream(aString); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(kIUnicharInputStreamIID, + (void**) aInstancePtrResult); +} + +//---------------------------------------------------------------------- + +class IsoLatin1Converter : public nsIB2UConverter { +public: + IsoLatin1Converter(); + + NS_DECL_ISUPPORTS + virtual PRInt32 Convert(PRUnichar* aDst, + PRInt32 aDstOffset, + PRInt32& aDstLen, + const char* aSrc, + PRInt32 aSrcOffset, + PRInt32& aSrcLen); +}; + +IsoLatin1Converter::IsoLatin1Converter() +{ + NS_INIT_REFCNT(); +} + +NS_DEFINE_IID(kIB2UConverterIID, NS_IB2UCONVERTER_IID); +NS_IMPL_ISUPPORTS(IsoLatin1Converter,kIB2UConverterIID); + +PRInt32 IsoLatin1Converter::Convert(PRUnichar* aDst, + PRInt32 aDstOffset, + PRInt32& aDstLen, + const char* aSrc, + PRInt32 aSrcOffset, + PRInt32& aSrcLen) +{ + PRInt32 amount = aSrcLen; + if (aSrcLen > aDstLen) { + amount = aDstLen; + } + const char* end = aSrc + amount; + while (aSrc < end) { + PRUint8 isoLatin1 = PRUint8(*aSrc++); + /* XXX insert table based lookup converter here */ + *aDst++ = isoLatin1; + } + aDstLen = amount; + aSrcLen = amount; + return NS_OK; +} + +NS_BASE nsresult +NS_NewB2UConverter(nsIB2UConverter** aInstancePtrResult, + nsISupports* aOuter, + nsCharSetID aCharSet) +{ + if (nsnull != aOuter) { + return NS_ERROR_NO_AGGREGATION; + } + if (eCharSetID_IsoLatin1 != aCharSet) { + return NS_INPUTSTREAM_NO_CONVERTER; + } + IsoLatin1Converter* it = new IsoLatin1Converter(); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIB2UConverterIID, (void**)aInstancePtrResult); +} + +//---------------------------------------------------------------------- + +class ConverterInputStream : public nsIUnicharInputStream { +public: + ConverterInputStream(nsIInputStream* aStream, + nsIB2UConverter* aConverter, + PRInt32 aBufSize); + ~ConverterInputStream(); + + NS_DECL_ISUPPORTS + virtual PRInt32 Read(PRInt32* aErrorCode, + PRUnichar* aBuf, + PRInt32 aOffset, + PRInt32 aCount); + virtual void Close(); + +protected: + PRInt32 Fill(PRInt32* aErrorCode); + + nsIInputStream* mInput; + nsIB2UConverter* mConverter; + nsIByteBuffer* mByteData; + PRInt32 mByteDataOffset; + nsIUnicharBuffer* mUnicharData; + PRInt32 mUnicharDataOffset; + PRInt32 mUnicharDataLength; +}; + +ConverterInputStream::ConverterInputStream(nsIInputStream* aStream, + nsIB2UConverter* aConverter, + PRInt32 aBufferSize) +{ + NS_INIT_REFCNT(); + mInput = aStream; aStream->AddRef(); + mConverter = aConverter; aConverter->AddRef(); + if (aBufferSize == 0) { + aBufferSize = 8192; + } + nsresult rv1 = NS_NewByteBuffer(&mByteData, nsnull, aBufferSize); + nsresult rv2 = NS_NewUnicharBuffer(&mUnicharData, nsnull, aBufferSize); + mByteDataOffset = 0; + mUnicharDataOffset = 0; + mUnicharDataLength = 0; +} + +NS_IMPL_ISUPPORTS(ConverterInputStream,kIUnicharInputStreamIID); + +ConverterInputStream::~ConverterInputStream() +{ + Close(); +} + +void ConverterInputStream::Close() +{ + if (nsnull != mInput) { + mInput->Release(); + mInput = nsnull; + } + if (nsnull != mConverter) { + mConverter->Release(); + mConverter = nsnull; + } + if (nsnull != mByteData) { + mByteData->Release(); + mByteData = nsnull; + } + if (nsnull != mUnicharData) { + mUnicharData->Release(); + mUnicharData = nsnull; + } +} + +PRInt32 ConverterInputStream::Read(PRInt32* aErrorCode, + PRUnichar* aBuf, + PRInt32 aOffset, + PRInt32 aCount) +{ + PRInt32 rv = mUnicharDataLength - mUnicharDataOffset; + if (0 == rv) { + // Fill the unichar buffer + rv = Fill(aErrorCode); + if (rv <= 0) { + return rv; + } + } + if (rv > aCount) { + rv = aCount; + } + nsCRT::memcpy(aBuf + aOffset, mUnicharData->GetBuffer() + mUnicharDataOffset, + rv * sizeof(PRUnichar)); + mUnicharDataOffset += rv; + return rv; +} + +PRInt32 ConverterInputStream::Fill(PRInt32* aErrorCode) +{ + if (nsnull == mInput) { + // We already closed the stream! + *aErrorCode = NS_INPUTSTREAM_CLOSED; + return -1; + } + + PRInt32 remainder = mByteData->GetLength() - mByteDataOffset; + mByteDataOffset = remainder; + PRInt32 nb = mByteData->Fill(aErrorCode, mInput, remainder); + if (nb <= 0) { + // Because we assume a many to one conversion, the lingering data + // in the byte buffer must be a partial conversion + // fragment. Because we know that we have recieved no more new + // data to add to it, we can't convert it. Therefore, we discard + // it. + return nb; + } + NS_ASSERTION(remainder + nb == mByteData->GetLength(), "bad nb"); + + // Now convert as much of the byte buffer to unicode as possible + PRInt32 dstLen = mUnicharData->GetBufferSize(); + PRInt32 srcLen = remainder + nb; + *aErrorCode = mConverter->Convert(mUnicharData->GetBuffer(), 0, dstLen, + mByteData->GetBuffer(), 0, srcLen); + mUnicharDataOffset = 0; + mUnicharDataLength = dstLen; + mByteDataOffset += srcLen; + return dstLen; +} + +// XXX hook up auto-detect here (do we need more info, like the url?) +NS_BASE nsresult +NS_NewConverterStream(nsIUnicharInputStream** aInstancePtrResult, + nsISupports* aOuter, + nsIInputStream* aStreamToWrap, + PRInt32 aBufferSize, + nsCharSetID aCharSet) +{ + if (nsnull != aOuter) { + return NS_ERROR_NO_AGGREGATION; + } + + // Create converter + nsIB2UConverter* converter; + nsresult rv = NS_NewB2UConverter(&converter, nsnull, aCharSet); + if (NS_OK != rv) { + return rv; + } + + // Create converter input stream + ConverterInputStream* it = + new ConverterInputStream(aStreamToWrap, converter, aBufferSize); + converter->Release(); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(kIUnicharInputStreamIID, + (void **) aInstancePtrResult); +} diff --git a/mozilla/xpcom/string/obsolete/nsString.cpp b/mozilla/xpcom/string/obsolete/nsString.cpp new file mode 100644 index 00000000000..9f5ada26569 --- /dev/null +++ b/mozilla/xpcom/string/obsolete/nsString.cpp @@ -0,0 +1,1979 @@ +/* -*- 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 +#include +#include +#include +#include "nsString.h" +#include "nsCRT.h" +#include "nsDebug.h" +#include "prprf.h" +#include "prdtoa.h" + + +const PRInt32 kGrowthDelta = 8; +const PRInt32 kNotFound = -1; +PRUnichar gBadChar = 0; +const char* kOutOfBoundsError = "Error: out of bounds"; +const char* kNullPointerError = "Error: unexpected null ptr"; + +//********************************************** +//NOTE: Our buffer always hold capacity+1 bytes. +//********************************************** + + +PRInt32 nsString::mInstanceCount=0; + +/**------------------------------------------------------- + * Default constructor + * + * @update gess 3/31/98 + * @param + * @return + *------------------------------------------------------*/ +nsString::nsString(const char* anISOLatin1/*=""*/) { + mLength=mCapacity=0; + mStr=0; + PRInt32 len=strlen(anISOLatin1); + EnsureCapacityFor(len); + this->SetString(anISOLatin1,len); + if(++mInstanceCount==1) + SelfTest(); +} + +/*------------------------------------------------------- + * constructor from string + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsString::nsString(const nsString &aString) { + mLength=mCapacity=0; + mStr=0; + EnsureCapacityFor(aString.mLength); + this->SetString(aString.mStr,aString.mLength); + if(++mInstanceCount==1) + SelfTest(); +} + +/*------------------------------------------------------- + * constructor from unicode string + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsString::nsString(const PRUnichar* aUnicodeStr){ + mLength=mCapacity=0; + mStr=0; + PRInt32 len=(aUnicodeStr) ? nsCRT::strlen(aUnicodeStr) : 0; + EnsureCapacityFor(len); + this->SetString(aUnicodeStr,len); + if(++mInstanceCount==1) + SelfTest(); +} + +/*------------------------------------------------------- + * standard destructor + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsString::~nsString() +{ + delete [] mStr; + mStr=0; + mCapacity=mLength=0; +} + +/*------------------------------------------------------- + * This method gets called when the internal buffer needs + * to grow to a given size. + * @update gess 3/30/98 + * @param aNewLength -- new capacity of string + * @return void + *------------------------------------------------------*/ +void nsString::EnsureCapacityFor(PRInt32 aNewLength) +{ + PRInt32 newCapacity; + + if (mCapacity > 64) { + // When the string starts getting large, double the capacity as we + // grow. + newCapacity = mCapacity * 2; + if (newCapacity < aNewLength) { + newCapacity = mCapacity + aNewLength; + } + } else { + // When the string is small, keep it's capacity a multiple of + // kGrowthDelta + PRInt32 size =aNewLength+kGrowthDelta; + newCapacity=size-(size % kGrowthDelta); + } + + if(mCapacity 0) { + nsCRT::memcpy(temp, mStr, mLength * sizeof(chartype)); + } + if(mStr) + delete [] mStr; + mStr = temp; + mStr[mLength]=0; + } +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +void nsString::SetLength(PRInt32 aLength) { +// NS_WARNING("Depricated method -- not longer required with dynamic strings. Use Truncate() instead."); + EnsureCapacityFor(aLength); + if (aLength > mLength) { + nsCRT::zero(mStr + mLength, (aLength - mLength) * sizeof(chartype)); + } + mLength=aLength; +} + +/*------------------------------------------------------- + * This method truncates this string to given length. + * + * @update gess 3/27/98 + * @param anIndex -- new length of string + * @return nada + *------------------------------------------------------*/ +void nsString::Truncate(PRInt32 anIndex) { + if((anIndex>-1) && (anIndex= 'A') && (ch <= 'Z')) { + *cp = 'a' + (ch - 'A'); + } + cp++; + } +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +void nsString::ToUpperCase() +{ + chartype* cp = mStr; + chartype* end = cp + mLength; + while (cp < end) { + chartype ch = *cp; + if ((ch >= 'a') && (ch <= 'z')) { + *cp = 'A' + (ch - 'a'); + } + cp++; + } +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +void nsString::ToLowerCase(nsString& aOut) const +{ + aOut.SetLength(mLength); + chartype* to = aOut.mStr; + chartype* from = mStr; + chartype* end = from + mLength; + while (from < end) { + chartype ch = *from++; + if ((ch >= 'A') && (ch <= 'Z')) { + ch = 'a' + (ch - 'A'); + } + *to++ = ch; + } + *to = 0; +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +void nsString::ToUpperCase(nsString& aOut) const +{ + aOut.SetLength(mLength); + chartype* to = aOut.mStr; + chartype* from = mStr; + chartype* end = from + mLength; + while (from < end) { + chartype ch = *from++; + if ((ch >= 'a') && (ch <= 'z')) { + ch = 'A' + (ch - 'a'); + } + *to++ = ch; + } + *to = 0; +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsString* nsString::ToNewString() const { + return new nsString(mStr); +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +char* nsString::ToNewCString() const +{ + char* rv = new char[mLength + 1]; + return ToCString(rv,mLength+1); +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRUnichar* nsString::ToNewUnicode() const +{ + PRInt32 len = mLength; + chartype* rv = new chartype[len + 1]; + chartype* to = rv; + chartype* from = mStr; + while (--len >= 0) { + *to++ = *from++; + } + *to++ = 0; + return rv; +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +void nsString::ToString(nsString& aString) const +{ + aString.SetLength(0); + aString.Append(mStr, mLength); +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +char* nsString::ToCString(char* aBuf, PRInt32 aBufLength) const +{ + aBufLength--; // leave room for the \0 + PRInt32 len = mLength; + if (len > aBufLength) { + len = aBufLength; + } + char* to = aBuf; + chartype* from = mStr; + while (--len >= 0) { + *to++ = char(*from++); + } + *to++ = '\0'; + return aBuf; +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +float nsString::ToFloat(PRInt32* aErrorCode) const +{ + char buf[40]; + if (mLength > sizeof(buf)-1) { + *aErrorCode = NS_ERROR_ILLEGAL_VALUE; + return 0.0f; + } + char* cp = ToCString(buf, sizeof(buf)); + float f = (float) PR_strtod(cp, &cp); + if (*cp != 0) { + *aErrorCode = NS_ERROR_ILLEGAL_VALUE; + } + return f; +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::ToInteger(PRInt32* aErrorCode) const { + PRInt32 rv = 0; + PRUnichar* cp = mStr; + PRUnichar* end = mStr + mLength; + + // Skip leading whitespace + while (cp < end) { + PRUnichar ch = *cp; + if (!IsSpace(ch)) { + break; + } + cp++; + } + if (cp == end) { + *aErrorCode = NS_ERROR_ILLEGAL_VALUE; + return rv; + } + + // Check for sign + PRUnichar sign = '+'; + if ((*cp == '+') || (*cp == '-')) { + sign = *cp++; + } + if (cp == end) { + *aErrorCode = NS_ERROR_ILLEGAL_VALUE; + return rv; + } + + // Convert the number + while (cp < end) { + PRUnichar ch = *cp++; + if ((ch < '0') || (ch > '9')) { + *aErrorCode = NS_ERROR_ILLEGAL_VALUE; + break; + } + rv = rv * 10 + (ch - '0'); + } + + if (sign == '-') { + rv = -rv; + } + return rv; +} + + +/*------------------------------------------------------- + * assign given string to this one + * @update gess 3/27/98 + * @param aString: string to be added to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator=(const nsString& aString) { + return this->SetString(aString.mStr,aString.mLength); +} + + +/*------------------------------------------------------- + * assign given char* to this string + * @update gess 3/27/98 + * @param anISOLatin1: buffer to be assigned to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator=(const char* anISOLatin1) { + return SetString(anISOLatin1); +} + + +/*------------------------------------------------------- + * assign given char to this string + * @update gess 3/27/98 + * @param aChar: char to be assignd to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator=(char aChar) { + return Append(PRUnichar(aChar)); +} + +/*------------------------------------------------------- + * assign given PRUnichar* to this string + * @update gess 3/27/98 + * @param anISOLatin1: buffer to be assigned to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::SetString(const PRUnichar* aStr,PRInt32 aLength) { + if(aStr!=0) { + PRInt32 len=(kNotFound==aLength) ? nsCRT::strlen(aStr) : aLength; + if(mCapacity< len ) + EnsureCapacityFor(len); + nsCRT::memcpy(mStr,aStr,len*sizeof(chartype)); + mLength=len; + mStr[mLength]=0; + } + else { + mLength=0; //This little bit of code handles the case + mStr[0]=0; //where some blockhead hands us a null string + } + return *this; +} + + +/*------------------------------------------------------- + * assign given char* to this string + * @update gess 3/27/98 + * @param anISOLatin1: buffer to be assigned to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::SetString(const char* anISOLatin1,PRInt32 aLength) { + if(anISOLatin1!=0) { + PRInt32 len=(kNotFound==aLength) ? nsCRT::strlen(anISOLatin1) : aLength; + if(mCapacitySetString(aStr); +} + + +/*------------------------------------------------------- + * assign given char to this string + * @update gess 3/27/98 + * @param aChar: char to be assignd to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator=(PRUnichar aChar) { + mLength=1; + if(mCapacity<1) + EnsureCapacityFor(kGrowthDelta); + mStr[0]=aChar; + mStr[1]=0; + return *this; +} + +/*------------------------------------------------------- + * append given string to this string + * @update gess 3/27/98 + * @param aString : string to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::Append(const nsString& aString,PRInt32 aLength) { + return Append(aString.mStr,aString.mLength); +} + +/*------------------------------------------------------- + * append given string to this string + * @update gess 3/27/98 + * @param aString : string to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::Append(const char* anISOLatin1,PRInt32 aLength) { + if(anISOLatin1!=0) { + PRInt32 len=(kNotFound==aLength) ? strlen(anISOLatin1) : aLength; + if(mLength+len > mCapacity) { + EnsureCapacityFor(mLength+len); + } + for(int i=0;i mCapacity) { + EnsureCapacityFor(mLength+len); + } + if(len>0) + nsCRT::memcpy(&mStr[mLength],aString,len*sizeof(chartype)); + mLength+=len; + mStr[mLength]=0; + } + return *this; +} + +/*------------------------------------------------------- + * append given string to this string + * @update gess 3/27/98 + * @param aString : string to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::Append(PRUnichar aChar) { + if(mLength < mCapacity) { + mStr[mLength++]=aChar; // the new string len < capacity, so just copy + mStr[mLength]=0; + } + else { // The new string exceeds our capacity + EnsureCapacityFor(mLength+1); + mStr[mLength++]=aChar; + mStr[mLength]=0; + } + return *this; +} + + +/*------------------------------------------------------- + * append given string to this string + * @update gess 3/27/98 + * @param aString : string to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator+=(const nsString &aString) { + return this->Append(aString.mStr,aString.mLength); +} + + +/*------------------------------------------------------- + * append given buffer to this string + * @update gess 3/27/98 + * @param anISOLatin1: buffer to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator+=(const char* anISOLatin1) { + return Append(anISOLatin1); +} + + +/*------------------------------------------------------- + * append given buffer to this string + * @update gess 3/27/98 + * @param aBuffer: buffer to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator+=(const PRUnichar* aBuffer) { + return Append(aBuffer); +} + + +/*------------------------------------------------------- + * append given char to this string + * @update gess 3/27/98 + * @param aChar: char to be appended to this + * @return this + *------------------------------------------------------*/ +nsString& nsString::operator+=(PRUnichar aChar) { + return Append(aChar); +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsString& nsString::Append(PRInt32 aInteger,PRInt32 aRadix) { + char* fmt = "%d"; + if (8 == aRadix) { + fmt = "%o"; + } else if (16 == aRadix) { + fmt = "%x"; + } + char buf[40]; + PR_snprintf(buf, sizeof(buf), fmt, aInteger); + Append(buf); + return *this; +} + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsString& nsString::Append(float aFloat){ + char buf[40]; + PR_snprintf(buf, sizeof(buf), "%g", aFloat); + Append(buf); + return *this; +} + + + +/**------------------------------------------------------- + * Copies n characters from this string to given string, + * starting at the leftmost offset. + * + * + * @update gess 4/1/98 + * @param aCopy -- Receiving string + * @param aCount -- number of chars to copy + * @return number of chars copied + *------------------------------------------------------*/ +PRInt32 nsString::Left(nsString& aCopy,PRInt32 aCount) { + return Mid(aCopy,0,aCount); +} + +/**------------------------------------------------------- + * Copies n characters from this string to given string, + * starting at the given offset. + * + * + * @update gess 4/1/98 + * @param aCopy -- Receiving string + * @param aCount -- number of chars to copy + * @param anOffset -- position where copying begins + * @return number of chars copied + *------------------------------------------------------*/ +PRInt32 nsString::Mid(nsString& aCopy,PRInt32 anOffset,PRInt32 aCount) { + if(anOffsetaCopy.mLength) ? aCopy.mLength : aCount; //don't try to copy more than you are given + if(aCount>0) { + + //1st optimization: If you're inserting at end, then simply append! + if(anOffset>=mLength){ + Append(aCopy,aCopy.mLength); + return aCopy.mLength; + } + + if(mLength+aCount > mCapacity) { + EnsureCapacityFor(mLength+aCount); + } + + PRUnichar* last = mStr + mLength; + PRUnichar* first = mStr + anOffset-1; + PRUnichar* next = mStr + mLength + aCount; + + //Copy rightmost chars, up to offset+aCount... + while(first=0) && (anOffset= 'A') && (ch <= 'Z')) || ((ch >= 'a') && (ch <= 'z'))) { + return PR_TRUE; + } + return PR_FALSE; +} + +/**------------------------------------------------------- + * + * + * @update gess 3/31/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool nsString::IsSpace(PRUnichar ch) { + // XXX i18n + if ((ch == ' ') || (ch == '\r') || (ch == '\n') || (ch == '\t')) { + return PR_TRUE; + } + return PR_FALSE; +} + +/**------------------------------------------------------- + * This method trims characters found in aTrimSet from + * either end of the underlying string. + * + * @update gess 3/31/98 + * @param aTrimSet -- contains chars to be trimmed from + * both ends + * @return this + *------------------------------------------------------*/ +nsString& nsString::Trim(const char* aTrimSet, + PRBool aEliminateLeading, + PRBool aEliminateTrailing) +{ + PRUnichar* from = mStr; + PRUnichar* end = mStr + mLength-1; + PRUnichar* to = mStr; + + //begin by find the first char not in aTrimSet + if(aEliminateLeading) { + while (from < end) { + PRUnichar ch = *from; + if(!strchr(aTrimSet,char(ch))) { + break; + } + from++; + } + } + + //Now, find last char not in aTrimSet + if(aEliminateTrailing) { + while(end> from) { + PRUnichar ch = *end; + if(!strchr(aTrimSet,char(ch))) { + break; + } + end--; + } + } + + //now rewrite your string without unwanted + //leading or trailing characters. + while (from <= end) { + *to++ = *from++; + } + + *to = '\0'; + mLength = to - mStr; + return *this; +} + +/**------------------------------------------------------- + * + * + * @update gess 3/31/98 + * @param + * @return + *------------------------------------------------------*/ +nsString& nsString::CompressWhitespace( PRBool aEliminateLeading, + PRBool aEliminateTrailing) +{ + PRUnichar* from = mStr; + PRUnichar* end = mStr + mLength; + PRUnichar* to = from; + + Trim(" \r\n\t",aEliminateLeading,aEliminateTrailing); + + //this code converts /n, /t, /r into normal space ' '; + //it also eliminates runs of whitespace... + while (from < end) { + PRUnichar ch = *from++; + if (IsSpace(ch)) { + *to++ = ' '; + while (from < end) { + ch = *from++; + if (!IsSpace(ch)) { + *to++ = ch; + break; + } + } + } else { + *to++ = ch; + } + } + + *to = '\0'; + mLength = to - mStr; + return *this; +} + +/**------------------------------------------------------- + * XXX This is used by bina all over the place; not sure + * it belongs here though + * + * @update gess 3/31/98 + * @param + * @return + *------------------------------------------------------*/ +nsString& nsString::StripWhitespace() +{ + Trim(" \r\n\t"); + return StripChars("\r\t\n"); +} + + +/**------------------------------------------------------- + * Search for given buffer within this string + * + * @update gess 3/25/98 + * @param anISOLatin1Buf - charstr to be found + * @return offset in string, or -1 (kNotFound) + *------------------------------------------------------*/ +PRInt32 nsString::Find(const char* anISOLatin1Buf) const{ + NS_ASSERTION(0!=anISOLatin1Buf,kNullPointerError); + PRInt32 result=-1; + if(anISOLatin1Buf) { + PRInt32 len=strlen(anISOLatin1Buf); + if(len<=mLength) { //only enter if abuffer length is <= mStr length. + for(PRInt32 offset=0;offset0;i--){ + char* pos=strchr(anISOLatin1Set,char(mStr[i])); + if(pos) + return i; + } + } + return kNotFound; +} + +/**------------------------------------------------------- + * + * + * @update gess 3/25/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::FindLastCharInSet(nsString& aSet,PRInt32 anOffset) const{ + if(aSet.Length()) { + for(PRInt32 i=mLength-1;i>0;i--){ + PRInt32 pos=aSet.Find(mStr[i]); + if(kNotFound!=pos) + return i; + } + } + return kNotFound; +} + +/**------------------------------------------------------- + * + * + * @update gess 3/25/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::RFind(const PRUnichar* aString,PRBool aIgnoreCase) const{ + NS_ASSERTION(0!=aString,kNullPointerError); + + if(aString) { + PRInt32 len=nsCRT::strlen(aString); + if((len) && (len<=mLength)) { //only enter if abuffer length is <= mStr length. + for(PRInt32 offset=mLength-len;offset>=0;offset--) { + PRInt32 result=0; + if(aIgnoreCase) + result=nsCRT::strncasecmp(&mStr[offset],aString,len); + else result=nsCRT::strncmp(&mStr[offset],aString,len); + if(0==result) + return offset; //in this case, 0 means they match + } + } + } + return kNotFound; +} + +/**------------------------------------------------------- + * + * + * @update gess 3/25/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::RFind(const nsString& aString,PRBool aIgnoreCase) const{ + PRInt32 len=aString.mLength; + if((len) && (len<=mLength)) { //only enter if abuffer length is <= mStr length. + for(PRInt32 offset=mLength-len;offset>=0;offset--) { + PRInt32 result=0; + if(aIgnoreCase) + result=nsCRT::strncasecmp(&mStr[offset],aString.mStr,len); + else result=nsCRT::strncmp(&mStr[offset],aString.mStr,len); + if(0==result) + return offset; //in this case, 0 means they match + } + } + return kNotFound; +} + +/**------------------------------------------------------- + * + * + * @update gess 3/25/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::RFind(const char* anISOLatin1Set,PRBool aIgnoreCase) const{ + NS_ASSERTION(0!=anISOLatin1Set,kNullPointerError); + + if(anISOLatin1Set) { + PRInt32 len=strlen(anISOLatin1Set); + if((len) && (len<=mLength)) { //only enter if abuffer length is <= mStr length. + for(PRInt32 offset=mLength-len;offset>=0;offset--) { + PRInt32 result=0; + if(aIgnoreCase) + result=nsCRT::strncasecmp(&mStr[offset],anISOLatin1Set,len); + else result=nsCRT::strncmp(&mStr[offset],anISOLatin1Set,len); + if(0==result) + return offset; //in this case, 0 means they match + } + } + } + return kNotFound; +} + + +/**------------------------------------------------------- + * Scans this string backwards for first occurance of + * the given char. + * + * @update gess 3/25/98 + * @param + * @return offset of char in string, or -1 (kNotFound) + *------------------------------------------------------*/ +PRInt32 nsString::RFind(PRUnichar aChar,PRBool aIgnoreCase) const{ + chartype uc=nsCRT::ToUpper(aChar); + for(PRInt32 offset=mLength-1;offset>0;offset--) + if(aIgnoreCase) { + if(nsCRT::ToUpper(mStr[offset])==uc) + return offset; + } + else if(mStr[offset]==aChar) + return offset; //in this case, 0 means they match + return kNotFound; + +} + + //****** comparision methods... ******* + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::Compare(const char *anISOLatin1,PRBool aIgnoreCase) const { + if (aIgnoreCase) { + return nsCRT::strcasecmp(mStr,anISOLatin1); + } + return nsCRT::strcmp(mStr,anISOLatin1); +} + +/*------------------------------------------------------- + * LAST MODS: gess + * + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::Compare(const nsString &S,PRBool aIgnoreCase) const { + if (aIgnoreCase) { + return nsCRT::strcasecmp(mStr,S.mStr); + } + return nsCRT::strcmp(mStr,S.mStr); +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRInt32 nsString::Compare(const PRUnichar* aString,PRBool aIgnoreCase) const { + if (aIgnoreCase) { + return nsCRT::strcasecmp(mStr,aString); + } + return nsCRT::strcmp(mStr,aString); +} + + +PRInt32 nsString::operator==(const nsString &S) const {return Compare(S)==0;} +PRInt32 nsString::operator==(const char *s) const {return Compare(s)==0;} +PRInt32 nsString::operator==(const PRUnichar *s) const {return Compare(s)==0;} +PRInt32 nsString::operator!=(const nsString &S) const {return Compare(S)!=0;} +PRInt32 nsString::operator!=(const char *s ) const {return Compare(s)!=0;} +PRInt32 nsString::operator!=(const PRUnichar *s) const {return Compare(s)==0;} +PRInt32 nsString::operator<(const nsString &S) const {return Compare(S)<0;} +PRInt32 nsString::operator<(const char *s) const {return Compare(s)<0;} +PRInt32 nsString::operator<(const PRUnichar *s) const {return Compare(s)==0;} +PRInt32 nsString::operator>(const nsString &S) const {return Compare(S)>0;} +PRInt32 nsString::operator>(const char *s) const {return Compare(s)>0;} +PRInt32 nsString::operator>(const PRUnichar *s) const {return Compare(s)==0;} +PRInt32 nsString::operator<=(const nsString &S) const {return Compare(S)<=0;} +PRInt32 nsString::operator<=(const char *s) const {return Compare(s)<=0;} +PRInt32 nsString::operator<=(const PRUnichar *s) const {return Compare(s)==0;} +PRInt32 nsString::operator>=(const nsString &S) const {return Compare(S)>=0;} +PRInt32 nsString::operator>=(const char *s) const {return Compare(s)>=0;} +PRInt32 nsString::operator>=(const PRUnichar *s) const {return Compare(s)==0;} + + + +/*------------------------------------------------------- + * Compare this to given string + * @update gess 3/27/98 + * @param aString -- string to compare to this + * @return TRUE if equal + *------------------------------------------------------*/ +PRBool nsString::Equals(const nsString& aString) const { + PRInt32 result=nsCRT::strcmp(mStr,aString.mStr); + return PRBool(0==result); +} + + +/*------------------------------------------------------- + * Compare this to given string + * @update gess 3/27/98 + * @param aCString -- Cstr to compare to this + * @return TRUE if equal + *------------------------------------------------------*/ +PRBool nsString::Equals(const char* aCString) const{ + NS_ASSERTION(0!=aCString,kNullPointerError); + PRInt32 result=nsCRT::strcmp(mStr,aCString); + return PRBool(0==result); +} + + +/*------------------------------------------------------- + * Compare this to given atom + * @update gess 3/27/98 + * @param aAtom -- atom to compare to this + * @return TRUE if equal + *------------------------------------------------------*/ +PRBool nsString::Equals(const nsIAtom* aAtom) const +{ + NS_ASSERTION(0!=aAtom,kNullPointerError); + PRInt32 result=nsCRT::strcmp(mStr,aAtom->GetUnicode()); + return PRBool(0==result); +} + + +/*------------------------------------------------------- + * Compare given strings + * @update gess 3/27/98 + * @param s1 -- first string to be compared + * @param s2 -- second string to be compared + * @return TRUE if equal + *------------------------------------------------------*/ +PRBool nsString::Equals(const PRUnichar* s1, const PRUnichar* s2) const { + NS_ASSERTION(0!=s1,kNullPointerError); + NS_ASSERTION(0!=s2,kNullPointerError); + PRBool result=PR_FALSE; + if((s1) && (s2)){ + PRInt32 cmp=nsCRT::strcmp(s1,s2); + result=PRBool(0==cmp); + } + return result; +} + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool nsString::EqualsIgnoreCase(const nsString& aString) const{ + PRInt32 result=nsCRT::strcasecmp(mStr,aString.mStr); + return PRBool(0==result); +} + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool nsString::EqualsIgnoreCase(const nsIAtom *aAtom) const{ + NS_ASSERTION(0!=aAtom,kNullPointerError); + PRBool result=PR_FALSE; + if(aAtom){ + PRInt32 cmp=nsCRT::strcasecmp(mStr,aAtom->GetUnicode()); + result=PRBool(0==cmp); + } + return result; +} + + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool nsString::EqualsIgnoreCase(const PRUnichar* s1, const PRUnichar* s2) const { + NS_ASSERTION(0!=s1,kNullPointerError); + NS_ASSERTION(0!=s2,kNullPointerError); + PRBool result=PR_FALSE; + if((s1) && (s2)){ + PRInt32 cmp=nsCRT::strcasecmp(s1,s2); + result=PRBool(0==cmp); + } + return result; +} + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +PRBool nsString::EqualsIgnoreCase(const char* aCString) const { + NS_ASSERTION(0!=aCString,kNullPointerError); + PRBool result=PR_FALSE; + if(aCString){ + PRInt32 cmp=nsCRT::strcasecmp(mStr,aCString); + result=PRBool(0==cmp); + } + return result; +} + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +void nsString::DebugDump(ostream& aStream) const { + for(int i=0;itemp3.Length(),"constructor error!"); //should be char longer + + nsString* es1=temp2.ToNewString(); //this should make us a new string + char* es2=temp2.ToNewCString(); + for(i=0;itemp8,"Error: Comparision (>) routine"); + NS_ASSERTION(temp9>aaaa,"Error: Comparision (>) routine"); + + NS_ASSERTION(temp8<=temp8,"Error: Comparision (<=) routine"); + NS_ASSERTION(temp8<=temp9,"Error: Comparision (<=) routine"); + NS_ASSERTION(temp8<=bbbb,"Error: Comparision (<=) routine"); + + NS_ASSERTION(temp9>=temp9,"Error: Comparision (<=) routine"); + NS_ASSERTION(temp9>=temp8,"Error: Comparision (<=) routine"); + NS_ASSERTION(temp9>=aaaa,"Error: Comparision (<=) routine"); + + NS_ASSERTION(temp8.Equals(temp8),"Equals error"); + NS_ASSERTION(temp8.Equals(aaaa),"Equals error"); + + nsString temp10(temp8); + temp10.ToUpperCase(); + NS_ASSERTION(temp8.EqualsIgnoreCase(temp10),"Equals error"); + NS_ASSERTION(temp8.EqualsIgnoreCase("AAAA"),"Equals error"); + + + //********************************************** + //Now let's test a few string MANIPULATORS... + //********************************************** + + nsAutoString ab("ab"); + nsString abcde("cde"); + abcde.Insert(ab,0,2); + nsAutoString xxx("xxx"); + abcde.Insert(xxx,2,3); + + temp2.ToUpperCase(); + for(i=0;i mCapacity) { + PRInt32 size = mCapacity * 2; + if (size < aNewLength) { + size = mCapacity + aNewLength; + } + mCapacity=size; + chartype* temp = new chartype[mCapacity+1]; + if (mLength > 0) { + nsCRT::memcpy(temp, mStr, mLength * sizeof(chartype)); + } + mStr = temp; + } +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsAutoString::nsAutoString(const PRUnichar* unicode, PRInt32 uslen) { + mStr = mBuf; + mCapacity = sizeof(mBuf) / sizeof(chartype); + if (0 == uslen) { + uslen = nsCRT::strlen(unicode); + } + Append(unicode, uslen); +} + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +nsAutoString::~nsAutoString() +{ + if (mStr == mBuf) { + // Force to null so that baseclass dtor doesn't do damage + mStr = nsnull; + } +} + + +/**------------------------------------------------------- + * + * + * @update gess 3/31/98 + * @param + * @return + *------------------------------------------------------*/ +void nsAutoString::SelfTest(){ + nsAutoString xas("Hello there"); + xas.Append("this string exceeds the max size"); + xas.DebugDump(cout); +} + + +/*------------------------------------------------------- + * + * @update gess 3/27/98 + * @param + * @return + *------------------------------------------------------*/ +NS_BASE int fputs(const nsString& aString, FILE* out) +{ + char buf[100]; + char* cp = buf; + PRInt32 len = aString.Length(); + if (len >= sizeof(buf)) { + cp = aString.ToNewCString(); + } else { + aString.ToCString(cp, len + 1); + } + ::fwrite(cp, 1, len, out); + if (cp != buf) { + delete cp; + } + return (int) len; +} + diff --git a/mozilla/xpcom/string/obsolete/nsString.h b/mozilla/xpcom/string/obsolete/nsString.h new file mode 100644 index 00000000000..dc26545c53b --- /dev/null +++ b/mozilla/xpcom/string/obsolete/nsString.h @@ -0,0 +1,233 @@ +/* -*- 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. + */ + +/** + * MODULE NOTES: + * LAST MODS: gess 28Feb98 + * + * This very simple string class that knows how to do + * efficient (dynamic) resizing. It offers almost no + * i18n support, and will undoubtedly have to be replaced. + * + */ + +#ifndef _NSSTRING +#define _NSSTRING + + +#include "prtypes.h" +#include "nscore.h" +#include "nsIAtom.h" +#include +#include + + +class NS_BASE nsString { + public: + + nsString(const char* anISOLatin1=""); + nsString(const nsString&); + nsString(const PRUnichar* aUnicode); + virtual ~nsString(); + + PRInt32 Length() const { return mLength; } + + void SetLength(PRInt32 aLength); + void Truncate(PRInt32 anIndex=0); + virtual void EnsureCapacityFor(PRInt32 aNewLength); + + ///accessor methods + //@{ + PRUnichar* GetUnicode(void) const; + operator PRUnichar*() const; + +#if 0 + // This is NOT allowed because it has to do a malloc to + // create the iso-latin-1 version of the unicode string + operator char*() const; +#endif + + PRUnichar* operator()() const; + PRUnichar operator()(PRInt32 i) const; + PRUnichar& operator[](PRInt32 i) const; + PRUnichar& CharAt(PRInt32 anIndex) const; + PRUnichar& First() const; + PRUnichar& Last() const; + + //string creation methods... + nsString operator+(const nsString& aString); + nsString operator+(const char* anISOLatin1); + nsString operator+(char aChar); + nsString operator+(const PRUnichar* aBuffer); + nsString operator+(PRUnichar aChar); + + void ToLowerCase(); + void ToLowerCase(nsString& aString) const; + void ToUpperCase(); + void ToUpperCase(nsString& aString) const; + + nsString* ToNewString() const; + char* ToNewCString() const; + + char* ToCString(char* aBuf,PRInt32 aBufLength) const; + void ToString(nsString& aString) const; + + PRUnichar* ToNewUnicode() const; + float ToFloat(PRInt32* aErrorCode) const; + PRInt32 ToInteger(PRInt32* aErrorCode) const; + //@} + + ///string manipulation methods... + //@{ + nsString& operator=(const nsString& aString); + nsString& operator=(const char* anISOLatin1); + nsString& operator=(char aChar); + nsString& operator=(const PRUnichar* aBuffer); + nsString& operator=(PRUnichar aChar); + nsString& SetString(const PRUnichar* aStr,PRInt32 aLength=-1); + nsString& SetString(const char* anISOLatin1,PRInt32 aLength=-1); + + nsString& operator+=(const nsString& aString); + nsString& operator+=(const char* anISOLatin1); + nsString& operator+=(const PRUnichar* aBuffer); + nsString& operator+=(PRUnichar aChar); + nsString& Append(const nsString& aString,PRInt32 aLength=-1); + nsString& Append(const char* anISOLatin1,PRInt32 aLength=-1); + nsString& Append(char aChar); + nsString& Append(const PRUnichar* aBuffer,PRInt32 aLength=-1); + nsString& Append(PRUnichar aChar); + nsString& Append(PRInt32 aInteger,PRInt32 aRadix); //radix=8,10 or 16 + nsString& Append(float aFloat); + + PRInt32 Left(nsString& aCopy,PRInt32 aCount); + PRInt32 Mid(nsString& aCopy,PRInt32 anOffset,PRInt32 aCount); + PRInt32 Right(nsString& aCopy,PRInt32 aCount); + PRInt32 Insert(nsString& aCopy,PRInt32 anOffset,PRInt32 aCount=-1); + + nsString& Cut(PRInt32 anOffset,PRInt32 aCount); + nsString& StripChars(const char* aSet); + nsString& StripWhitespace(); + nsString& Trim( const char* aSet, + PRBool aEliminateLeading=PR_TRUE, + PRBool aEliminateTrailing=PR_TRUE); + nsString& CompressWhitespace( PRBool aEliminateLeading=PR_TRUE, + PRBool aEliminateTrailing=PR_TRUE); + static PRBool IsSpace(PRUnichar ch); + static PRBool IsAlpha(PRUnichar ch); + //@} + + ///searching methods... + //@{ + PRInt32 Find(const char* anISOLatin1) const; + PRInt32 Find(const PRUnichar* aString) const; + PRInt32 Find(PRUnichar aChar,PRInt32 offset=0) const; + PRInt32 Find(const nsString& aString) const; + PRInt32 FindFirstCharInSet(const char* anISOLatin1Set,PRInt32 offset=0) const; + PRInt32 FindFirstCharInSet(nsString& aString,PRInt32 offset=0) const; + PRInt32 FindLastCharInSet(const char* anISOLatin1Set,PRInt32 offset=0) const; + PRInt32 FindLastCharInSet(nsString& aString,PRInt32 offset=0) const; + PRInt32 RFind(const char* anISOLatin1,PRBool aIgnoreCase=PR_FALSE) const; + PRInt32 RFind(const PRUnichar* aString,PRBool aIgnoreCase=PR_FALSE) const; + PRInt32 RFind(const nsString& aString,PRBool aIgnoreCase=PR_FALSE) const; + PRInt32 RFind(PRUnichar aChar,PRBool aIgnoreCase=PR_FALSE) const; + //@} + + ///comparision methods... + //@{ + virtual PRInt32 Compare(const nsString &S,PRBool aIgnoreCase=PR_FALSE) const; + virtual PRInt32 Compare(const char *anISOLatin1,PRBool aIgnoreCase=PR_FALSE) const; + virtual PRInt32 Compare(const PRUnichar *aString,PRBool aIgnoreCase=PR_FALSE) const; + + PRInt32 operator==(const nsString &S) const; + PRInt32 operator==(const char *anISOLatin1) const; + PRInt32 operator==(const PRUnichar* aString) const; + PRInt32 operator!=(const nsString &S) const; + PRInt32 operator!=(const char *anISOLatin1) const; + PRInt32 operator!=(const PRUnichar* aString) const; + PRInt32 operator<(const nsString &S) const; + PRInt32 operator<(const char *anISOLatin1) const; + PRInt32 operator<(const PRUnichar* aString) const; + PRInt32 operator>(const nsString &S) const; + PRInt32 operator>(const char *anISOLatin1) const; + PRInt32 operator>(const PRUnichar* aString) const; + PRInt32 operator<=(const nsString &S) const; + PRInt32 operator<=(const char *anISOLatin1) const; + PRInt32 operator<=(const PRUnichar* aString) const; + PRInt32 operator>=(const nsString &S) const; + PRInt32 operator>=(const char *anISOLatin1) const; + PRInt32 operator>=(const PRUnichar* aString) const; + + PRBool Equals(const nsString& aString) const; + PRBool Equals(const char* anISOLatin1) const; + PRBool Equals(const nsIAtom *aAtom) const; + PRBool Equals(const PRUnichar* s1, const PRUnichar* s2) const; + + PRBool EqualsIgnoreCase(const nsString& aString) const; + PRBool EqualsIgnoreCase(const char* anISOLatin1) const; + PRBool EqualsIgnoreCase(const nsIAtom *aAtom) const; + PRBool EqualsIgnoreCase(const PRUnichar* s1, const PRUnichar* s2) const; + //@} + + static void SelfTest(); + virtual void DebugDump(ostream& aStream) const; + + protected: + +typedef PRUnichar chartype; + + chartype* mStr; + PRInt32 mLength; + PRInt32 mCapacity; + static PRInt32 mInstanceCount; +}; + +extern NS_BASE int fputs(const nsString& aString, FILE* out); + +//---------------------------------------------------------------------- + +/** + * A version of nsString which is designed to be used as an automatic + * variable. It attempts to operate out of a fixed size internal + * buffer until too much data is added; then a dynamic buffer is + * allocated and grown as necessary. + */ +// XXX template this with a parameter for the size of the buffer? +class NS_BASE nsAutoString : public nsString { +public: + nsAutoString(); + nsAutoString(const nsString& other); + nsAutoString(const nsAutoString& other); + nsAutoString(PRUnichar aChar); + nsAutoString(const char* isolatin1); + nsAutoString(const PRUnichar* us, PRInt32 uslen = -1); + virtual ~nsAutoString(); + + static void SelfTest(); + +protected: + virtual void EnsureCapacityFor(PRInt32 aNewLength); + + PRUnichar mBuf[32]; + +private: + // XXX these need writing I suppose + nsAutoString& operator=(const nsAutoString& other); +}; + +#endif + diff --git a/mozilla/xpcom/tests/CvtURL.cpp b/mozilla/xpcom/tests/CvtURL.cpp new file mode 100644 index 00000000000..365b687431a --- /dev/null +++ b/mozilla/xpcom/tests/CvtURL.cpp @@ -0,0 +1,104 @@ +/* -*- 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 +#include "nsIUnicharInputStream.h" +#include "nsIURL.h" +#include "nsCRT.h" +#include "nsString.h" +#include "prprf.h" +#include "prtime.h" + +static nsCharSetID ConvertCharacterSetName(const char* aName) +{ + if (nsCRT::strcasecmp(aName, "iso-latin-1") == 0) { + return eCharSetID_IsoLatin1; + } + return (nsCharSetID) -1; +} + +int main(int argc, char** argv) +{ + if (3 != argc) { + printf("usage: CvtURL url character-set-name\n"); + return -1; + } + + char* characterSetName = argv[2]; + nsCharSetID cset = ConvertCharacterSetName(characterSetName); + if (PRInt32(cset) < 0) { + printf("illegal character set name: '%s'\n", characterSetName); + return -1; + } + + // Create url object + char* urlName = argv[1]; + nsIURL* url; + nsresult rv = NS_NewURL(&url, urlName); + if (NS_OK != rv) { + printf("invalid URL: '%s'\n", urlName); + return -1; + } + + // Get an input stream from the url + PRInt32 ec; + nsIInputStream* in = url->Open(&ec); + if (nsnull == in) { + printf("open of url('%s') failed: error=%x\n", urlName, ec); + return -1; + } + + // Translate the input using the argument character set id into unicode + nsIUnicharInputStream* uin; + rv = NS_NewConverterStream(&uin, nsnull, in, 0, cset); + if (NS_OK != rv) { + printf("can't create converter input stream: %d\n", rv); + return -1; + } + + // Read the input and write some output + PRTime start = PR_Now(); + PRInt32 count = 0; + for (;;) { + PRUnichar buf[1000]; + PRInt32 nb = uin->Read(&ec, buf, 0, 1000); + if (nb <= 0) { + if (nb < 0) { + printf("i/o error: %d\n", ec); + } + break; + } + count += nb; + } + PRTime end = PR_Now(); + PRTime conversion, ustoms; + LL_I2L(ustoms, 1000); + LL_SUB(conversion, end, start); + LL_DIV(conversion, conversion, ustoms); + char buf[500]; + PR_snprintf(buf, sizeof(buf), + "converting and discarding %d bytes took %lldms", + count, conversion); + puts(buf); + + // Release the objects + in->Release(); + uin->Release(); + url->Release(); + + return 0; +} diff --git a/mozilla/xpcom/tests/TestAtoms.cpp b/mozilla/xpcom/tests/TestAtoms.cpp new file mode 100644 index 00000000000..745a424a4ec --- /dev/null +++ b/mozilla/xpcom/tests/TestAtoms.cpp @@ -0,0 +1,108 @@ +/* -*- 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 "nsIAtom.h" +#include "nsString.h" +#include "prprf.h" +#include "prtime.h" +#include + +extern "C" int _CrtSetDbgFlag(int); + +int main(int argc, char** argv) +{ + FILE* fp = fopen("words.txt", "r"); + if (nsnull == fp) { + printf("can't open words.txt\n"); + return -1; + } + + PRInt32 count = 0; + PRUnichar** strings = new PRUnichar*[60000]; + nsIAtom** ids = new nsIAtom*[60000]; + nsAutoString s1, s2; + PRTime start = PR_Now(); + for (PRInt32 i = 0; i < 60000; i++) { + char buf[1000]; + char* s = fgets(buf, sizeof(buf), fp); + if (nsnull == s) { + break; + } + nsAutoString sb(buf); + strings[count++] = sb.ToNewUnicode(); + sb.ToUpperCase(); + strings[count++] = sb.ToNewUnicode(); + } + PRTime end0 = PR_Now(); + + // Find and create idents + for (i = 0; i < count; i++) { + ids[i] = NS_NewAtom(strings[i]); + } + PRUnichar qqs[1]; qqs[0] = 0; + nsIAtom* qq = NS_NewAtom(qqs); + PRTime end1 = PR_Now(); + + // Now make sure we can find all the idents we just made + for (i = 0; i < count; i++) { + nsIAtom* id = NS_NewAtom(ids[i]->GetUnicode()); + if (id != ids[i]) { + id->ToString(s1); + ids[i]->ToString(s2); + printf("find failed: id='%s' ids[%d]='%s'\n", + s1.ToNewCString(), i, s2.ToNewCString()); + return -1; + } + NS_RELEASE(id); + } + PRTime end2 = PR_Now(); + + // Destroy all the atoms we just made + NS_RELEASE(qq); + for (i = 0; i < count; i++) { + NS_RELEASE(ids[i]); + } + + // Print out timings + PRTime end3 = PR_Now(); + PRTime creates, finds, lookups, dtor, ustoms; + LL_I2L(ustoms, 1000); + LL_SUB(creates, end0, start); + LL_DIV(creates, creates, ustoms); + LL_SUB(finds, end1, end0); + LL_DIV(finds, finds, ustoms); + LL_SUB(lookups, end2, end1); + LL_DIV(lookups, lookups, ustoms); + LL_SUB(dtor, end3, end2); + char buf[500]; + PR_snprintf(buf, sizeof(buf), "making %d ident strings took %lldms", + count, creates); + puts(buf); + PR_snprintf(buf, sizeof(buf), "%d new idents took %lldms", + count, finds); + puts(buf); + PR_snprintf(buf, sizeof(buf), "%d ident lookups took %lldms", + count, lookups); + puts(buf); + PR_snprintf(buf, sizeof(buf), "dtor took %lldusec", dtor); + puts(buf); + + printf("%d live atoms\n", NS_GetNumberOfAtoms()); + NS_POSTCONDITION(0 == NS_GetNumberOfAtoms(), "dangling atoms"); + + return 0; +} diff --git a/mozilla/xpcom/tests/TestCRT.cpp b/mozilla/xpcom/tests/TestCRT.cpp new file mode 100644 index 00000000000..951a3a741cf --- /dev/null +++ b/mozilla/xpcom/tests/TestCRT.cpp @@ -0,0 +1,89 @@ +/* -*- 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 "nsCRT.h" +#include "nsString.h" +#include "plstr.h" +#include + +// Verify that nsCRT versions of string comparison routines get the +// same answers as the native non-unicode versions. We only pass in +// iso-latin-1 strings, so the comparision must be valid. +static void Check(const char* s1, const char* s2, PRIntn n) +{ + PRIntn clib = PL_strcmp(s1, s2); + PRIntn clib_n = PL_strncmp(s1, s2, n); + PRIntn clib_case = PL_strcasecmp(s1, s2); + PRIntn clib_case_n = PL_strncasecmp(s1, s2, n); + + nsAutoString t1(s1), t2(s2); + PRUnichar* us1 = t1.GetUnicode(); + PRUnichar* us2 = t2.GetUnicode(); + + PRIntn u = nsCRT::strcmp(us1, s2); + PRIntn u_n = nsCRT::strncmp(us1, s2, n); + PRIntn u_case = nsCRT::strcasecmp(us1, s2); + PRIntn u_case_n = nsCRT::strncasecmp(us1, s2, n); + + PRIntn u2 = nsCRT::strcmp(us1, us2); + PRIntn u2_n = nsCRT::strncmp(us1, us2, n); + PRIntn u2_case = nsCRT::strcasecmp(us1, us2); + PRIntn u2_case_n = nsCRT::strncasecmp(us1, us2, n); + + NS_ASSERTION(clib == u, "strcmp"); + NS_ASSERTION(clib_n == u_n, "strncmp"); + NS_ASSERTION(clib_case == u_case, "strcasecmp"); + NS_ASSERTION(clib_case_n == u_case_n, "strncasecmp"); + + NS_ASSERTION(clib == u2, "strcmp"); + NS_ASSERTION(clib_n == u2_n, "strncmp"); + NS_ASSERTION(clib_case == u2_case, "strcasecmp"); + NS_ASSERTION(clib_case_n == u2_case_n, "strncasecmp"); +} + +struct Test { + const char* s1; + const char* s2; + PRIntn n; +}; + +static Test tests[] = { + { "foo", "foo", 3 }, + { "foo", "fo", 3 }, + + { "foo", "bar", 3 }, + { "foo", "ba", 3 }, + + { "foo", "zap", 3 }, + { "foo", "za", 3 }, + + { "bar", "foo", 3 }, + { "bar", "fo", 3 }, + + { "bar", "foo", 3 }, + { "bar", "fo", 3 }, +}; +#define NUM_TESTS (sizeof(tests) / sizeof(tests[0])) + +void main() +{ + Test* tp = tests; + for (PRIntn i = 0; i < NUM_TESTS; i++, tp++) { + Check(tp->s1, tp->s2, tp->n); + } +} diff --git a/mozilla/xpcom/tests/resources.h b/mozilla/xpcom/tests/resources.h new file mode 100644 index 00000000000..99145e93a2a --- /dev/null +++ b/mozilla/xpcom/tests/resources.h @@ -0,0 +1,32 @@ +/* -*- 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. + */ +#ifndef resources_h___ +#define resources_h___ + +#define TIMER_1SECOND 40000 +#define TIMER_5SECOND 40001 +#define TIMER_10SECOND 40002 + +#define TIMER_1REPEAT 40003 +#define TIMER_5REPEAT 40004 +#define TIMER_10REPEAT 40005 + +#define TIMER_CANCEL 40006 +#define TIMER_EXIT 40010 + +#endif /* resources_h___ */