/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer 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" #include "nsUnitConversion.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, nsIFrame* aParentFrame); NS_IMETHOD Reflow(nsIPresContext* aPresContext, nsReflowMetrics& aDesiredSize, const nsReflowState& aReflowState, nsReflowStatus& aStatus); protected: virtual ~SpacerFrame(); }; class SpacerPart : public nsHTMLTagContent { public: SpacerPart(nsIAtom* aTag); virtual nsresult CreateFrame(nsIPresContext* aPresContext, nsIFrame* aParentFrame, nsIStyleContext* aStyleContext, nsIFrame*& aResult); 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, nsIFrame* aParentFrame) : nsFrame(aContent, aParentFrame) { } SpacerFrame::~SpacerFrame() { } NS_METHOD SpacerFrame::Reflow(nsIPresContext* aPresContext, nsReflowMetrics& aDesiredSize, const nsReflowState& aReflowState, nsReflowStatus& aStatus) { // Get cached state for containing block frame nsBlockReflowState* state = nsnull; #if XXX nsIFrame* parent = mGeometricParent; while (nsnull != parent) { nsresult status = parent->QueryInterface(kIHTMLFrameTypeIID, (void**) &ft); if (NS_OK == status) { nsHTMLFrameType type = ft->GetFrameType(); if (eHTMLFrame_Block == type) { break; } } parent->GetGeometricParent(parent); } if (nsnull != parent) { nsIPresShell* shell = aPresContext->GetShell(); state = (nsBlockReflowState*) shell->GetCachedData(parent); NS_RELEASE(shell); } #endif // 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 aStatus = NS_FRAME_COMPLETE; return NS_OK; } 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) { // XXX percent??? float p2t = aPresContext->GetPixelsToTwips(); width = (nscoord)NS_INT_PIXELS_TO_TWIPS(val.GetPixelValue(), p2t); } } else { nsHTMLValue val; float p2t = aPresContext->GetPixelsToTwips(); ca = part->GetAttribute(nsHTMLAtoms::width, val); if (eContentAttr_HasValue == ca) { if (eHTMLUnit_Pixel == val.GetUnit()) { width = (nscoord)NS_INT_PIXELS_TO_TWIPS(val.GetPixelValue(), p2t); } else if (eHTMLUnit_Percent == val.GetUnit()) { // XXX percent of what? } } ca = part->GetAttribute(nsHTMLAtoms::height, val); if (eContentAttr_HasValue == ca) { if (eHTMLUnit_Pixel == val.GetUnit()) { height = (nscoord)NS_INT_PIXELS_TO_TWIPS(val.GetPixelValue(), p2t); } 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) { #if XXX state->breakBeforeChild = PR_TRUE; state->breakAfterChild = PR_TRUE; #endif 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; } aStatus = NS_FRAME_COMPLETE; return NS_OK; } //---------------------------------------------------------------------- SpacerPart::SpacerPart(nsIAtom* aTag) : nsHTMLTagContent(aTag) { } SpacerPart::~SpacerPart() { } nsresult SpacerPart::CreateFrame(nsIPresContext* aPresContext, nsIFrame* aParentFrame, nsIStyleContext* aStyleContext, nsIFrame*& aResult) { nsIFrame* frame = new SpacerFrame(this, aParentFrame); if (nsnull == frame) { return NS_ERROR_OUT_OF_MEMORY; } frame->SetStyleContext(aPresContext, aStyleContext); aResult = frame; return NS_OK; } 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, eHTMLUnit_Pixel); 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, eHTMLUnit_Pixel); 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); }