892 lines
27 KiB
C++
892 lines
27 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer 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 "nsIPresContext.h"
|
|
#include "nsHTMLIIDs.h"
|
|
#include "nsHTMLAtoms.h"
|
|
#include "nsIHTMLAttributes.h"
|
|
#include "nsDOMIterator.h"
|
|
#include "nsUnitConversion.h"
|
|
#include "nsIURL.h"
|
|
#include "prprf.h"
|
|
|
|
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);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLContainer::InsertChildAt(nsIContent* aKid, PRInt32 aIndex,
|
|
PRBool aNotify)
|
|
{
|
|
NS_PRECONDITION(nsnull != aKid, "null ptr");
|
|
PRBool rv = mChildren.InsertElementAt(aKid, aIndex);/* XXX fix up void array api to use nsresult's*/
|
|
if (rv) {
|
|
NS_ADDREF(aKid);
|
|
aKid->SetParent(this);
|
|
nsIDocument* doc = mDocument;
|
|
if (nsnull != doc) {
|
|
aKid->SetDocument(doc);
|
|
if (aNotify) {
|
|
doc->ContentInserted(this, aKid, aIndex);
|
|
}
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLContainer::ReplaceChildAt(nsIContent* aKid, PRInt32 aIndex,
|
|
PRBool aNotify)
|
|
{
|
|
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);
|
|
if (aNotify) {
|
|
doc->ContentReplaced(this, oldKid, aKid, aIndex);
|
|
}
|
|
}
|
|
oldKid->SetDocument(nsnull);
|
|
oldKid->SetParent(nsnull);
|
|
NS_RELEASE(oldKid);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLContainer::AppendChild(nsIContent* aKid, PRBool aNotify)
|
|
{
|
|
NS_PRECONDITION((nsnull != aKid) && (aKid != this), "null ptr");
|
|
PRBool rv = mChildren.AppendElement(aKid);
|
|
if (rv) {
|
|
NS_ADDREF(aKid);
|
|
aKid->SetParent(this);
|
|
nsIDocument* doc = mDocument;
|
|
if (nsnull != doc) {
|
|
aKid->SetDocument(doc);
|
|
if (aNotify) {
|
|
doc->ContentAppended(this);
|
|
}
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLContainer::RemoveChildAt(PRInt32 aIndex, PRBool aNotify)
|
|
{
|
|
nsIContent* oldKid = (nsIContent*) mChildren.ElementAt(aIndex);
|
|
if (nsnull != oldKid ) {
|
|
nsIDocument* doc = mDocument;
|
|
if (aNotify) {
|
|
if (nsnull != doc) {
|
|
doc->ContentWillBeRemoved(this, oldKid, aIndex);
|
|
}
|
|
}
|
|
PRBool rv = mChildren.RemoveElementAt(aIndex);
|
|
if (aNotify) {
|
|
if (nsnull != doc) {
|
|
doc->ContentHasBeenRemoved(this, oldKid, aIndex);
|
|
}
|
|
}
|
|
oldKid->SetDocument(nsnull);
|
|
oldKid->SetParent(nsnull);
|
|
NS_RELEASE(oldKid);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void nsHTMLContainer::Compact()
|
|
{
|
|
//XXX I'll turn this on in a bit... mChildren.Compact();
|
|
}
|
|
|
|
nsresult
|
|
nsHTMLContainer::CreateFrame(nsIPresContext* aPresContext,
|
|
nsIFrame* aParentFrame,
|
|
nsIStyleContext* aStyleContext,
|
|
nsIFrame*& aResult)
|
|
{
|
|
const nsStyleDisplay* styleDisplay =
|
|
(const nsStyleDisplay*) aStyleContext->GetStyleData(eStyleStruct_Display);
|
|
|
|
// Use style to choose what kind of frame to create
|
|
nsIFrame* frame = nsnull;
|
|
nsresult rv;
|
|
switch (styleDisplay->mDisplay) {
|
|
case NS_STYLE_DISPLAY_BLOCK:
|
|
case NS_STYLE_DISPLAY_LIST_ITEM:
|
|
rv = nsBlockFrame::NewFrame(&frame, this, aParentFrame);
|
|
break;
|
|
|
|
case NS_STYLE_DISPLAY_INLINE:
|
|
rv = nsInlineFrame::NewFrame(&frame, this, aParentFrame);
|
|
break;
|
|
|
|
default:
|
|
// Create an empty frame for holding content that is not being
|
|
// reflowed.
|
|
rv = nsFrame::NewFrame(&frame, this, aParentFrame);
|
|
break;
|
|
}
|
|
if (NS_OK == rv) {
|
|
frame->SetStyleContext(aPresContext, aStyleContext);
|
|
}
|
|
aResult = frame;
|
|
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 }
|
|
};
|
|
|
|
static nsHTMLTagContent::EnumTable kDirTable[] = {
|
|
{ "ltr", NS_STYLE_DIRECTION_LTR },
|
|
{ "rtl", NS_STYLE_DIRECTION_RTL },
|
|
{ 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;
|
|
|
|
// Check for attributes common to most html containers
|
|
if (aAttribute == nsHTMLAtoms::dir) {
|
|
if (ParseEnumValue(aValue, kDirTable, val)) {
|
|
nsHTMLTagContent::SetAttribute(aAttribute, val);
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
if (aAttribute == nsHTMLAtoms::lang) {
|
|
nsHTMLTagContent::SetAttribute(aAttribute, aValue);
|
|
return;
|
|
}
|
|
|
|
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.SetEmptyValue();
|
|
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.SetIntValue(v, ((ch == '+') || (ch == '-')) ?
|
|
eHTMLUnit_Integer : 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, eHTMLUnit_Integer);
|
|
nsHTMLTagContent::SetAttribute(aAttribute, val);
|
|
return;
|
|
}
|
|
|
|
// Note: These attributes only apply when cols > 1
|
|
if (aAttribute == nsHTMLAtoms::gutter) {
|
|
ParseValue(aValue, 1, val, eHTMLUnit_Pixel);
|
|
nsHTMLTagContent::SetAttribute(aAttribute, val);
|
|
return;
|
|
}
|
|
if (aAttribute == nsHTMLAtoms::width) {
|
|
ParseValueOrPercent(aValue, val, eHTMLUnit_Pixel);
|
|
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.SetEmptyValue();
|
|
nsHTMLTagContent::SetAttribute(aAttribute, val);
|
|
return;
|
|
}
|
|
if (aAttribute == nsHTMLAtoms::cols) {
|
|
ParseValue(aValue, 0, val, eHTMLUnit_Integer);
|
|
nsHTMLTagContent::SetAttribute(aAttribute, val);
|
|
return;
|
|
}
|
|
if (aAttribute == nsHTMLAtoms::tabstop) {
|
|
PRInt32 ec, tabstop = aValue.ToInteger(&ec);
|
|
if (tabstop <= 0) {
|
|
tabstop = 8;
|
|
}
|
|
val.SetIntValue(tabstop, eHTMLUnit_Integer);
|
|
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, eHTMLUnit_Integer);
|
|
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.SetIntValue(NS_STYLE_LIST_STYLE_BASIC, eHTMLUnit_Enumerated);
|
|
}
|
|
nsHTMLTagContent::SetAttribute(aAttribute, val);
|
|
return;
|
|
}
|
|
if (aAttribute == nsHTMLAtoms::start) {
|
|
ParseValue(aValue, 1, val, eHTMLUnit_Integer);
|
|
nsHTMLTagContent::SetAttribute(aAttribute, val);
|
|
return;
|
|
}
|
|
if (aAttribute == nsHTMLAtoms::compact) {
|
|
val.SetEmptyValue();
|
|
nsHTMLTagContent::SetAttribute(aAttribute, val);
|
|
return;
|
|
}
|
|
}
|
|
else if (mTag == nsHTMLAtoms::dl) {
|
|
if (aAttribute == nsHTMLAtoms::compact) {
|
|
val.SetEmptyValue();
|
|
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;
|
|
|
|
// Check for attributes common to most html containers
|
|
GetAttribute(nsHTMLAtoms::dir, value);
|
|
if (value.GetUnit() == eHTMLUnit_Enumerated) {
|
|
nsStyleDisplay* display = (nsStyleDisplay*)
|
|
aContext->GetMutableStyleData(eStyleStruct_Display);
|
|
display->mDirection = value.GetIntValue();
|
|
}
|
|
|
|
if (mTag == nsHTMLAtoms::p) {
|
|
// align: enum
|
|
GetAttribute(nsHTMLAtoms::align, value);
|
|
if (value.GetUnit() == eHTMLUnit_Enumerated) {
|
|
nsStyleText* text = (nsStyleText*)aContext->GetMutableStyleData(eStyleStruct_Text);
|
|
text->mTextAlign = value.GetIntValue();
|
|
}
|
|
}
|
|
else if (mTag == nsHTMLAtoms::a) {
|
|
// suppress: bool (absolute)
|
|
GetAttribute(nsHTMLAtoms::suppress, value);
|
|
if (value.GetUnit() == eHTMLUnit_Empty) {
|
|
// XXX set suppress
|
|
}
|
|
}
|
|
else if (mTag == nsHTMLAtoms::font) {
|
|
nsStyleFont* font = (nsStyleFont*)aContext->GetMutableStyleData(eStyleStruct_Font);
|
|
const nsStyleFont* parentFont = font;
|
|
nsIStyleContext* parentContext = aContext->GetParent();
|
|
if (nsnull != parentContext) {
|
|
parentFont = (const nsStyleFont*)parentContext->GetStyleData(eStyleStruct_Font);
|
|
}
|
|
|
|
// 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: int, enum
|
|
GetAttribute(nsHTMLAtoms::pointSize, value);
|
|
if (value.GetUnit() == eHTMLUnit_Integer) {
|
|
// 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: int, enum
|
|
GetAttribute(nsHTMLAtoms::size, value);
|
|
if ((value.GetUnit() == eHTMLUnit_Integer) || (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 { // int (+/-)
|
|
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: int, enum
|
|
GetAttribute(nsHTMLAtoms::fontWeight, value);
|
|
if (value.GetUnit() == eHTMLUnit_Integer) { // +/-
|
|
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->GetMutableStyleData(eStyleStruct_Color);
|
|
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->GetMutableStyleData(eStyleStruct_Color);
|
|
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_Integer) {
|
|
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_Pixel) {
|
|
// XXX set
|
|
}
|
|
|
|
// width: pixel, %
|
|
GetAttribute(nsHTMLAtoms::width, value);
|
|
if (value.GetUnit() == eHTMLUnit_Pixel) {
|
|
// XXX set
|
|
}
|
|
else if (value.GetUnit() == eHTMLUnit_Percent) {
|
|
// 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: empty
|
|
GetAttribute(nsHTMLAtoms::wrap, value);
|
|
if (value.GetUnit() == eHTMLUnit_Empty) {
|
|
// XXX set
|
|
}
|
|
|
|
// variable: empty
|
|
GetAttribute(nsHTMLAtoms::variable, value);
|
|
if (value.GetUnit() == eHTMLUnit_Empty) {
|
|
// XXX set
|
|
}
|
|
|
|
// cols: int
|
|
GetAttribute(nsHTMLAtoms::cols, value);
|
|
if (value.GetUnit() == eHTMLUnit_Integer) {
|
|
// XXX set
|
|
}
|
|
|
|
// tabstop: int
|
|
if (value.GetUnit() == eHTMLUnit_Integer) {
|
|
// XXX set
|
|
}
|
|
}
|
|
else if (mTag == nsHTMLAtoms::li) {
|
|
nsStyleList* list = (nsStyleList*)aContext->GetMutableStyleData(eStyleStruct_List);
|
|
|
|
// 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->GetMutableStyleData(eStyleStruct_List);
|
|
|
|
// type: enum
|
|
GetAttribute(nsHTMLAtoms::type, value);
|
|
if (value.GetUnit() == eHTMLUnit_Enumerated) {
|
|
list->mListStyleType = value.GetIntValue();
|
|
}
|
|
|
|
// compact: empty
|
|
GetAttribute(nsHTMLAtoms::compact, value);
|
|
if (value.GetUnit() == eHTMLUnit_Empty) {
|
|
// XXX set
|
|
}
|
|
}
|
|
else if (mTag == nsHTMLAtoms::dl) {
|
|
// compact: flag
|
|
GetAttribute(nsHTMLAtoms::compact, value);
|
|
if (value.GetUnit() == eHTMLUnit_Empty) {
|
|
// 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->GetMutableStyleData(eStyleStruct_Color);
|
|
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->GetMutableStyleData(eStyleStruct_Color);
|
|
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->GetMutableStyleData(eStyleStruct_Color);
|
|
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)
|
|
{
|
|
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)
|
|
{
|
|
NS_PRECONDITION(nsnull != newChild, "Null new child");
|
|
|
|
// Get the nsIContent interface for the new content
|
|
nsIContent* newContent = nsnull;
|
|
nsresult res = newChild->QueryInterface(kIContentIID, (void**)&newContent);
|
|
NS_ASSERTION(NS_OK == res, "New child must be an nsIContent");
|
|
|
|
if (NS_OK == res) {
|
|
if (nsnull == refChild) {
|
|
// Append the new child to the end
|
|
res = AppendChild(newContent, PR_TRUE);
|
|
} else {
|
|
nsIContent* content = nsnull;
|
|
|
|
// Get the index of where to insert the new child
|
|
res = refChild->QueryInterface(kIContentIID, (void**)&content);
|
|
NS_ASSERTION(NS_OK == res, "Ref child must be an nsIContent");
|
|
if (NS_OK == res) {
|
|
PRInt32 pos = IndexOf(content);
|
|
if (pos >= 0) {
|
|
res = InsertChildAt(newContent, pos, PR_TRUE);
|
|
}
|
|
NS_RELEASE(content);
|
|
}
|
|
}
|
|
|
|
NS_RELEASE(newContent);
|
|
}
|
|
|
|
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) {
|
|
res = ReplaceChildAt(newContent, pos, PR_TRUE);
|
|
NS_RELEASE(newContent);
|
|
}
|
|
}
|
|
NS_RELEASE(content);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
nsresult
|
|
nsHTMLContainer::RemoveChild(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) {
|
|
res = RemoveChildAt(pos, PR_TRUE);
|
|
}
|
|
NS_RELEASE(content);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|