/**
 * This file is part of the DOM implementation for KDE.
 *
 * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org)
 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
 *           (C) 2002-2003 Apple Computer, Inc.
 *           (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
 *           (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 */
// -------------------------------------------------------------------------
//#define DEBUG_LAYOUT
//#define CLIP_DEBUG


#include <tqpainter.h>

#include "misc/loader.h"
#include "rendering/render_replaced.h"
#include "rendering/render_canvas.h"
#include "rendering/render_table.h"
#include "rendering/render_inline.h"
#include "rendering/render_block.h"
#include "rendering/render_line.h"
#include "rendering/render_layer.h"
#include "misc/htmlhashes.h"
#include "xml/dom_nodeimpl.h"
#include "xml/dom_docimpl.h"
#include "html/html_elementimpl.h"

#include <khtmlview.h>
#include <kdebug.h>
#include <kglobal.h>
#include <assert.h>


using namespace DOM;
using namespace khtml;

#define TABLECELLMARGIN -0x4000

RenderBox::RenderBox(DOM::NodeImpl* node)
    : RenderContainer(node)
{
    m_minWidth = -1;
    m_maxWidth = -1;
    m_width = m_height = 0;
    m_x = 0;
    m_y = 0;
    m_marginTop = 0;
    m_marginBottom = 0;
    m_marginLeft = 0;
    m_marginRight = 0;
    m_staticX = 0;
    m_staticY = 0;

    m_placeHolderBox = 0;
    m_layer = 0;
}

RenderBlock* RenderBox::createAnonymousBlock()
{
    RenderStyle *newStyle = new RenderStyle();
    newStyle->inheritFrom(style());
    newStyle->setDisplay(BLOCK);

    RenderBlock *newBox = new (renderArena()) RenderBlock(document() /* anonymous*/);
    newBox->setStyle(newStyle);
    return newBox;
}

void RenderBox::restructureParentFlow() {
    if (!parent() || parent()->childrenInline() == isInline())
        return;
    // We have gone from not affecting the inline status of the parent flow to suddenly
    // having an impact.  See if there is a mismatch between the parent flow's
    // childrenInline() state and our state.
    if (!isInline()) {
        if (parent()->isRenderInline()) {
            // We have to split the parent flow.
            RenderInline* parentInline = static_cast<RenderInline*>(parent());
            RenderBlock* newBox = parentInline->createAnonymousBlock();

            RenderFlow* oldContinuation = parent()->continuation();
            parentInline->setContinuation(newBox);

            RenderObject* beforeChild = nextSibling();
            parent()->removeChildNode(this);
            parentInline->splitFlow(beforeChild, newBox, this, oldContinuation);
        }
        else if (parent()->isRenderBlock())
            static_cast<RenderBlock*>(parent())->makeChildrenNonInline();
    }
    else {
        // An anonymous block must be made to wrap this inline.
        RenderBlock* box = createAnonymousBlock();
        parent()->insertChildNode(box, this);
        box->appendChildNode(parent()->removeChildNode(this));
    }
}

static inline bool overflowAppliesTo(RenderObject* o) 
{
     // css 2.1-11.1.1
     // 1) overflow only applies to non-replaced block-level elements, table cells, and inline-block elements
     if (o->isRenderBlock() || o->isTableRow() || o->isTableSection())
         // 2) overflow on root applies to the viewport (cf. KHTMLView::layout)
         if (!o->isRoot())
             // 3) overflow on body may apply to the viewport...
             if (!o->isBody()
                   // ...but only for HTML documents...
                   || !o->document()->isHTMLDocument()
                   // ...and only when the root has a visible overflow   
                   || !o->document()->documentElement()->renderer()
                   || !o->document()->documentElement()->renderer()->style()
                   ||  o->document()->documentElement()->renderer()->style()->hidesOverflow())
                 return true;

     return false; 
} 

void RenderBox::setStyle(RenderStyle *_style)
{
    bool affectsParent = style() && isFloatingOrPositioned() &&
         (!_style->isFloating() && _style->position() != ABSOLUTE && _style->position() != FIXED) &&
         parent() && (parent()->isBlockFlow() || parent()->isInlineFlow());

    RenderContainer::setStyle(_style);

    // The root always paints its background/border.
    if (isRoot())
        setShouldPaintBackgroundOrBorder(true);

    switch(_style->display())
    {
    case INLINE:
    case INLINE_BLOCK:
    case INLINE_TABLE:
        setInline(true);
        break;
    case RUN_IN:
        if (isInline() && parent() && parent()->childrenInline())
            break;
    default:
        setInline(false);
    }

    switch(_style->position())
    {
    case ABSOLUTE:
    case FIXED:
        setPositioned(true);
        break;
    default:
        setPositioned(false);
        if( !isTableCell() && _style->isFloating() )
            setFloating(true);

        if( _style->position() == RELATIVE )
            setRelPositioned(true);
    }

    if (overflowAppliesTo(this) && _style->hidesOverflow())
        setHasOverflowClip();
        
    if (requiresLayer()) {
        if (!m_layer) {
            m_layer = new (renderArena()) RenderLayer(this);
            m_layer->insertOnlyThisLayer();
            if (parent() && containingBlock())
                m_layer->updateLayerPosition();
        }
    }
    else if (m_layer && !isCanvas()) {
        m_layer->removeOnlyThisLayer();
        m_layer = 0;
    }

    if (m_layer)
        m_layer->styleChanged();

    if (style()->outlineWidth() > 0 && style()->outlineSize() > maximalOutlineSize(PaintActionOutline))
        static_cast<RenderCanvas*>(document()->renderer())->setMaximalOutlineSize(style()->outlineSize());
    if (affectsParent)
        restructureParentFlow();
}

RenderBox::~RenderBox()
{
    //kdDebug( 6040 ) << "Element destructor: this=" << nodeName().string() << endl;
}

void RenderBox::detach()
{
    RenderLayer* layer = m_layer;
    RenderArena* arena = renderArena();

    RenderContainer::detach();

    if (layer)
        layer->detach(arena);
}

InlineBox* RenderBox::createInlineBox(bool /*makePlaceHolderBox*/, bool /*isRootLineBox*/)
{
    if (m_placeHolderBox)
        m_placeHolderBox->detach(renderArena());
    return (m_placeHolderBox = new (renderArena()) InlineBox(this));
}

void RenderBox::deleteInlineBoxes(RenderArena* arena)
{
    if (m_placeHolderBox) {
        m_placeHolderBox->detach( arena ? arena : renderArena() );
        m_placeHolderBox = 0;
    }
}

short RenderBox::contentWidth() const
{
    short w = m_width - style()->borderLeftWidth() - style()->borderRightWidth();
    w -= paddingLeft() + paddingRight();

    if (m_layer && scrollsOverflowY())
        w -= m_layer->verticalScrollbarWidth();

    //kdDebug( 6040 ) << "RenderBox::contentWidth(2) = " << w << endl;
    return w;
}

int RenderBox::contentHeight() const
{
    int h = m_height - style()->borderTopWidth() - style()->borderBottomWidth();
    h -= paddingTop() + paddingBottom();

    if (m_layer && scrollsOverflowX())
        h -= m_layer->horizontalScrollbarHeight();

    return h;
}

void RenderBox::setPos( int xPos, int yPos )
{
    m_x = xPos; m_y = yPos;
}

short RenderBox::width() const
{
    return m_width;
}

int RenderBox::height() const
{
    return m_height;
}

void RenderBox::setWidth( int width )
{
    m_width = width;
}

void RenderBox::setHeight( int height )
{
    m_height = height;
}

int RenderBox::calcBoxHeight(int h) const
{
    if (style()->boxSizing() == CONTENT_BOX)
        h += borderTop() + borderBottom() + paddingTop() + paddingBottom();

    return h;
}

int RenderBox::calcBoxWidth(int w) const
{
    if (style()->boxSizing() == CONTENT_BOX)
        w += borderLeft() + borderRight() + paddingLeft() + paddingRight();

    return w;
}

int RenderBox::calcContentHeight(int h) const
{
    if (style()->boxSizing() == BORDER_BOX)
        h -= borderTop() + borderBottom() + paddingTop() + paddingBottom();

    return kMax(0, h);
}

int RenderBox::calcContentWidth(int w) const
{
    if (style()->boxSizing() == BORDER_BOX)
        w -= borderLeft() + borderRight() + paddingLeft() + paddingRight();

    return kMax(0, w);
}

// --------------------- painting stuff -------------------------------

void RenderBox::paint(PaintInfo& i, int _tx, int _ty)
{
    _tx += m_x;
    _ty += m_y;

    if (hasOverflowClip() && m_layer)
        m_layer->subtractScrollOffset(_tx, _ty);

    // default implementation. Just pass things through to the children
    for(RenderObject* child = firstChild(); child; child = child->nextSibling())
        child->paint(i, _tx, _ty);
}

void RenderBox::paintRootBoxDecorations(PaintInfo& paintInfo, int _tx, int _ty)
{
    //kdDebug( 6040 ) << renderName() << "::paintRootBoxDecorations()" << _tx << "/" << _ty << endl;
    const BackgroundLayer* bgLayer = style()->backgroundLayers();
    TQColor bgColor = style()->backgroundColor();
    if (document()->isHTMLDocument() && !style()->hasBackground()) {
        // Locate the <body> element using the DOM.  This is easier than trying
        // to crawl around a render tree with potential :before/:after content and
        // anonymous blocks created by inline <body> tags etc.  We can locate the <body>
        // render object very easily via the DOM.
        HTMLElementImpl* body = document()->body();
        RenderObject* bodyObject = (body && body->id() == ID_BODY) ? body->renderer() : 0;

        if (bodyObject) {
            bgLayer = bodyObject->style()->backgroundLayers();
            bgColor = bodyObject->style()->backgroundColor();
        }
    }

    if( !bgColor.isValid() && canvas()->view())
        bgColor = canvas()->view()->palette().active().color(TQColorGroup::Base);

    int w = width();
    int h = height();

    //    kdDebug(0) << "width = " << w <<endl;

    int rw, rh;
    if (canvas()->view()) {
        rw = canvas()->view()->contentsWidth();
        rh = canvas()->view()->contentsHeight();
    } else {
        rw = canvas()->docWidth();
        rh = canvas()->docHeight();
    }

    //    kdDebug(0) << "rw = " << rw <<endl;

    int bx = _tx - marginLeft();
    int by = _ty - marginTop();
    int bw = QMAX(w + marginLeft() + marginRight() + borderLeft() + borderRight(), rw);
    int bh = QMAX(h + marginTop() + marginBottom() + borderTop() + borderBottom(), rh);

    // CSS2 14.2:
    // " The background of the box generated by the root element covers the entire canvas."
    // hence, paint the background even in the margin areas (unlike for every other element!)
    // I just love these little inconsistencies .. :-( (Dirk)
    int my = kMax(by, paintInfo.r.y());

    paintBackgrounds(paintInfo.p, bgColor, bgLayer, my, paintInfo.r.height(), bx, by, bw, bh);

    if(style()->hasBorder())
        paintBorder( paintInfo.p, _tx, _ty, w, h, style() );
}

void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, int _tx, int _ty)
{
    //kdDebug( 6040 ) << renderName() << "::paintDecorations()" << endl;

    if(isRoot())
        return paintRootBoxDecorations(paintInfo, _tx, _ty);

    int w = width();
    int h = height() + borderTopExtra() + borderBottomExtra();
    _ty -= borderTopExtra();

    int my = kMax(_ty,paintInfo.r.y());
    int end = kMin( paintInfo.r.y() + paintInfo.r.height(), _ty + h );
    int mh = end - my;

   // The <body> only paints its background if the root element has defined a background
   // independent of the body.  Go through the DOM to get to the root element's render object,
   // since the root could be inline and wrapped in an anonymous block.

   if (!isBody() || !document()->isHTMLDocument() || document()->documentElement()->renderer()->style()->hasBackground())
        paintBackgrounds(paintInfo.p, style()->backgroundColor(), style()->backgroundLayers(), my, mh, _tx, _ty, w, h);

   if(style()->hasBorder()) {
        paintBorder(paintInfo.p, _tx, _ty, w, h, style());
    }
}

void RenderBox::paintBackgrounds(TQPainter *p, const TQColor& c, const BackgroundLayer* bgLayer, int clipy, int cliph, int _tx, int _ty, int w, int height)
 {
    if (!bgLayer) return;
    paintBackgrounds(p, c, bgLayer->next(), clipy, cliph, _tx, _ty, w, height);
    paintBackground(p, c, bgLayer, clipy, cliph, _tx, _ty, w, height);
}

void RenderBox::paintBackground(TQPainter *p, const TQColor& c, const BackgroundLayer* bgLayer, int clipy, int cliph, int _tx, int _ty, int w, int height)
{
    paintBackgroundExtended(p, c, bgLayer, clipy, cliph, _tx, _ty, w, height,
                            borderLeft(), borderRight(), paddingLeft(), paddingRight());
}

static void calculateBackgroundSize(const BackgroundLayer* bgLayer, int& scaledWidth, int& scaledHeight)
{
    CachedImage* bg = bgLayer->backgroundImage();

    if (bgLayer->isBackgroundSizeSet()) {
        Length bgWidth = bgLayer->backgroundSize().width;
        Length bgHeight = bgLayer->backgroundSize().height;

        if (bgWidth.isPercent())
            scaledWidth = scaledWidth * bgWidth.value() / 100;
        else if (bgWidth.isFixed())
            scaledWidth = bgWidth.value();
        else if (bgWidth.isVariable()) {
            // If the width is auto and the height is not, we have to use the appropriate
            // scale to maintain our aspect ratio.
            if (bgHeight.isPercent()) {
                int scaledH = scaledHeight * bgHeight.value() / 100;
                scaledWidth = bg->pixmap_size().width() * scaledH / bg->pixmap_size().height();
            } else if (bgHeight.isFixed())
                scaledWidth = bg->pixmap_size().width() * bgHeight.value() / bg->pixmap_size().height();
        }

        if (bgHeight.isPercent())
            scaledHeight = scaledHeight * bgHeight.value() / 100;
        else if (bgHeight.isFixed())
            scaledHeight = bgHeight.value();
        else if (bgHeight.isVariable()) {
            // If the height is auto and the width is not, we have to use the appropriate
            // scale to maintain our aspect ratio.
            if (bgWidth.isPercent())
                scaledHeight = bg->pixmap_size().height() * scaledWidth / bg->pixmap_size().width();
            else if (bgWidth.isFixed())
                scaledHeight = bg->pixmap_size().height() * bgWidth.value() / bg->pixmap_size().width();
            else if (bgWidth.isVariable()) {
                // If both width and height are auto, we just want to use the image's
                // intrinsic size.
                scaledWidth = bg->pixmap_size().width();
                scaledHeight = bg->pixmap_size().height();
            }
        }
    } else {
        scaledWidth = bg->pixmap_size().width();
        scaledHeight = bg->pixmap_size().height();
    }
}

void RenderBox::paintBackgroundExtended(TQPainter *p, const TQColor &c, const BackgroundLayer* bgLayer, int clipy, int cliph,
                                        int _tx, int _ty, int w, int h,
                                        int bleft, int bright, int pleft, int pright)
{
    if ( cliph < 0 )
	return;

    if (bgLayer->backgroundClip() != BGBORDER) {
        // Clip to the padding or content boxes as necessary.
        bool includePadding = bgLayer->backgroundClip() == BGCONTENT;
        int x = _tx + bleft + (includePadding ? pleft : 0);
        int y = _ty + borderTop() + (includePadding ? paddingTop() : 0);
        int width = w - bleft - bright - (includePadding ? pleft + pright : 0);
        int height = h - borderTop() - borderBottom() - (includePadding ? paddingTop() + paddingBottom() : 0);
        p->save();
        p->setClipRect(TQRect(x, y, width, height), TQPainter::CoordPainter);
    }

    CachedImage* bg = bgLayer->backgroundImage();
    bool shouldPaintBackgroundImage = bg && bg->pixmap_size() == bg->valid_rect().size() && !bg->isTransparent() && !bg->isErrorImage();
    TQColor bgColor = c;

    // Paint the color first underneath all images.
    if (!bgLayer->next() && bgColor.isValid() && tqAlpha(bgColor.rgb()) > 0)
        p->fillRect(_tx, clipy, w, cliph, bgColor);

    // no progressive loading of the background image
    if (shouldPaintBackgroundImage) {
        int sx = 0;
        int sy = 0;
        int cw,ch;
        int cx,cy;
        int scaledImageWidth, scaledImageHeight;

        // CSS2 chapter 14.2.1

        if (bgLayer->backgroundAttachment()) {
            //scroll
            int hpab = 0, vpab = 0, left = 0, top = 0; // Init to 0 for background-origin of 'border'
            if (bgLayer->backgroundOrigin() != BGBORDER) {
                hpab += bleft + bright;
                vpab += borderTop() + borderBottom();
                left += bleft;
                top += borderTop();
                if (bgLayer->backgroundOrigin() == BGCONTENT) {
                    hpab += pleft + pright;
                    vpab += paddingTop() + paddingBottom();
                    left += pleft;
                    top += paddingTop();
                }
            }

            int pw = w - hpab;
            int ph = h - vpab;
            scaledImageWidth = pw;
            scaledImageHeight = ph;
            calculateBackgroundSize(bgLayer, scaledImageWidth, scaledImageHeight);

            EBackgroundRepeat bgr = bgLayer->backgroundRepeat();
            if (bgr == NO_REPEAT || bgr == REPEAT_Y) {
                cw = scaledImageWidth;
                int xPosition = bgLayer->backgroundXPosition().minWidth(pw-scaledImageWidth);
                if ( xPosition >= 0 ) {
                    cx = _tx + xPosition;
                    cw = kMin(scaledImageWidth, pw - xPosition);
                }
                else {
                    cx = _tx;
                    if (scaledImageWidth > 0) {
                        sx = -xPosition;
                        cw = kMin(scaledImageWidth+xPosition, pw);
                    }
                }
                cx += left;
            } else {
                // repeat over x
                cw = w;
                cx = _tx;
                if (scaledImageWidth > 0) {
                    int xPosition = bgLayer->backgroundXPosition().minWidth(pw-scaledImageWidth);
                    sx = scaledImageWidth - (xPosition % scaledImageWidth);
                    sx -= left % scaledImageWidth;
                }
            }
            if (bgr == NO_REPEAT || bgr == REPEAT_X) {
                ch = scaledImageHeight;
                int yPosition = bgLayer->backgroundYPosition().minWidth(ph - scaledImageHeight);
                if ( yPosition >= 0 ) {
                    cy = _ty + yPosition;
                    ch = kMin(ch, ph - yPosition);
                }
                else {
                    cy = _ty;
                    if (scaledImageHeight > 0) {
                        sy = -yPosition;
                        ch = kMin(scaledImageHeight+yPosition, ph);
                    }
                }

                cy += top;
            } else {
                // repeat over y
                ch = h;
                cy = _ty;
                if (scaledImageHeight > 0) {
                    int yPosition = bgLayer->backgroundYPosition().minWidth(ph - scaledImageHeight);
                    sy = scaledImageHeight - (yPosition % scaledImageHeight);
                    sy -= top % scaledImageHeight;
                }
            }
	    if (layer())
		layer()->scrollOffset(sx, sy);
        }
        else
        {
            //fixed
            TQRect vr = viewRect();
            int pw = vr.width();
            int ph = vr.height();
            scaledImageWidth = pw;
            scaledImageHeight = ph;
            calculateBackgroundSize(bgLayer, scaledImageWidth, scaledImageHeight);
            EBackgroundRepeat bgr = bgLayer->backgroundRepeat();

            int xPosition = bgLayer->backgroundXPosition().minWidth(pw-scaledImageWidth);
            if (bgr == NO_REPEAT || bgr == REPEAT_Y) {
                cw = kMin(scaledImageWidth, pw - xPosition);
                cx = vr.x() + xPosition;
            } else {
                cw = pw;
                cx = vr.x();
                if (scaledImageWidth > 0)
                    sx = scaledImageWidth - xPosition % scaledImageWidth;
            }

            int yPosition = bgLayer->backgroundYPosition().minWidth(ph-scaledImageHeight);
            if (bgr == NO_REPEAT || bgr == REPEAT_X) {
                ch = kMin(scaledImageHeight, ph - yPosition);
                cy = vr.y() + yPosition;
            } else {
                ch = ph;
                cy = vr.y();
                if (scaledImageHeight > 0)
                    sy = scaledImageHeight - yPosition % scaledImageHeight;
            }

            TQRect fix(cx, cy, cw, ch);
            TQRect ele(_tx, _ty, w, h);
            TQRect b = fix.intersect(ele);

            //kdDebug() <<" ele is " << ele << " b is " << b << " fix is " << fix << endl;
            sx+=b.x()-cx;
            sy+=b.y()-cy;
            cx=b.x();cy=b.y();cw=b.width();ch=b.height();
        }
        // restrict painting to repaint-clip
        if (cy < clipy) {
            ch -= (clipy - cy);
            sy += (clipy - cy);
            cy = clipy;
        }
        ch = kMin(ch, cliph);

//         kdDebug() << " clipy, cliph: " << clipy << ", " << cliph << endl;
//         kdDebug() << " drawTiledPixmap(" << cx << ", " << cy << ", " << cw << ", " << ch << ", " << sx << ", " << sy << ")" << endl;
        if (cw>0 && ch>0)
            p->drawTiledPixmap(cx, cy, cw, ch, bg->tiled_pixmap(c, scaledImageWidth, scaledImageHeight), sx, sy);

    }

    if (bgLayer->backgroundClip() != BGBORDER)
        p->restore(); // Undo the background clip

}

void RenderBox::outlineBox(TQPainter *p, int _tx, int _ty, const char *color)
{
    p->setPen(TQPen(TQColor(color), 1, Qt::DotLine));
    p->setBrush( Qt::NoBrush );
    p->drawRect(_tx, _ty, m_width, m_height);
}

TQRect RenderBox::getOverflowClipRect(int tx, int ty)
{
    // XXX When overflow-clip (CSS3) is implemented, we'll obtain the property
    // here.
    int bl=borderLeft(),bt=borderTop(),bb=borderBottom(),br=borderRight();
    int clipx = tx+bl;
    int clipy = ty+bt;
    int clipw = m_width-bl-br;
    int cliph = m_height-bt-bb+borderTopExtra()+borderBottomExtra();

    // Substract out scrollbars if we have them.
    if (m_layer) {
        clipw -= m_layer->verticalScrollbarWidth();
        cliph -= m_layer->horizontalScrollbarHeight();
    }

    return TQRect(clipx,clipy,clipw,cliph);
}

TQRect RenderBox::getClipRect(int tx, int ty)
{
    int bl=borderLeft(),bt=borderTop(),bb=borderBottom(),br=borderRight();
    // ### what about paddings?
    int clipw = m_width-bl-br;
    int cliph = m_height-bt-bb;

    bool rtl = (style()->direction() == RTL);

    int clipleft = 0;
    int clipright = clipw;
    int cliptop = 0;
    int clipbottom = cliph;

    if ( style()->hasClip() && style()->position() == ABSOLUTE ) {
	// the only case we use the clip property according to CSS 2.1
	if (!style()->clipLeft().isVariable()) {
	    int c = style()->clipLeft().width(clipw);
	    if ( rtl )
		clipleft = clipw - c;
	    else
		clipleft = c;
	}
	if (!style()->clipRight().isVariable()) {
	    int w = style()->clipRight().width(clipw);
	    if ( rtl ) {
		clipright = clipw - w;
	    } else {
		clipright = w;
	    }
	}
	if (!style()->clipTop().isVariable())
	    cliptop = style()->clipTop().width(cliph);
	if (!style()->clipBottom().isVariable())
	    clipbottom = style()->clipBottom().width(cliph);
    }
    int clipx = tx + clipleft;
    int clipy = ty + cliptop;
    clipw = clipright-clipleft;
    cliph = clipbottom-cliptop;

    //kdDebug( 6040 ) << "setting clip("<<clipx<<","<<clipy<<","<<clipw<<","<<cliph<<")"<<endl;

    return TQRect(clipx,clipy,clipw,cliph);
}

void RenderBox::close()
{
    setNeedsLayoutAndMinMaxRecalc();
}

short RenderBox::containingBlockWidth() const
{
    if (isCanvas() && canvas()->view())
    {
        if (canvas()->pagedMode())
            return canvas()->width();
        else
            return canvas()->view()->visibleWidth();
    }

    RenderBlock* cb = containingBlock();
    if (isRenderBlock() && cb->isTable() && static_cast<RenderTable*>(cb)->caption() == this) {
        //captions are not affected by table border or padding
        return cb->width();
    }
    if (usesLineWidth())
        return cb->lineWidth(m_y);
    else
        return cb->contentWidth();
}

bool RenderBox::absolutePosition(int &_xPos, int &_yPos, bool f) const
{
    if ( style()->position() == FIXED )
	f = true;
    RenderObject *o = container();
    if( o && o->absolutePosition(_xPos, _yPos, f))
    {
        if ( o->layer() ) {
            if (o->hasOverflowClip())
                o->layer()->subtractScrollOffset( _xPos, _yPos );
            if (isPositioned())
                o->layer()->checkInlineRelOffset(this, _xPos, _yPos);
        }

        if(!isInline() || isReplaced()) {
            _xPos += xPos(),
            _yPos += yPos();
        }

        if(isRelPositioned())
            relativePositionOffset(_xPos, _yPos);
        return true;
    }
    else
    {
        _xPos = 0;
        _yPos = 0;
        return false;
    }
}

void RenderBox::position(InlineBox* box, int /*from*/, int /*len*/, bool /*reverse*/)
{
    if (isPositioned()) {
        // Cache the x position only if we were an INLINE type originally.
        bool wasInline = style()->isOriginalDisplayInlineType();

        if (wasInline && hasStaticX()) {
            // The value is cached in the xPos of the box.  We only need this value if
            // our object was inline originally, since otherwise it would have ended up underneath
            // the inlines.
            m_staticX = box->xPos();
        }
        else if (!wasInline && hasStaticY()) {
            // Our object was a block originally, so we make our normal flow position be
            // just below the line box (as though all the inlines that came before us got
            // wrapped in an anonymous block, which is what would have happened had we been
            // in flow).  This value was cached in the yPos() of the box.
            m_staticY = box->yPos();
        }
    }
    else if (isReplaced())
        setPos( box->xPos(), box->yPos() );
}

void RenderBox::repaint(Priority prior)
{
    int ow = style() ? style()->outlineSize() : 0;
    if( isInline() && !isReplaced() )
    {
        RenderObject* p = parent();
        Q_ASSERT(p);
        while( p->isInline() && !p->isReplaced() )
            p = p->parent();
        int xoff = p->hasOverflowClip() ? 0 : p->overflowLeft();
        int yoff = p->hasOverflowClip() ? 0 : p->overflowTop();
        p->repaintRectangle( -ow + xoff, -ow + yoff, p->effectiveWidth()+ow*2, p->effectiveHeight()+ow*2, prior);
    }
    else
    {
        int xoff = hasOverflowClip() ? 0 : overflowLeft();
        int yoff = hasOverflowClip() ? 0 : overflowTop();
        repaintRectangle( -ow + xoff, -ow + yoff, effectiveWidth()+ow*2, effectiveHeight()+ow*2, prior);
    }
}

void RenderBox::repaintRectangle(int x, int y, int w, int h, Priority p, bool f)
{
    x += m_x;
    y += m_y;

    // Apply the relative position offset when invalidating a rectangle.  The layer
    // is translated, but the render box isn't, so we need to do this to get the
    // right dirty rect.  Since this is called from RenderObject::setStyle, the relative position
    // flag on the RenderObject has been cleared, so use the one on the style().
    if (style()->position() == RELATIVE && m_layer)
        relativePositionOffset(x,y);

    if (style()->position() == FIXED) f=true;

    // kdDebug( 6040 ) << "RenderBox(" <<this << ", " << renderName() << ")::repaintRectangle (" << x << "/" << y << ") (" << w << "/" << h << ")" << endl;
    RenderObject *o = container();
    if( o ) {
         if (o->layer()) {
             if (o->style()->hidesOverflow() && o->layer() && !o->isInlineFlow())
                 o->layer()->subtractScrollOffset(x,y); // For overflow:auto/scroll/hidden.
             if (style()->position() == ABSOLUTE)
                 o->layer()->checkInlineRelOffset(this,x,y);
        }
        o->repaintRectangle(x, y, w, h, p, f);
    }
}

void RenderBox::relativePositionOffset(int &tx, int &ty) const
{
    if(!style()->left().isVariable())
        tx += style()->left().width(containingBlockWidth());
    else if(!style()->right().isVariable())
        tx -= style()->right().width(containingBlockWidth());
    if(!style()->top().isVariable())
    {
        if (!style()->top().isPercent()
                || containingBlock()->style()->height().isFixed())
            ty += style()->top().width(containingBlockHeight());
    }
    else if(!style()->bottom().isVariable())
    {
        if (!style()->bottom().isPercent()
                || containingBlock()->style()->height().isFixed())
            ty -= style()->bottom().width(containingBlockHeight());
    }
}

void RenderBox::calcWidth()
{
#ifdef DEBUG_LAYOUT
    kdDebug( 6040 ) << "RenderBox("<<renderName()<<")::calcWidth()" << endl;
#endif
    if (isPositioned())
    {
        calcAbsoluteHorizontal();
    }
    else
    {
        bool treatAsReplaced = isReplaced() && !isInlineBlockOrInlineTable();
        Length w;
        if (treatAsReplaced)
            w = Length( calcReplacedWidth(), Fixed );
        else
            w = style()->width();

        Length ml = style()->marginLeft();
        Length mr = style()->marginRight();

	int cw = containingBlockWidth();
        if (cw<0) cw = 0;

        m_marginLeft = 0;
        m_marginRight = 0;

        if (isInline() && !isInlineBlockOrInlineTable())
        {
            // just calculate margins
            m_marginLeft = ml.minWidth(cw);
            m_marginRight = mr.minWidth(cw);
            if (treatAsReplaced)
            {
                m_width = calcBoxWidth(w.width(cw));
                m_width = KMAX(m_width, m_minWidth);
            }

            return;
        }
        else
        {
            LengthType widthType, minWidthType, maxWidthType;
            if (treatAsReplaced) {
                m_width = calcBoxWidth(w.width(cw));
                widthType = w.type();
            } else {
                m_width = calcWidthUsing(Width, cw, widthType);
                int minW = calcWidthUsing(MinWidth, cw, minWidthType);
                int maxW = style()->maxWidth().value() == UNDEFINED ?
                             m_width : calcWidthUsing(MaxWidth, cw, maxWidthType);

                if (m_width > maxW) {
                    m_width = maxW;
                    widthType = maxWidthType;
                }
                if (m_width < minW) {
                    m_width = minW;
                    widthType = minWidthType;
                }
            }

            if (widthType == Variable) {
    //          kdDebug( 6040 ) << "variable" << endl;
                m_marginLeft = ml.minWidth(cw);
                m_marginRight = mr.minWidth(cw);
            }
            else
            {
//              kdDebug( 6040 ) << "non-variable " << w.type << ","<< w.value << endl;
                calcHorizontalMargins(ml,mr,cw);
            }
        }

        if (cw && cw != m_width + m_marginLeft + m_marginRight && !isFloating() && !isInline())
        {
            if (containingBlock()->style()->direction()==LTR)
                m_marginRight = cw - m_width - m_marginLeft;
            else
                m_marginLeft = cw - m_width - m_marginRight;
        }
    }

#ifdef DEBUG_LAYOUT
    kdDebug( 6040 ) << "RenderBox::calcWidth(): m_width=" << m_width << " containingBlockWidth()=" << containingBlockWidth() << endl;
    kdDebug( 6040 ) << "m_marginLeft=" << m_marginLeft << " m_marginRight=" << m_marginRight << endl;
#endif
}

int RenderBox::calcWidthUsing(WidthType widthType, int cw, LengthType& lengthType)
{
    int width = m_width;
    Length w;
    if (widthType == Width)
        w = style()->width();
    else if (widthType == MinWidth)
        w = style()->minWidth();
    else
        w = style()->maxWidth();

    lengthType = w.type();

    if (lengthType == Variable) {
        int marginLeft = style()->marginLeft().minWidth(cw);
        int marginRight = style()->marginRight().minWidth(cw);
        if (cw) width = cw - marginLeft - marginRight;

        // size to max width?
        if (sizesToMaxWidth()) {
            width = KMAX(width, (int)m_minWidth);
            width = KMIN(width, (int)m_maxWidth);
        }
    }
    else
    {
        width = calcBoxWidth(w.width(cw));
    }

    return width;
}

void RenderBox::calcHorizontalMargins(const Length& ml, const Length& mr, int cw)
{
    if (isFloating() || isInline()) // Inline blocks/tables and floats don't have their margins increased.
    {
        m_marginLeft = ml.minWidth(cw);
        m_marginRight = mr.minWidth(cw);
    }
    else
    {
        if ( (ml.isVariable() && mr.isVariable() && m_width<cw) ||
             (!ml.isVariable() && !mr.isVariable() &&
                containingBlock()->style()->textAlign() == KHTML_CENTER) )
        {
            m_marginLeft = (cw - m_width)/2;
            if (m_marginLeft<0) m_marginLeft=0;
            m_marginRight = cw - m_width - m_marginLeft;
        }
        else if ( (mr.isVariable() && m_width<cw) ||
                 (!ml.isVariable() && containingBlock()->style()->direction() == RTL &&
                  containingBlock()->style()->textAlign() == KHTML_LEFT))
        {
            m_marginLeft = ml.width(cw);
            m_marginRight = cw - m_width - m_marginLeft;
        }
        else if ( (ml.isVariable() && m_width<cw) ||
                 (!mr.isVariable() && containingBlock()->style()->direction() == LTR &&
                  containingBlock()->style()->textAlign() == KHTML_RIGHT))
        {
            m_marginRight = mr.width(cw);
            m_marginLeft = cw - m_width - m_marginRight;
        }
        else
        {
           // this makes auto margins 0 if we failed a m_width<cw test above (css2.1, 10.3.3)
            m_marginLeft = ml.minWidth(cw);
            m_marginRight = mr.minWidth(cw);
        }
    }
}

void RenderBox::calcHeight()
{

#ifdef DEBUG_LAYOUT
    kdDebug( 6040 ) << "RenderBox::calcHeight()" << endl;
#endif

    //cell height is managed by table, inline elements do not have a height property.
    if ( isTableCell() || (isInline() && !isReplaced()) )
        return;

    if (isPositioned())
        calcAbsoluteVertical();
    else
    {
        calcVerticalMargins();

        // For tables, calculate margins only
        if (isTable())
            return;

        Length h;
        bool treatAsReplaced = isReplaced() && !isInlineBlockOrInlineTable();
        bool checkMinMaxHeight = false;

        if ( treatAsReplaced )
            h = Length( calcReplacedHeight(), Fixed );
        else {
            h = style()->height();
            checkMinMaxHeight = true;
        }

        int height;
        if (checkMinMaxHeight) {
            height = calcHeightUsing(style()->height());
            if (height == -1)
                height = m_height;
            int minH = calcHeightUsing(style()->minHeight()); // Leave as -1 if unset.
            int maxH = style()->maxHeight().value() == UNDEFINED ? height : calcHeightUsing(style()->maxHeight());
            if (maxH == -1)
                maxH = height;
            height = kMin(maxH, height);
            height = kMax(minH, height);
        }
        else {
            // The only times we don't check min/max height are when a fixed length has
            // been given as an override.  Just use that.
            height = calcBoxHeight(h.value());
        }

        if (height<m_height && !overhangingContents() && !hasOverflowClip())
            setOverhangingContents();

        m_height = height;
    }

    // Unfurling marquees override with the furled height.
    if (style()->overflowX() == OMARQUEE && m_layer && m_layer->marquee() &&
        m_layer->marquee()->isUnfurlMarquee() && !m_layer->marquee()->isHorizontal()) {
        m_layer->marquee()->setEnd(m_height);
        m_height = kMin(m_height, m_layer->marquee()->unfurlPos());
    }

}

int RenderBox::calcHeightUsing(const Length& h)
{
    int height = -1;
    if (!h.isVariable()) {
        if (h.isFixed())
            height = h.value();
        else if (h.isPercent())
            height = calcPercentageHeight(h);
        if (height != -1) {
            height = calcBoxHeight(height);
            return height;
        }
    }
    return height;
}

int RenderBox::calcImplicitHeight() const {
    assert(hasImplicitHeight());

    RenderBlock* cb = containingBlock();
    // padding-box height
    int ch = cb->height() - cb->borderTop() + cb->borderBottom();
    int top = style()->top().width(ch);
    int bottom = style()->bottom().width(ch);

    return ch - top - bottom;
}

int RenderBox::calcPercentageHeight(const Length& height, bool treatAsReplaced) const
{
    int result = -1;
    RenderBlock* cb = containingBlock();
    // In quirk mode, table cells violate what the CSS spec says to do with heights.
    if (cb->isTableCell() && style()->htmlHacks()) {
        result = static_cast<RenderTableCell*>(cb)->cellPercentageHeight();
    }

    // Otherwise we only use our percentage height if our containing block had a specified
    // height.
    else if (cb->style()->height().isFixed())
        result = cb->calcContentHeight(cb->style()->height().value());
    else if (cb->style()->height().isPercent()) {
        // We need to recur and compute the percentage height for our containing block.
        result = cb->calcPercentageHeight(cb->style()->height(), treatAsReplaced);
        if (result != -1)
            result = cb->calcContentHeight(result);
    }
    else if (cb->isCanvas()) {
        if (!canvas()->pagedMode())
            result = static_cast<RenderCanvas*>(cb)->viewportHeight();
        else
            result = static_cast<RenderCanvas*>(cb)->height();
        result -= cb->style()->borderTopWidth() - cb->style()->borderBottomWidth();
        result -= cb->paddingTop() + cb->paddingBottom();
    }
    else if (cb->isBody() && style()->htmlHacks() &&
                             cb->style()->height().isVariable() && !cb->isFloatingOrPositioned()) {
        int margins = cb->collapsedMarginTop() + cb->collapsedMarginBottom();
        int visHeight = canvas()->viewportHeight();
        RenderObject* p = cb->parent();
        result = visHeight - (margins + p->marginTop() + p->marginBottom() +
                              p->borderTop() + p->borderBottom() +
                              p->paddingTop() + p->paddingBottom());
    }
    else if (cb->isRoot() && style()->htmlHacks() && cb->style()->height().isVariable()) {
        int visHeight = canvas()->viewportHeight();
        result = visHeight - (marginTop() + marginBottom() +
                              borderTop() + borderBottom() +
                              paddingTop() + paddingBottom());
    }
    else if (cb->isAnonymousBlock() || treatAsReplaced && style()->htmlHacks()) {
        // IE quirk.
        result = cb->calcPercentageHeight(cb->style()->height(), treatAsReplaced);
    }
    else if (cb->hasImplicitHeight()) {
        result = cb->calcImplicitHeight();
    }

    if (result != -1) {
        result = height.width(result);
        if (cb->isTableCell() && style()->boxSizing() != BORDER_BOX) {
            result -= (borderTop() + paddingTop() + borderBottom() + paddingBottom());
            result = kMax(0, result);
        }
    }
    return result;
}

short RenderBox::calcReplacedWidth() const
{
    int width = calcReplacedWidthUsing(Width);
    int minW = calcReplacedWidthUsing(MinWidth);
    int maxW = style()->maxWidth().value() == UNDEFINED ? width : calcReplacedWidthUsing(MaxWidth);

    if (width > maxW)
        width = maxW;

    if (width < minW)
        width = minW;

    return width;
}

int RenderBox::calcReplacedWidthUsing(WidthType widthType) const
{
    Length w;
    if (widthType == Width)
        w = style()->width();
    else if (widthType == MinWidth)
        w = style()->minWidth();
    else
        w = style()->maxWidth();

    switch (w.type()) {
    case Fixed:
        return w.value();
    case Percent:
    {
        const int cw = containingBlockWidth();
        if (cw > 0) {
            int result = w.minWidth(cw);
            return result;
        }
    }
    // fall through
    default:
        return intrinsicWidth();
    }
}

int RenderBox::calcReplacedHeight() const
{
    int height = calcReplacedHeightUsing(Height);
    int minH = calcReplacedHeightUsing(MinHeight);
    int maxH = style()->maxHeight().value() == UNDEFINED ? height : calcReplacedHeightUsing(MaxHeight);

    if (height > maxH)
        height = maxH;

    if (height < minH)
        height = minH;

    return height;
}

int RenderBox::calcReplacedHeightUsing(HeightType heightType) const
{
    Length h;
    if (heightType == Height)
        h = style()->height();
    else if (heightType == MinHeight)
        h = style()->minHeight();
    else
        h = style()->maxHeight();
    switch( h.type() ) {
    case Fixed:
        return h.value();
    case Percent:
      {
        int th = calcPercentageHeight(h, true);
        if (th != -1)
            return th;
        // fall through
      }
    default:
        return intrinsicHeight();
    };
}

int RenderBox::availableHeight() const
{
    return availableHeightUsing(style()->height());
}

int RenderBox::availableHeightUsing(const Length& h) const
{
    if (h.isFixed())
        return calcContentHeight(h.value());

    if (isCanvas())
        if (static_cast<const RenderCanvas*>(this)->pagedMode())
            return static_cast<const RenderCanvas*>(this)->pageHeight();
        else
            return static_cast<const RenderCanvas*>(this)->viewportHeight();

    // We need to stop here, since we don't want to increase the height of the table
    // artificially.  We're going to rely on this cell getting expanded to some new
    // height, and then when we lay out again we'll use the calculation below.
    if (isTableCell() && (h.isVariable() || h.isPercent())) {
        const RenderTableCell* tableCell = static_cast<const RenderTableCell*>(this);
        return tableCell->cellPercentageHeight() -
	    (borderTop()+borderBottom()+paddingTop()+paddingBottom());
    }

    if (h.isPercent())
       return calcContentHeight(h.width(containingBlock()->availableHeight()));

    // Check for implicit height
    if (hasImplicitHeight())
        return calcImplicitHeight();

    return containingBlock()->availableHeight();
}

int RenderBox::availableWidth() const
{
    return availableWidthUsing(style()->width());
}

int RenderBox::availableWidthUsing(const Length& w) const
{
    if (w.isFixed())
        return calcContentWidth(w.value());

    if (isCanvas())
        return static_cast<const RenderCanvas*>(this)->viewportWidth();

    if (w.isPercent())
       return calcContentWidth(w.width(containingBlock()->availableWidth()));

    return containingBlock()->availableWidth();
}

void RenderBox::calcVerticalMargins()
{
    if( isTableCell() ) {
	// table margins are basically infinite
	m_marginTop = TABLECELLMARGIN;
	m_marginBottom = TABLECELLMARGIN;
	return;
    }

    Length tm = style()->marginTop();
    Length bm = style()->marginBottom();

    // margins are calculated with respect to the _width_ of
    // the containing block (8.3)
    int cw = containingBlock()->contentWidth();

    m_marginTop = tm.minWidth(cw);
    m_marginBottom = bm.minWidth(cw);
}

void RenderBox::setStaticX(short staticX)
{
    m_staticX = staticX;
}

void RenderBox::setStaticY(int staticY)
{
    m_staticY = staticY;
}

void RenderBox::calcAbsoluteHorizontal()
{
   if (isReplaced()) {
        calcAbsoluteHorizontalReplaced();
        return;
    }

    // QUESTIONS
    // FIXME 1: Which RenderObject's 'direction' property should used: the
    // containing block (cb) as the spec seems to imply, the parent (parent()) as
    // was previously done in calculating the static distances, or ourself, which
    // was also previously done for deciding what to override when you had
    // over-constrained margins?  Also note that the container block is used
    // in similar situations in other parts of the RenderBox class (see calcWidth()
    // and calcHorizontalMargins()). For now we are using the parent for quirks
    // mode and the containing block for strict mode.

    // FIXME 2: Can perhaps optimize out cases when max-width/min-width are greater
    // than or less than the computed m_width.  Be careful of box-sizing and
    // percentage issues.

    // The following is based off of the W3C Working Draft from April 11, 2006 of
    // CSS 2.1: Section 10.3.7 "Absolutely positioned, non-replaced elements"
    // <http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width>
    // (block-style-comments in this function and in calcAbsoluteHorizontalValues()
    // correspond to text from the spec)


    // We don't use containingBlock(), since we may be positioned by an enclosing
    // relative positioned inline.
    const RenderObject* containerBlock = container();

    // FIXME: This is incorrect for cases where the container block is a relatively
    // positioned inline.
    const int containerWidth = containingBlockWidth() + containerBlock->paddingLeft() + containerBlock->paddingRight();

    // To match WinIE, in quirks mode use the parent's 'direction' property
    // instead of the the container block's.
    EDirection containerDirection = (style()->htmlHacks()) ? parent()->style()->direction() : containerBlock->style()->direction();

    const int bordersPlusPadding = borderLeft() + borderRight() + paddingLeft() + paddingRight();
    const Length marginLeft = style()->marginLeft();
    const Length marginRight = style()->marginRight();
    Length left = style()->left();
    Length right = style()->right();

    /*---------------------------------------------------------------------------*\
     * For the purposes of this section and the next, the term "static position"
     * (of an element) refers, roughly, to the position an element would have had
     * in the normal flow. More precisely:
     *
     * * The static position for 'left' is the distance from the left edge of the
     *   containing block to the left margin edge of a hypothetical box that would
     *   have been the first box of the element if its 'position' property had
     *   been 'static' and 'float' had been 'none'. The value is negative if the
     *   hypothetical box is to the left of the containing block.
     * * The static position for 'right' is the distance from the right edge of the
     *   containing block to the right margin edge of the same hypothetical box as
     *   above. The value is positive if the hypothetical box is to the left of the
     *   containing block's edge.
     *
     * But rather than actually calculating the dimensions of that hypothetical box,
     * user agents are free to make a guess at its probable position.
     *
     * For the purposes of calculating the static position, the containing block of
     * fixed positioned elements is the initial containing block instead of the
     * viewport, and all scrollable boxes should be assumed to be scrolled to their
     * origin.
    \*---------------------------------------------------------------------------*/

    // Calculate the static distance if needed.
    if (left.isVariable() && right.isVariable()) {
        if (containerDirection == LTR) {
            // 'm_staticX' should already have been set through layout of the parent.
            int staticPosition = m_staticX - containerBlock->borderLeft();
            for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent())
                staticPosition += po->xPos();
            left = Length(staticPosition, Fixed);
        } else {
            RenderObject* po = parent();
            // 'm_staticX' should already have been set through layout of the parent.
            int staticPosition = m_staticX + containerWidth + containerBlock->borderRight() - po->width();
            for (; po && po != containerBlock; po = po->parent())
                staticPosition -= po->xPos();
            right = Length(staticPosition, Fixed);
        }
    }

    // Calculate constraint equation values for 'width' case.
    calcAbsoluteHorizontalValues(style()->width(), containerBlock, containerDirection,
                                 containerWidth, bordersPlusPadding,
                                 left, right, marginLeft, marginRight,
                                 m_width, m_marginLeft, m_marginRight, m_x);
    // Calculate constraint equation values for 'max-width' case.calcContentWidth(width.width(containerWidth));
    if (style()->maxWidth().value() != UNDEFINED) {
        short maxWidth;
        short maxMarginLeft;
        short maxMarginRight;
        short maxXPos;

        calcAbsoluteHorizontalValues(style()->maxWidth(), containerBlock, containerDirection,
                                     containerWidth, bordersPlusPadding,
                                     left, right, marginLeft, marginRight,
                                     maxWidth, maxMarginLeft, maxMarginRight, maxXPos);

        if (m_width > maxWidth) {
            m_width = maxWidth;
            m_marginLeft = maxMarginLeft;
            m_marginRight = maxMarginRight;
            m_x = maxXPos;
        }
    }

    // Calculate constraint equation values for 'min-width' case.
    if (style()->minWidth().value()) {
        short minWidth;
        short minMarginLeft;
        short minMarginRight;
        short minXPos;

        calcAbsoluteHorizontalValues(style()->minWidth(), containerBlock, containerDirection,
                                     containerWidth, bordersPlusPadding,
                                     left, right, marginLeft, marginRight,
                                     minWidth, minMarginLeft, minMarginRight, minXPos);

        if (m_width < minWidth) {
            m_width = minWidth;
            m_marginLeft = minMarginLeft;
            m_marginRight = minMarginRight;
            m_x = minXPos;
        }
    }

    // Put m_width into correct form.
    m_width += bordersPlusPadding;
}

void RenderBox::calcAbsoluteHorizontalValues(Length width, const RenderObject* containerBlock, EDirection containerDirection,
                                             const int containerWidth, const int bordersPlusPadding,
                                             const Length left, const Length right, const Length marginLeft, const Length marginRight,
                                             short& widthValue, short& marginLeftValue, short& marginRightValue, short& xPos)
{
    // 'left' and 'right' cannot both be 'auto' because one would of been
    // converted to the static postion already
    assert(!(left.isVariable() && right.isVariable()));

    int leftValue = 0;

    bool widthIsAuto = width.isVariable();
    bool leftIsAuto = left.isVariable();
    bool rightIsAuto = right.isVariable();

    if (!leftIsAuto && !widthIsAuto && !rightIsAuto) {
        /*-----------------------------------------------------------------------*\
         * If none of the three is 'auto': If both 'margin-left' and 'margin-
         * right' are 'auto', solve the equation under the extra constraint that
         * the two margins get equal values, unless this would make them negative,
         * in which case when direction of the containing block is 'ltr' ('rtl'),
         * set 'margin-left' ('margin-right') to zero and solve for 'margin-right'
         * ('margin-left'). If one of 'margin-left' or 'margin-right' is 'auto',
         * solve the equation for that value. If the values are over-constrained,
         * ignore the value for 'left' (in case the 'direction' property of the
         * containing block is 'rtl') or 'right' (in case 'direction' is 'ltr')
         * and solve for that value.
        \*-----------------------------------------------------------------------*/
        // NOTE:  It is not necessary to solve for 'right' in the over constrained
        // case because the value is not used for any further calculations.

        leftValue = left.width(containerWidth);
        widthValue = calcContentWidth(width.width(containerWidth));

        const int availableSpace = containerWidth - (leftValue + widthValue + right.width(containerWidth) + bordersPlusPadding);

        // Margins are now the only unknown
        if (marginLeft.isVariable() && marginRight.isVariable()) {
            // Both margins auto, solve for equality
            if (availableSpace >= 0) {
                marginLeftValue = availableSpace / 2; // split the diference
                marginRightValue = availableSpace - marginLeftValue;  // account for odd valued differences
            } else {
                // see FIXME 1
                if (containerDirection == LTR) {
                    marginLeftValue = 0;
                    marginRightValue = availableSpace; // will be negative
                } else {
                    marginLeftValue = availableSpace; // will be negative
                    marginRightValue = 0;
                }
            }
        } else if (marginLeft.isVariable()) {
            // Solve for left margin
            marginRightValue = marginRight.width(containerWidth);
            marginLeftValue = availableSpace - marginRightValue;
        } else if (marginRight.isVariable()) {
            // Solve for right margin
            marginLeftValue = marginLeft.width(containerWidth);
            marginRightValue = availableSpace - marginLeftValue;
        } else {
            // Over-constrained, solve for left if direction is RTL
            marginLeftValue = marginLeft.width(containerWidth);
            marginRightValue = marginRight.width(containerWidth);

            // see FIXME 1 -- used to be "this->style()->direction()"
            if (containerDirection == RTL)
                leftValue = (availableSpace + leftValue) - marginLeftValue - marginRightValue;
        }
    } else {
        /*--------------------------------------------------------------------*\
         * Otherwise, set 'auto' values for 'margin-left' and 'margin-right'
         * to 0, and pick the one of the following six rules that applies.
         *
         * 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the
         *    width is shrink-to-fit. Then solve for 'left'
         *
         *              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
         * ------------------------------------------------------------------
         * 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if
         *    the 'direction' property of the containing block is 'ltr' set
         *    'left' to the static position, otherwise set 'right' to the
         *    static position. Then solve for 'left' (if 'direction is 'rtl')
         *    or 'right' (if 'direction' is 'ltr').
         * ------------------------------------------------------------------
         *
         * 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the
         *    width is shrink-to-fit . Then solve for 'right'
         * 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve
         *    for 'left'
         * 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve
         *    for 'width'
         * 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve
         *    for 'right'
         *
         * Calculation of the shrink-to-fit width is similar to calculating the
         * width of a table cell using the automatic table layout algorithm.
         * Roughly: calculate the preferred width by formatting the content
         * without breaking lines other than where explicit line breaks occur,
         * and also calculate the preferred minimum width, e.g., by trying all
         * possible line breaks. CSS 2.1 does not define the exact algorithm.
         * Thirdly, calculate the available width: this is found by solving
         * for 'width' after setting 'left' (in case 1) or 'right' (in case 3)
         * to 0.
         *
         * Then the shrink-to-fit width is:
         * kMin(kMax(preferred minimum width, available width), preferred width).
        \*--------------------------------------------------------------------*/
        // NOTE: For rules 3 and 6 it is not necessary to solve for 'right'
        // because the value is not used for any further calculations.

        // Calculate margins, 'auto' margins are ignored.
        marginLeftValue = marginLeft.minWidth(containerWidth);
        marginRightValue = marginRight.minWidth(containerWidth);

        const int availableSpace = containerWidth - (marginLeftValue + marginRightValue + bordersPlusPadding);

        // FIXME: Is there a faster way to find the correct case?
        // Use rule/case that applies.
        if (leftIsAuto && widthIsAuto && !rightIsAuto) {
            // RULE 1: (use shrink-to-fit for width, and solve of left)
            int rightValue = right.width(containerWidth);

            // FIXME: would it be better to have shrink-to-fit in one step?
            int preferredWidth = m_maxWidth - bordersPlusPadding;
            int preferredMinWidth = m_minWidth - bordersPlusPadding;
            int availableWidth = availableSpace - rightValue;
            widthValue = kMin(kMax(preferredMinWidth, availableWidth), preferredWidth);
            leftValue = availableSpace - (widthValue + rightValue);
        } else if (!leftIsAuto && widthIsAuto && rightIsAuto) {
            // RULE 3: (use shrink-to-fit for width, and no need solve of right)
            leftValue = left.width(containerWidth);

            // FIXME: would it be better to have shrink-to-fit in one step?
            int preferredWidth = m_maxWidth - bordersPlusPadding;
            int preferredMinWidth = m_minWidth - bordersPlusPadding;
            int availableWidth = availableSpace - leftValue;
            widthValue = kMin(kMax(preferredMinWidth, availableWidth), preferredWidth);
        } else if (leftIsAuto && !width.isVariable() && !rightIsAuto) {
            // RULE 4: (solve for left)
            widthValue = calcContentWidth(width.width(containerWidth));
            leftValue = availableSpace - (widthValue + right.width(containerWidth));
        } else if (!leftIsAuto && widthIsAuto && !rightIsAuto) {
            // RULE 5: (solve for width)
            leftValue = left.width(containerWidth);
            widthValue = availableSpace - (leftValue + right.width(containerWidth));
        } else if (!leftIsAuto&& !widthIsAuto && rightIsAuto) {
            // RULE 6: (no need solve for right)
            leftValue = left.width(containerWidth);
            widthValue = calcContentWidth(width.width(containerWidth));
        }
    }

    // Use computed values to calculate the horizontal position.
    xPos = leftValue + marginLeftValue + containerBlock->borderLeft();
}


void RenderBox::calcAbsoluteVertical()
{
    if (isReplaced()) {
        calcAbsoluteVerticalReplaced();
        return;
    }

    // The following is based off of the W3C Working Draft from April 11, 2006 of
    // CSS 2.1: Section 10.6.4 "Absolutely positioned, non-replaced elements"
    // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-non-replaced-height>
    // (block-style-comments in this function and in calcAbsoluteVerticalValues()
    // correspond to text from the spec)


    // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
    const RenderObject* containerBlock = container();
    const int containerHeight = containerBlock->height() - containerBlock->borderTop() - containerBlock->borderBottom();

    const int bordersPlusPadding = borderTop() + borderBottom() + paddingTop() + paddingBottom();
    const Length marginTop = style()->marginTop();
    const Length marginBottom = style()->marginBottom();
    Length top = style()->top();
    Length bottom = style()->bottom();

    /*---------------------------------------------------------------------------*\
     * For the purposes of this section and the next, the term "static position"
     * (of an element) refers, roughly, to the position an element would have had
     * in the normal flow. More precisely, the static position for 'top' is the
     * distance from the top edge of the containing block to the top margin edge
     * of a hypothetical box that would have been the first box of the element if
     * its 'position' property had been 'static' and 'float' had been 'none'. The
     * value is negative if the hypothetical box is above the containing block.
     *
     * But rather than actually calculating the dimensions of that hypothetical
     * box, user agents are free to make a guess at its probable position.
     *
     * For the purposes of calculating the static position, the containing block
     * of fixed positioned elements is the initial containing block instead of
     * the viewport.
    \*---------------------------------------------------------------------------*/

    // Calculate the static distance if needed.
    if (top.isVariable() && bottom.isVariable()) {
        // m_staticY should already have been set through layout of the parent()
        int staticTop = m_staticY - containerBlock->borderTop();
        for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) {
            staticTop += po->yPos();
        }
        top.setValue(Fixed, staticTop);
    }


    int height; // Needed to compute overflow.

    // Calculate constraint equation values for 'height' case.
    calcAbsoluteVerticalValues(style()->height(), containerBlock, containerHeight, bordersPlusPadding,
                               top, bottom, marginTop, marginBottom,
                               height, m_marginTop, m_marginBottom, m_y);

    // Avoid doing any work in the common case (where the values of min-height and max-height are their defaults).
    // see FIXME 2

    // Calculate constraint equation values for 'max-height' case.
    if (style()->maxHeight().value() != UNDEFINED) {
        int maxHeight;
        short maxMarginTop;
        short maxMarginBottom;
        int maxYPos;

        calcAbsoluteVerticalValues(style()->maxHeight(), containerBlock, containerHeight, bordersPlusPadding,
                                   top, bottom, marginTop, marginBottom,
                                   maxHeight, maxMarginTop, maxMarginBottom, maxYPos);

        if (height > maxHeight) {
            height = maxHeight;
            m_marginTop = maxMarginTop;
            m_marginBottom = maxMarginBottom;
            m_y = maxYPos;
        }
    }

    // Calculate constraint equation values for 'min-height' case.
    if (style()->minHeight().value()) {
        int minHeight;
        short minMarginTop;
        short minMarginBottom;
        int minYPos;

        calcAbsoluteVerticalValues(style()->minHeight(), containerBlock, containerHeight, bordersPlusPadding,
                                   top, bottom, marginTop, marginBottom,
                                   minHeight, minMarginTop, minMarginBottom, minYPos);

        if (height < minHeight) {
            height = minHeight;
            m_marginTop = minMarginTop;
            m_marginBottom = minMarginBottom;
            m_y = minYPos;
        }
    }

    height += bordersPlusPadding;

    // Set final height value.
    m_height = height;
}

void RenderBox::calcAbsoluteVerticalValues(Length height, const RenderObject* containerBlock,
                                           const int containerHeight, const int bordersPlusPadding,
                                           const Length top, const Length bottom, const Length marginTop, const Length marginBottom,
                                           int& heightValue, short& marginTopValue, short& marginBottomValue, int& yPos)
{
    // 'top' and 'bottom' cannot both be 'auto' because 'top would of been
    // converted to the static position in calcAbsoluteVertical()
    assert(!(top.isVariable() && bottom.isVariable()));

    int contentHeight = m_height - bordersPlusPadding;

    int topValue = 0;

    bool heightIsAuto = height.isVariable();
    bool topIsAuto = top.isVariable();
    bool bottomIsAuto = bottom.isVariable();

    if (isTable() && heightIsAuto) {
         // Height is never unsolved for tables. "auto" means shrink to fit.
         // Use our height instead.
        heightValue = contentHeight;
        heightIsAuto = false;
    } else if (!heightIsAuto) {
        heightValue = calcContentHeight(height.width(containerHeight));
        if (contentHeight > heightValue) {
            if (!isTable())
                contentHeight = heightValue;
            else
                heightValue = contentHeight;
        }
    }


    if (!topIsAuto && !heightIsAuto && !bottomIsAuto) {
        /*-----------------------------------------------------------------------*\
         * If none of the three are 'auto': If both 'margin-top' and 'margin-
         * bottom' are 'auto', solve the equation under the extra constraint that
         * the two margins get equal values. If one of 'margin-top' or 'margin-
         * bottom' is 'auto', solve the equation for that value. If the values
         * are over-constrained, ignore the value for 'bottom' and solve for that
         * value.
        \*-----------------------------------------------------------------------*/
        // NOTE:  It is not necessary to solve for 'bottom' in the over constrained
        // case because the value is not used for any further calculations.

        topValue = top.width(containerHeight);

        const int availableSpace = containerHeight - (topValue + heightValue + bottom.width(containerHeight) + bordersPlusPadding);

        // Margins are now the only unknown
        if (marginTop.isVariable() && marginBottom.isVariable()) {
            // Both margins auto, solve for equality
            // NOTE: This may result in negative values.
            marginTopValue = availableSpace / 2; // split the diference
            marginBottomValue = availableSpace - marginTopValue; // account for odd valued differences
        } else if (marginTop.isVariable()) {
            // Solve for top margin
            marginBottomValue = marginBottom.width(containerHeight);
            marginTopValue = availableSpace - marginBottomValue;
        } else if (marginBottom.isVariable()) {
            // Solve for bottom margin
            marginTopValue = marginTop.width(containerHeight);
            marginBottomValue = availableSpace - marginTopValue;
        } else {
            // Over-constrained, (no need solve for bottom)
            marginTopValue = marginTop.width(containerHeight);
            marginBottomValue = marginBottom.width(containerHeight);
        }
    } else {
        /*--------------------------------------------------------------------*\
         * Otherwise, set 'auto' values for 'margin-top' and 'margin-bottom'
         * to 0, and pick the one of the following six rules that applies.
         *
         * 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then
         *    the height is based on the content, and solve for 'top'.
         *
         *              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
         * ------------------------------------------------------------------
         * 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then
         *    set 'top' to the static position, and solve for 'bottom'.
         * ------------------------------------------------------------------
         *
         * 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then
         *    the height is based on the content, and solve for 'bottom'.
         * 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', and
         *    solve for 'top'.
         * 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', and
         *    solve for 'height'.
         * 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', and
         *    solve for 'bottom'.
        \*--------------------------------------------------------------------*/
        // NOTE: For rules 3 and 6 it is not necessary to solve for 'bottom'
        // because the value is not used for any further calculations.

        // Calculate margins, 'auto' margins are ignored.
        marginTopValue = marginTop.minWidth(containerHeight);
        marginBottomValue = marginBottom.minWidth(containerHeight);

        const int availableSpace = containerHeight - (marginTopValue + marginBottomValue + bordersPlusPadding);

        // Use rule/case that applies.
        if (topIsAuto && heightIsAuto && !bottomIsAuto) {
            // RULE 1: (height is content based, solve of top)
            heightValue = contentHeight;
            topValue = availableSpace - (heightValue + bottom.width(containerHeight));
        }
        else if (topIsAuto && !heightIsAuto && bottomIsAuto) {
            // RULE 2: (shouldn't happen)
        }
        else if (!topIsAuto && heightIsAuto && bottomIsAuto) {
            // RULE 3: (height is content based, no need solve of bottom)
            heightValue = contentHeight;
            topValue = top.width(containerHeight);
        } else if (topIsAuto && !heightIsAuto && !bottomIsAuto) {
            // RULE 4: (solve of top)
            topValue = availableSpace - (heightValue + bottom.width(containerHeight));
        } else if (!topIsAuto && heightIsAuto && !bottomIsAuto) {
            // RULE 5: (solve of height)
            topValue = top.width(containerHeight);
            heightValue = kMax(0, availableSpace - (topValue + bottom.width(containerHeight)));
        } else if (!topIsAuto && !heightIsAuto && bottomIsAuto) {
            // RULE 6: (no need solve of bottom)
            topValue = top.width(containerHeight);
        }
    }

    // Use computed values to calculate the vertical position.
    yPos = topValue + marginTopValue + containerBlock->borderTop();
}

void RenderBox::calcAbsoluteHorizontalReplaced()
{
    // The following is based off of the W3C Working Draft from April 11, 2006 of
    // CSS 2.1: Section 10.3.8 "Absolutly positioned, replaced elements"
    // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-width>
    // (block-style-comments in this function correspond to text from the spec and
    // the numbers correspond to numbers in spec)

    // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
    const RenderObject* containerBlock = container();

    // FIXME: This is incorrect for cases where the container block is a relatively
    // positioned inline.
    const int containerWidth = containingBlockWidth() + containerBlock->paddingLeft() + containerBlock->paddingRight();

    // To match WinIE, in quirks mode use the parent's 'direction' property
    // instead of the the container block's.
    EDirection containerDirection = (style()->htmlHacks()) ? parent()->style()->direction() : containerBlock->style()->direction();

    // Variables to solve.
    Length left = style()->left();
    Length right = style()->right();
    Length marginLeft = style()->marginLeft();
    Length marginRight = style()->marginRight();


    /*-----------------------------------------------------------------------*\
     * 1. The used value of 'width' is determined as for inline replaced
     *    elements.
    \*-----------------------------------------------------------------------*/
    // NOTE: This value of width is FINAL in that the min/max width calculations
    // are dealt with in calcReplacedWidth().  This means that the steps to produce
    // correct max/min in the non-replaced version, are not necessary.
    m_width = calcReplacedWidth() + borderLeft() + borderRight() + paddingLeft() + paddingRight();
    const int availableSpace = containerWidth - m_width;

    /*-----------------------------------------------------------------------*\
     * 2. If both 'left' and 'right' have the value 'auto', then if 'direction'
     *    of the containing block is 'ltr', set 'left' to the static position;
     *    else if 'direction' is 'rtl', set 'right' to the static position.
    \*-----------------------------------------------------------------------*/
    if (left.isVariable() && right.isVariable()) {
        // see FIXME 1
        if (containerDirection == LTR) {
            // 'm_staticX' should already have been set through layout of the parent.
            int staticPosition = m_staticX - containerBlock->borderLeft();
            for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent())
                staticPosition += po->xPos();
            left.setValue(Fixed, staticPosition);
        } else {
            RenderObject* po = parent();
            // 'm_staticX' should already have been set through layout of the parent.
            int staticPosition = m_staticX + containerWidth + containerBlock->borderRight() - po->width();
            for (; po && po != containerBlock; po = po->parent())
                staticPosition -= po->xPos();
            right.setValue(Fixed, staticPosition);
        }
    }

    /*-----------------------------------------------------------------------*\
     * 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left'
     *    or 'margin-right' with '0'.
    \*-----------------------------------------------------------------------*/
    if (left.isVariable() || right.isVariable()) {
        if (marginLeft.isVariable())
            marginLeft.setValue(Fixed, 0);
        if (marginRight.isVariable())
            marginRight.setValue(Fixed, 0);
    }

    /*-----------------------------------------------------------------------*\
     * 4. If at this point both 'margin-left' and 'margin-right' are still
     *    'auto', solve the equation under the extra constraint that the two
     *    margins must get equal values, unless this would make them negative,
     *    in which case when the direction of the containing block is 'ltr'
     *    ('rtl'), set 'margin-left' ('margin-right') to zero and solve for
     *    'margin-right' ('margin-left').
    \*-----------------------------------------------------------------------*/
    int leftValue = 0;
    int rightValue = 0;

    if (marginLeft.isVariable() && marginRight.isVariable()) {
        // 'left' and 'right' cannot be 'auto' due to step 3
        assert(!(left.isVariable() && right.isVariable()));

        leftValue = left.width(containerWidth);
        rightValue = right.width(containerWidth);

        int difference = availableSpace - (leftValue + rightValue);
        if (difference > 0) {
            m_marginLeft = difference / 2; // split the diference
            m_marginRight = difference - m_marginLeft; // account for odd valued differences
        } else {
            // see FIXME 1
            if (containerDirection == LTR) {
                m_marginLeft = 0;
                m_marginRight = difference;  // will be negative
            } else {
                m_marginLeft = difference;  // will be negative
                m_marginRight = 0;
            }
        }

    /*-----------------------------------------------------------------------*\
     * 5. If at this point there is an 'auto' left, solve the equation for
     *    that value.
    \*-----------------------------------------------------------------------*/
    } else if (left.isVariable()) {
        m_marginLeft = marginLeft.width(containerWidth);
        m_marginRight = marginRight.width(containerWidth);
        rightValue = right.width(containerWidth);

        // Solve for 'left'
        leftValue = availableSpace - (rightValue + m_marginLeft + m_marginRight);
    } else if (right.isVariable()) {
        m_marginLeft = marginLeft.width(containerWidth);
        m_marginRight = marginRight.width(containerWidth);
        leftValue = left.width(containerWidth);

        // Solve for 'right'
        rightValue = availableSpace - (leftValue + m_marginLeft + m_marginRight);
    } else if (marginLeft.isVariable()) {
        m_marginRight = marginRight.width(containerWidth);
        leftValue = left.width(containerWidth);
        rightValue = right.width(containerWidth);

        // Solve for 'margin-left'
        m_marginLeft = availableSpace - (leftValue + rightValue + m_marginRight);
    } else if (marginRight.isVariable()) {
        m_marginLeft = marginLeft.width(containerWidth);
        leftValue = left.width(containerWidth);
        rightValue = right.width(containerWidth);

        // Solve for 'margin-right'
        m_marginRight = availableSpace - (leftValue + rightValue + m_marginLeft);
    }

    /*-----------------------------------------------------------------------*\
     * 6. If at this point the values are over-constrained, ignore the value
     *    for either 'left' (in case the 'direction' property of the
     *    containing block is 'rtl') or 'right' (in case 'direction' is
     *    'ltr') and solve for that value.
    \*-----------------------------------------------------------------------*/
    else  {
        m_marginLeft = marginLeft.width(containerWidth);
        m_marginRight = marginRight.width(containerWidth);
        if (containerDirection  == LTR) {
            leftValue = left.width(containerWidth);
            rightValue = availableSpace - (leftValue + m_marginLeft + m_marginRight);
        }
        else {
            rightValue = right.width(containerWidth);
            leftValue = availableSpace - (rightValue + m_marginLeft + m_marginRight);
        }
    }

    int totalWidth = m_width + leftValue + rightValue +  m_marginLeft + m_marginRight;
    if (totalWidth > containerWidth && (containerDirection == RTL))
        leftValue = containerWidth - (totalWidth - leftValue);

    // Use computed values to calculate the horizontal position.
    m_x = leftValue + m_marginLeft + containerBlock->borderLeft();
}

void RenderBox::calcAbsoluteVerticalReplaced()
{
    // The following is based off of the W3C Working Draft from April 11, 2006 of
    // CSS 2.1: Section 10.6.5 "Absolutly positioned, replaced elements"
    // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-height>
    // (block-style-comments in this function correspond to text from the spec and
    // the numbers correspond to numbers in spec)

    // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
    const RenderObject* containerBlock = container();
    const int containerHeight = containerBlock->height() - containerBlock->borderTop() - containerBlock->borderBottom();

    // Variables to solve.
    Length top = style()->top();
    Length bottom = style()->bottom();
    Length marginTop = style()->marginTop();
    Length marginBottom = style()->marginBottom();


    /*-----------------------------------------------------------------------*\
     * 1. The used value of 'height' is determined as for inline replaced
     *    elements.
    \*-----------------------------------------------------------------------*/
    // NOTE: This value of height is FINAL in that the min/max height calculations
    // are dealt with in calcReplacedHeight().  This means that the steps to produce
    // correct max/min in the non-replaced version, are not necessary.
    m_height = calcReplacedHeight() + borderTop() + borderBottom() + paddingTop() + paddingBottom();
    const int availableSpace = containerHeight - m_height;

    /*-----------------------------------------------------------------------*\
     * 2. If both 'top' and 'bottom' have the value 'auto', replace 'top'
     *    with the element's static position.
    \*-----------------------------------------------------------------------*/
    if (top.isVariable() && bottom.isVariable()) {
        // m_staticY should already have been set through layout of the parent().
        int staticTop = m_staticY - containerBlock->borderTop();
        for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) {
            staticTop += po->yPos();
        }
        top.setValue(Fixed, staticTop);
    }

    /*-----------------------------------------------------------------------*\
     * 3. If 'bottom' is 'auto', replace any 'auto' on 'margin-top' or
     *    'margin-bottom' with '0'.
    \*-----------------------------------------------------------------------*/
    // FIXME: The spec. says that this step should only be taken when bottom is
    // auto, but if only top is auto, this makes step 4 impossible.
    if (top.isVariable() || bottom.isVariable()) {
        if (marginTop.isVariable())
            marginTop.setValue(Fixed, 0);
        if (marginBottom.isVariable())
            marginBottom.setValue(Fixed, 0);
    }

    /*-----------------------------------------------------------------------*\
     * 4. If at this point both 'margin-top' and 'margin-bottom' are still
     *    'auto', solve the equation under the extra constraint that the two
     *    margins must get equal values.
    \*-----------------------------------------------------------------------*/
    int topValue = 0;
    int bottomValue = 0;

    if (marginTop.isVariable() && marginBottom.isVariable()) {
        // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combinded.
        assert(!(top.isVariable() || bottom.isVariable()));

        topValue = top.width(containerHeight);
        bottomValue = bottom.width(containerHeight);

        int difference = availableSpace - (topValue + bottomValue);
        // NOTE: This may result in negative values.
        m_marginTop =  difference / 2; // split the difference
        m_marginBottom = difference - m_marginTop; // account for odd valued differences

    /*-----------------------------------------------------------------------*\
     * 5. If at this point there is only one 'auto' left, solve the equation
     *    for that value.
    \*-----------------------------------------------------------------------*/
    } else if (top.isVariable()) {
        m_marginTop = marginTop.width(containerHeight);
        m_marginBottom = marginBottom.width(containerHeight);
        bottomValue = bottom.width(containerHeight);

        // Solve for 'top'
        topValue = availableSpace - (bottomValue + m_marginTop + m_marginBottom);
    } else if (bottom.isVariable()) {
        m_marginTop = marginTop.width(containerHeight);
        m_marginBottom = marginBottom.width(containerHeight);
        topValue = top.width(containerHeight);

        // Solve for 'bottom'
        // NOTE: It is not necessary to solve for 'bottom' because we don't ever
        // use the value.
    } else if (marginTop.isVariable()) {
        m_marginBottom = marginBottom.width(containerHeight);
        topValue = top.width(containerHeight);
        bottomValue = bottom.width(containerHeight);

        // Solve for 'margin-top'
        m_marginTop = availableSpace - (topValue + bottomValue + m_marginBottom);
    } else if (marginBottom.isVariable()) {
        m_marginTop = marginTop.width(containerHeight);
        topValue = top.width(containerHeight);
        bottomValue = bottom.width(containerHeight);

        // Solve for 'margin-bottom'
        m_marginBottom = availableSpace - (topValue + bottomValue + m_marginTop);
    }

    /*-----------------------------------------------------------------------*\
     * 6. If at this point the values are over-constrained, ignore the value
     *    for 'bottom' and solve for that value.
    \*-----------------------------------------------------------------------*/
    else {
        m_marginTop = marginTop.width(containerHeight);
        m_marginBottom = marginBottom.width(containerHeight);
        topValue = top.width(containerHeight);

        // Solve for 'bottom'
        // NOTE: It is not necessary to solve for 'bottom' because we don't ever
        // use the value.
    }

    // Use computed values to calculate the vertical position.
    m_y = topValue + m_marginTop + containerBlock->borderTop();
}

int RenderBox::highestPosition(bool /*includeOverflowInterior*/, bool includeSelf) const
{
    return includeSelf ? 0 : m_height;
}

int RenderBox::lowestPosition(bool /*includeOverflowInterior*/, bool includeSelf) const
{
    return includeSelf ? m_height : 0;
}

int RenderBox::rightmostPosition(bool /*includeOverflowInterior*/, bool includeSelf) const
{
    return includeSelf ? m_width : 0;
}

int RenderBox::leftmostPosition(bool /*includeOverflowInterior*/, bool includeSelf) const
{
    return includeSelf ? 0 : m_width;
}

int RenderBox::pageTopAfter(int y) const
{
    RenderObject* cb = container();
    if (cb)
        return cb->pageTopAfter(y+yPos()) - yPos();
    else
        return 0;
}

int RenderBox::crossesPageBreak(int t, int b) const
{
    RenderObject* cb = container();
    if (cb)
        return cb->crossesPageBreak(yPos()+t, yPos()+b);
    else
        return false;
}

void RenderBox::caretPos(int /*offset*/, int flags, int &_x, int &_y, int &width, int &height)
{
#if 0
    _x = -1;

    // propagate it downwards to its children, someone will feel responsible
    RenderObject *child = firstChild();
//    if (child) kdDebug(6040) << "delegating caretPos to " << child->renderName() << endl;
    if (child) child->caretPos(offset, override, _x, _y, width, height);

    // if not, use the extents of this box. offset 0 means left, offset 1 means
    // right
    if (_x == -1) {
        //kdDebug(6040) << "no delegation" << endl;
        _x = xPos() + (offset == 0 ? 0 : m_width);
	_y = yPos();
	height = m_height;
	width = override && offset == 0 ? m_width : 1;

	// If height of box is smaller than font height, use the latter one,
	// otherwise the caret might become invisible.
	// FIXME: ignoring :first-line, missing good reason to take care of
	int fontHeight = style()->fontMetrics().height();
	if (fontHeight > height)
	  height = fontHeight;

        int absx, absy;

        RenderObject *cb = containingBlock();

        if (cb && cb != this && cb->absolutePosition(absx,absy)) {
            //kdDebug(6040) << "absx=" << absx << " absy=" << absy << endl;
            _x += absx;
            _y += absy;
        } else {
            // we don't know our absolute position, and there is no point returning
            // just a relative one
            _x = _y = -1;
        }
    }
#endif

    _x = xPos();
    _y = yPos();
//     kdDebug(6040) << "_x " << _x << " _y " << _y << endl;
    width = 1;		// no override is indicated in boxes

    RenderBlock *cb = containingBlock();

    // Place caret outside the border
    if (flags & CFOutside) {

        RenderStyle *s = element() && element()->parent()
			&& element()->parent()->renderer()
			? element()->parent()->renderer()->style()
			: cb->style();

        const TQFontMetrics &fm = s->fontMetrics();
        height = fm.height();

	bool rtl = s->direction() == RTL;
	bool outsideEnd = flags & CFOutsideEnd;

	if (outsideEnd) {
	    _x += this->width();
	} else {
	    _x--;
	}

	int hl = fm.leading() / 2;
	if (!isReplaced() || style()->display() == BLOCK) {
	    if (!outsideEnd ^ rtl)
	        _y -= hl;
	    else
	        _y += kMax(this->height() - fm.ascent() - hl, 0);
	} else {
	    _y += baselinePosition(false) - fm.ascent() - hl;
	}

    // Place caret inside the element
    } else {
        const TQFontMetrics &fm = style()->fontMetrics();
        height = fm.height();

        RenderStyle *s = style();

        _x += borderLeft() + paddingLeft();
        _y += borderTop() + paddingTop();

        // ### regard direction
	switch (s->textAlign()) {
	case LEFT:
	case KHTML_LEFT:
	case TAAUTO:	// ### find out what this does
	case JUSTIFY:
	    break;
	case CENTER:
	case KHTML_CENTER:
	    _x += contentWidth() / 2;
	    break;
	case KHTML_RIGHT:
	case RIGHT:
	    _x += contentWidth();
	    break;
	}
    }

    int absx, absy;
    if (cb && cb != this && cb->absolutePosition(absx,absy)) {
//         kdDebug(6040) << "absx=" << absx << " absy=" << absy << endl;
        _x += absx;
        _y += absy;
    } else {
        // we don't know our absolute position, and there is no point returning
        // just a relative one
        _x = _y = -1;
    }
}

#undef DEBUG_LAYOUT