#include <qpainter.h>
#include "rendering/render_box.h"
#include "rendering/render_replaced.h"
#include "rendering/render_canvas.h"
#include "rendering/render_table.h"
#include "render_flexbox.h"
#include "render_arena.h"
#include "misc/htmlhashes.h"
#include "xml/dom_nodeimpl.h"
#include "xml/dom_docimpl.h"
#include "html/html_elementimpl.h"
#include "render_line.h"
#include <khtmlview.h>
#include <kdebug.h>
#include <assert.h>
using namespace DOM;
using namespace khtml;
#define TABLECELLMARGIN -0x4000
RenderBox::RenderBox(DOM::NodeImpl* node)
: RenderObject(node)
{
m_minWidth = -1;
m_maxWidth = -1;
m_overrideSize = -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_layer = 0;
m_inlineBoxWrapper = 0;
}
void RenderBox::setStyle(RenderStyle *_style)
{
RenderObject::setStyle(_style);
if (isRoot())
setShouldPaintBackgroundOrBorder(true);
setInline(_style->isDisplayInlineType());
switch(_style->position())
{
case ABSOLUTE:
case FIXED:
setPositioned(true);
break;
default:
setPositioned(false);
if (_style->isFloating())
setFloating(true);
if (_style->position() == RELATIVE)
setRelPositioned(true);
}
if (_style->overflow() != OVISIBLE && isBlockFlow() && !isTableCell() &&
(!document()->isHTMLDocument() || !isBody()))
setHasOverflowClip();
if (requiresLayer()) {
if (!m_layer) {
m_layer = new (renderArena()) RenderLayer(this);
m_layer->insertOnlyThisLayer();
if (containingBlock())
m_layer->updateLayerPositions();
}
}
else if (m_layer && !isRoot() && !isCanvas()) {
m_layer->removeOnlyThisLayer();
m_layer = 0;
}
if (m_layer)
m_layer->styleChanged();
if (isBody())
element()->getDocument()->setTextColor(_style->color());
if (style()->outlineWidth() > 0 && style()->outlineSize() > maximalOutlineSize(PaintActionOutline))
static_cast<RenderCanvas*>(document()->renderer())->setMaximalOutlineSize(style()->outlineSize());
}
RenderBox::~RenderBox()
{
}
void RenderBox::detach()
{
RenderLayer* layer = m_layer;
RenderArena* arena = renderArena();
if (layer)
layer->clearClipRect();
if (m_inlineBoxWrapper) {
if (!documentBeingDestroyed())
m_inlineBoxWrapper->remove();
m_inlineBoxWrapper->detach(arena);
m_inlineBoxWrapper = 0;
}
RenderObject::detach();
if (layer)
layer->detach(arena);
}
int RenderBox::contentWidth() const
{
int w = m_width - borderLeft() - borderRight();
w -= paddingLeft() + paddingRight();
if (includeScrollbarSize())
w -= m_layer->verticalScrollbarWidth();
return w;
}
int RenderBox::contentHeight() const
{
int h = m_height - borderTop() - borderBottom();
h -= paddingTop() + paddingBottom();
if (includeScrollbarSize())
h -= m_layer->horizontalScrollbarHeight();
return h;
}
int RenderBox::overrideWidth() const
{
return m_overrideSize == -1 ? m_width : m_overrideSize;
}
int RenderBox::overrideHeight() const
{
return m_overrideSize == -1 ? m_height : m_overrideSize;
}
void RenderBox::setPos( int xPos, int yPos )
{
if (xPos == m_x && yPos == m_y)
return;
m_x = xPos; m_y = yPos;
}
int RenderBox::width() const
{
return m_width;
}
int RenderBox::height() const
{
return m_height;
}
bool RenderBox::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
HitTestAction hitTestAction)
{
_tx += m_x;
_ty += m_y;
for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
if (!child->layer() && !child->isInlineFlow() && child->nodeAtPoint(info, _x, _y, _tx, _ty, hitTestAction)) {
setInnerNode(info);
return true;
}
}
if (hitTestAction != HitTestForeground)
return false;
QRect boundsRect(_tx, _ty, m_width, m_height);
if (boundsRect.contains(_x, _y)) {
setInnerNode(info);
return true;
}
return false;
}
void RenderBox::paint(PaintInfo& i, int _tx, int _ty)
{
_tx += m_x;
_ty += m_y;
for (RenderObject* child = firstChild(); child; child = child->nextSibling())
child->paint(i, _tx, _ty);
}
void RenderBox::paintRootBoxDecorations(PaintInfo& i, int _tx, int _ty)
{
const BackgroundLayer* bgLayer = style()->backgroundLayers();
QColor bgColor = style()->backgroundColor();
if (document()->isHTMLDocument() && !style()->hasBackground()) {
HTMLElementImpl* body = document()->body();
RenderObject* bodyObject = (body && body->id() == ID_BODY) ? body->renderer() : 0;
if (bodyObject) {
bgLayer = bodyObject->style()->backgroundLayers();
bgColor = bodyObject->style()->backgroundColor();
}
}
int w = width();
int h = height();
int rw, rh;
if (canvas()->view()) {
rw = canvas()->view()->contentsWidth();
rh = canvas()->view()->contentsHeight();
}
else {
rw = canvas()->width();
rh = canvas()->height();
}
int bx = _tx - marginLeft();
int by = _ty - marginTop();
int bw = kMax(w + marginLeft() + marginRight() + borderLeft() + borderRight(), rw);
int bh = kMax(h + marginTop() + marginBottom() + borderTop() + borderBottom(), rh);
int my = kMax(by, i.r.y());
paintBackgrounds(i.p, bgColor, bgLayer, my, i.r.height(), bx, by, bw, bh);
if (style()->hasBorder() && style()->display() != INLINE)
paintBorder( i.p, _tx, _ty, w, h, style() );
}
void RenderBox::paintBoxDecorations(PaintInfo& i, int _tx, int _ty)
{
if (!shouldPaintWithinRoot(i))
return;
if (isRoot())
return paintRootBoxDecorations(i, _tx, _ty);
int w = width();
int h = height() + borderTopExtra() + borderBottomExtra();
_ty -= borderTopExtra();
int my = kMax(_ty, i.r.y());
int mh;
if (_ty < i.r.y())
mh= kMax(0, h - (i.r.y() - _ty));
else
mh = kMin(i.r.height(), h);
if (!isBody() || !document()->isHTMLDocument() || document()->documentElement()->renderer()->style()->hasBackground())
paintBackgrounds(i.p, style()->backgroundColor(), style()->backgroundLayers(), my, mh, _tx, _ty, w, h);
if (style()->hasBorder())
paintBorder(i.p, _tx, _ty, w, h, style());
}
void RenderBox::paintBackgrounds(QPainter *p, const QColor& 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(QPainter *p, const QColor& 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());
}
void RenderBox::paintBackgroundExtended(QPainter *p, const QColor& c, const BackgroundLayer* bgLayer, int clipy, int cliph,
int _tx, int _ty, int w, int h,
int bleft, int bright)
{
CachedImage* bg = bgLayer->backgroundImage();
bool shouldPaintBackgroundImage = bg && bg->pixmap_size() == bg->valid_rect().size() && !bg->isTransparent() && !bg->isErrorImage();
QColor bgColor = c;
if (style()->forceBackgroundsToWhite()) {
bool shouldPaintBackgroundColor = !bgLayer->next() && bgColor.isValid() && qAlpha(bgColor.rgb()) > 0;
if (shouldPaintBackgroundImage || shouldPaintBackgroundColor) {
bgColor = Qt::white;
shouldPaintBackgroundImage = false;
}
}
if (!bgLayer->next() && isRoot() && !(bgColor.isValid() && qAlpha(bgColor.rgb()) > 0) && canvas()->view()) {
bool isTransparent;
DOM::NodeImpl* elt = document()->ownerElement();
if (elt) {
if (elt->id() == ID_FRAME)
isTransparent = false;
else {
HTMLElementImpl* body = document()->body();
isTransparent = !body || body->id() != ID_FRAMESET; }
} else
isTransparent = canvas()->view()->isTransparent();
if (isTransparent)
canvas()->view()->useSlowRepaints(); else
bgColor = canvas()->view()->palette().active().color(QColorGroup::Base);
}
if (!bgLayer->next() && bgColor.isValid() && qAlpha(bgColor.rgb()) > 0) {
if (qAlpha(bgColor.rgb()) < 0xFF && isRoot() && !canvas()->view()->isTransparent())
p->fillRect(_tx, clipy, w, cliph, canvas()->view()->palette().active().color(QColorGroup::Base));
p->fillRect(_tx, clipy, w, cliph, bgColor);
}
if (shouldPaintBackgroundImage) {
int sx = 0;
int sy = 0;
int cw,ch;
int cx,cy;
int vpab = bleft + bright;
int hpab = borderTop() + borderBottom();
if (bgLayer->backgroundAttachment())
{
int pw = w - vpab;
int ph = h - hpab;
int pixw = bg->pixmap_size().width();
int pixh = bg->pixmap_size().height();
EBackgroundRepeat bgr = bgLayer->backgroundRepeat();
if( (bgr == NO_REPEAT || bgr == REPEAT_Y) && w > pixw ) {
cw = pixw;
int xPosition = bgLayer->backgroundXPosition().minWidth(pw-pixw);
if (xPosition >= 0)
cx = _tx + xPosition;
else {
cx = _tx;
if (pixw == 0)
sx = 0;
else {
sx = -xPosition;
cw += xPosition;
}
}
cx += bleft;
} else {
cw = w;
cx = _tx;
if (pixw == 0)
sx = 0;
else {
sx = pixw - ((bgLayer->backgroundXPosition().minWidth(pw-pixw)) % pixw );
sx -= bleft % pixw;
}
}
if( (bgr == NO_REPEAT || bgr == REPEAT_X) && h > pixh ) {
ch = pixh;
int yPosition = bgLayer->backgroundYPosition().minWidth(ph-pixh);
if (yPosition >= 0)
cy = _ty + yPosition;
else {
cy = _ty;
if (pixh == 0)
sy = 0;
else {
sy = -yPosition;
ch += yPosition;
}
}
cy += borderTop();
} else {
ch = h;
cy = _ty;
if(pixh == 0){
sy = 0;
}else{
sy = pixh - ((bgLayer->backgroundYPosition().minWidth(ph-pixh)) % pixh );
sy -= borderTop() % pixh;
}
}
}
else
{
QRect vr = viewRect();
int pw = vr.width();
int ph = vr.height();
int pixw = bg->pixmap_size().width();
int pixh = bg->pixmap_size().height();
EBackgroundRepeat bgr = bgLayer->backgroundRepeat();
if( (bgr == NO_REPEAT || bgr == REPEAT_Y) && pw > pixw ) {
cw = pixw;
cx = vr.x() + bgLayer->backgroundXPosition().minWidth(pw-pixw);
} else {
cw = pw;
cx = vr.x();
if(pixw == 0){
sx = 0;
}else{
sx = pixw - ((bgLayer->backgroundXPosition().minWidth(pw-pixw)) % pixw );
}
}
if( (bgr == NO_REPEAT || bgr == REPEAT_X) && ph > pixh ) {
ch = pixh;
cy = vr.y() + bgLayer->backgroundYPosition().minWidth(ph-pixh);
} else {
ch = ph;
cy = vr.y();
if(pixh == 0){
sy = 0;
}else{
sy = pixh - ((bgLayer->backgroundYPosition().minWidth(ph-pixh)) % pixh );
}
}
QRect fix(cx,cy,cw,ch);
QRect ele(_tx,_ty,w,h);
QRect b = fix.intersect(ele);
sx+=b.x()-cx;
sy+=b.y()-cy;
cx=b.x();cy=b.y();cw=b.width();ch=b.height();
}
if (cw>0 && ch>0)
p->drawTiledPixmap(cx, cy, cw, ch, bg->tiled_pixmap(c), sx, sy);
}
}
void RenderBox::outlineBox(QPainter *p, int _tx, int _ty, const char *color)
{
p->setPen(QPen(QColor(color), 1, Qt::DotLine));
p->setBrush( Qt::NoBrush );
p->drawRect(_tx, _ty, m_width, m_height);
}
QRect RenderBox::getOverflowClipRect(int tx, int ty)
{
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;
if (m_layer) {
clipw -= m_layer->verticalScrollbarWidth();
cliph -= m_layer->horizontalScrollbarHeight();
}
return QRect(clipx,clipy,clipw,cliph);
}
QRect RenderBox::getClipRect(int tx, int ty)
{
int clipx = tx;
int clipy = ty;
int clipw = m_width;
int cliph = m_height;
if (!style()->clipLeft().isVariable())
{
int c=style()->clipLeft().width(m_width);
clipx+=c;
clipw-=c;
}
if (!style()->clipRight().isVariable())
{
int w = style()->clipRight().width(m_width);
clipw -= m_width - w;
}
if (!style()->clipTop().isVariable())
{
int c=style()->clipTop().width(m_height);
clipy+=c;
cliph-=c;
}
if (!style()->clipBottom().isVariable())
{
int h = style()->clipBottom().width(m_height);
cliph -= m_height - h;
}
QRect cr(clipx,clipy,clipw,cliph);
return cr;
}
int RenderBox::containingBlockWidth() const
{
RenderBlock* cb = containingBlock();
if (!cb)
return 0;
if (usesLineWidth())
return cb->lineWidth(m_y);
else
return cb->contentWidth();
}
bool RenderBox::absolutePosition(int &xPos, int &yPos, bool f)
{
if (style()->position() == FIXED)
f = true;
RenderObject *o = container();
if (o && o->absolutePosition(xPos, yPos, f)) {
if (o->hasOverflowClip())
o->layer()->subtractScrollOffset(xPos, yPos);
if (!isInline() || isReplaced())
xPos += m_x, yPos += m_y;
if (isRelPositioned())
relativePositionOffset(xPos, yPos);
return true;
}
else {
xPos = yPos = 0;
return false;
}
}
void RenderBox::dirtyLineBoxes(bool fullLayout, bool)
{
if (m_inlineBoxWrapper) {
if (fullLayout) {
m_inlineBoxWrapper->detach(renderArena());
m_inlineBoxWrapper = 0;
}
else
m_inlineBoxWrapper->dirtyLineBoxes();
}
}
void RenderBox::position(InlineBox* box, int from, int len, bool reverse)
{
if (isPositioned()) {
bool wasInline = style()->isOriginalDisplayInlineType();
if (wasInline && hasStaticX()) {
m_staticX = box->xPos();
}
else if (!wasInline && hasStaticY())
m_staticY = box->yPos();
box->remove();
box->detach(renderArena());
}
else if (isReplaced()) {
m_x = box->xPos();
m_y = box->yPos();
m_inlineBoxWrapper = box;
}
}
InlineBox* RenderBox::inlineBoxWrapper() const
{
return m_inlineBoxWrapper;
}
void RenderBox::deleteLineBoxWrapper()
{
if (m_inlineBoxWrapper)
m_inlineBoxWrapper->detach(renderArena());
m_inlineBoxWrapper = 0;
}
void RenderBox::setInlineBoxWrapper(InlineBox* b)
{
m_inlineBoxWrapper = b;
}
QRect RenderBox::getAbsoluteRepaintRect()
{
int ow = style() ? style()->outlineSize() : 0;
QRect r(-ow, -ow, overflowWidth(false)+ow*2, overflowHeight(false)+ow*2);
computeAbsoluteRepaintRect(r);
return r;
}
void RenderBox::computeAbsoluteRepaintRect(QRect& r, bool f)
{
int x = r.x() + m_x;
int y = r.y() + m_y;
if (style()->position() == RELATIVE && m_layer)
m_layer->relativePositionOffset(x,y);
if (style()->position()==FIXED)
f = true;
RenderObject* o = container();
if (o) {
if (o->hasOverflowClip()) {
QRect boxRect(0, 0, o->layer()->width(), o->layer()->height());
o->layer()->subtractScrollOffset(x,y); QRect repaintRect(x, y, r.width(), r.height());
r = repaintRect.intersect(boxRect);
if (r.isEmpty())
return;
}
else {
r.setX(x);
r.setY(y);
}
o->computeAbsoluteRepaintRect(r, f);
}
}
void RenderBox::repaintDuringLayoutIfMoved(int oldX, int oldY)
{
int newX = m_x;
int newY = m_y;
if (oldX != newX || oldY != newY) {
m_x = oldX; m_y = oldY;
repaint();
repaintFloatingDescendants();
m_x = newX; m_y = newY;
repaint();
repaintFloatingDescendants();
}
}
void RenderBox::relativePositionOffset(int &tx, int &ty)
{
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
{
if (m_overrideSize != -1 && parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
&& parent()->isFlexingChildren()) {
m_width = m_overrideSize;
return;
}
bool inVerticalBox = parent()->isFlexibleBox() && parent()->style()->boxOrient() == VERTICAL;
bool stretching = parent()->style()->boxAlign() == BSTRETCH;
bool treatAsReplaced = isReplaced() && !isInlineBlockOrInlineTable() &&
(!inVerticalBox || !stretching);
Length w;
if (treatAsReplaced)
w = Length( calcReplacedWidth(), Fixed );
else
w = style()->width();
Length ml = style()->marginLeft();
Length mr = style()->marginRight();
RenderBlock *cb = containingBlock();
int cw = containingBlockWidth();
if (cw<0) cw = 0;
m_marginLeft = 0;
m_marginRight = 0;
if (isInline() && !isInlineBlockOrInlineTable())
{
m_marginLeft = ml.minWidth(cw);
m_marginRight = mr.minWidth(cw);
if (treatAsReplaced)
{
m_width = w.width(cw);
m_width += paddingLeft() + paddingRight() + borderLeft() + borderRight();
if(m_width < m_minWidth) m_width = m_minWidth;
}
return;
}
else {
LengthType widthType, minWidthType, maxWidthType;
if (treatAsReplaced) {
m_width = w.width(cw);
m_width += paddingLeft() + paddingRight() + borderLeft() + borderRight();
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) {
m_marginLeft = ml.minWidth(cw);
m_marginRight = mr.minWidth(cw);
}
else
{
calcHorizontalMargins(ml,mr,cw);
}
}
if (cw && cw != m_width + m_marginLeft + m_marginRight && !isFloating() && !isInline() &&
!cb->isFlexibleBox())
{
if (cb->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;
if (sizesToMaxWidth()) {
if (width < m_minWidth)
width = m_minWidth;
if (width > m_maxWidth)
width = m_maxWidth;
}
}
else
{
width = w.width(cw);
width += paddingLeft() + paddingRight() + borderLeft() + borderRight();
}
return width;
}
void RenderBox::calcHorizontalMargins(const Length& ml, const Length& mr, int cw)
{
if (isFloating() || isInline()) {
m_marginLeft = ml.minWidth(cw);
m_marginRight = mr.minWidth(cw);
}
else
{
if ( (ml.type == Variable && mr.type == Variable) ||
(ml.type != Variable && mr.type != Variable &&
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.type == Variable ||
(ml.type != Variable && containingBlock()->style()->direction() == RTL &&
containingBlock()->style()->textAlign() == KHTML_LEFT))
{
m_marginLeft = ml.width(cw);
m_marginRight = cw - m_width - m_marginLeft;
}
else if (ml.type == Variable ||
(mr.type != Variable && containingBlock()->style()->direction() == LTR &&
containingBlock()->style()->textAlign() == KHTML_RIGHT))
{
m_marginRight = mr.width(cw);
m_marginLeft = cw - m_width - m_marginRight;
}
else
{
m_marginLeft = ml.minWidth(cw);
m_marginRight = mr.minWidth(cw);
}
}
}
void RenderBox::calcHeight()
{
#ifdef DEBUG_LAYOUT
kdDebug( 6040 ) << "RenderBox::calcHeight()" << endl;
#endif
if (isTableCell() || (isInline() && !isReplaced()))
return;
if (isPositioned())
calcAbsoluteVertical();
else
{
calcVerticalMargins();
if (isTable())
return;
Length h;
bool inHorizontalBox = parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL;
bool stretching = parent()->style()->boxAlign() == BSTRETCH;
bool treatAsReplaced = isReplaced() && !isInlineBlockOrInlineTable() && (!inHorizontalBox || !stretching);
bool checkMinMaxHeight = false;
if (m_overrideSize != -1 && parent()->isFlexibleBox() && parent()->style()->boxOrient() == VERTICAL
&& parent()->isFlexingChildren())
h = Length(m_overrideSize - borderTop() - borderBottom() - paddingTop() - paddingBottom(), Fixed);
else if (treatAsReplaced)
h = Length(calcReplacedHeight(), Fixed);
else {
h = style()->height();
checkMinMaxHeight = true;
}
if (h.isVariable() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
&& parent()->isStretchingChildren()) {
h = Length(parent()->contentHeight() - marginTop() - marginBottom() -
borderTop() - paddingTop() - borderBottom() - paddingBottom(), Fixed);
checkMinMaxHeight = false;
}
int height;
if (checkMinMaxHeight) {
height = calcHeightUsing(style()->height());
int minH = calcHeightUsing(style()->minHeight());
int maxH = style()->maxHeight().value == UNDEFINED ? height : calcHeightUsing(style()->maxHeight());
height = kMin(maxH, height);
height = kMax(minH, height);
}
else
height = h.value + borderTop() + paddingTop() + borderBottom() + paddingBottom();
m_height = height;
}
if (style()->overflow() == 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());
}
if (style()->htmlHacks() && style()->height().isVariable() &&
!isFloatingOrPositioned() && (isRoot() || isBody())) {
int margins = collapsedMarginTop() + collapsedMarginBottom();
int visHeight = canvas()->view()->visibleHeight();
if (isRoot())
m_height = kMax(m_height, visHeight - margins);
else
m_height = kMax(m_height, visHeight -
(margins + parent()->marginTop() + parent()->marginBottom() +
parent()->borderTop() + parent()->borderBottom() +
parent()->paddingTop() + parent()->paddingBottom()));
}
}
int RenderBox::calcHeightUsing(const Length& h)
{
if (!h.isVariable()) {
int height = -1;
if (h.isFixed())
height = h.value;
else if (h.isPercent())
height = calcPercentageHeight(h);
if (height != -1) {
height += borderTop() + paddingTop() + borderBottom() + paddingBottom();
return height;
}
}
return m_height;
}
int RenderBox::calcPercentageHeight(const Length& height)
{
int result = -1;
bool includeBorderPadding = isTable();
RenderBlock* cb = containingBlock();
if (style()->htmlHacks()) {
for ( ; !cb->isCanvas() && !cb->isBody() && !cb->isTableCell() && !cb->isPositioned() &&
cb->style()->height().isVariable(); cb = cb->containingBlock());
}
if (cb->isTableCell()) {
result = cb->overrideSize();
if (result == -1) {
RenderTableCell* cell = static_cast<RenderTableCell*>(cb);
if (scrollsOverflow() &&
(!cell->style()->height().isVariable() || !cell->table()->style()->height().isVariable()))
return 0;
return -1;
}
includeBorderPadding = true;
}
else if (cb->style()->height().isFixed())
result = cb->style()->height().value;
else if (cb->style()->height().isPercent())
result = cb->calcPercentageHeight(cb->style()->height());
else if (cb->isCanvas() || (cb->isBody() && style()->htmlHacks())) {
int oldHeight = cb->height();
cb->calcHeight();
result = cb->contentHeight();
cb->setHeight(oldHeight);
}
if (result != -1) {
result = height.width(result);
if (includeBorderPadding) {
result -= (borderTop() + paddingTop() + borderBottom() + paddingBottom());
result = kMax(0, result);
}
}
return result;
}
int 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;
}
}
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 Percent:
return availableHeightUsing(h);
case Fixed:
return h.value;
default:
return intrinsicHeight();
};
}
int RenderBox::availableHeight() const
{
return availableHeightUsing(style()->height());
}
int RenderBox::availableHeightUsing(const Length& h) const
{
if (h.isFixed())
return h.value;
if (isCanvas())
return static_cast<const RenderCanvas*>(this)->viewportHeight();
if (isTableCell() && (h.isVariable() || h.isPercent())) {
return overrideSize() - (borderLeft()+borderRight()+paddingLeft()+paddingRight());
}
if (h.isPercent())
return h.width(containingBlock()->availableHeight());
return containingBlock()->availableHeight();
}
void RenderBox::calcVerticalMargins()
{
if( isTableCell() ) {
m_marginTop = TABLECELLMARGIN;
m_marginBottom = TABLECELLMARGIN;
return;
}
Length tm = style()->marginTop();
Length bm = style()->marginBottom();
int cw = containingBlock()->contentWidth();
m_marginTop = tm.minWidth(cw);
m_marginBottom = bm.minWidth(cw);
}
void RenderBox::setStaticX(int staticX)
{
m_staticX = staticX;
}
void RenderBox::setStaticY(int staticY)
{
m_staticY = staticY;
}
void RenderBox::calcAbsoluteHorizontal()
{
const int AUTO = -666666;
int l,r,w,ml,mr,cw;
int pab = borderLeft()+ borderRight()+ paddingLeft()+ paddingRight();
l=r=ml=mr=w=AUTO;
RenderObject* cb = container();
cw = containingBlockWidth() + cb->paddingLeft() + cb->paddingRight();
if(!style()->left().isVariable())
l = style()->left().width(cw);
if(!style()->right().isVariable())
r = style()->right().width(cw);
if(!style()->width().isVariable())
w = style()->width().width(cw);
else if (isReplaced())
w = intrinsicWidth();
if(!style()->marginLeft().isVariable())
ml = style()->marginLeft().width(cw);
if(!style()->marginRight().isVariable())
mr = style()->marginRight().width(cw);
int static_distance=0;
if ((parent()->style()->direction()==LTR && (l==AUTO && r==AUTO ))
|| style()->left().isStatic())
{
static_distance = m_staticX - cb->borderLeft(); RenderObject* po = parent();
for (; po && po != cb; po = po->parent())
static_distance += po->xPos();
if (l==AUTO || style()->left().isStatic())
l = static_distance;
}
else if ((parent()->style()->direction()==RTL && (l==AUTO && r==AUTO ))
|| style()->right().isStatic())
{
RenderObject* po = parent();
static_distance = m_staticX - cb->borderLeft(); while (po && po!=containingBlock()) {
static_distance+=po->xPos();
po=po->parent();
}
if (r==AUTO || style()->right().isStatic())
r = static_distance;
}
if (l!=AUTO && w!=AUTO && r!=AUTO)
{
int ot = l + w + r + pab;
if (ml==AUTO && mr==AUTO)
{
ml = (cw - ot)/2;
mr = cw - ot - ml;
}
else if (ml==AUTO)
ml = cw - ot - mr;
else if (mr==AUTO)
mr = cw - ot - ml;
else
{
if (style()->direction()==LTR)
r = cw - ( l + w + ml + mr + pab);
else
l = cw - ( r + w + ml + mr + pab);
}
}
else
{
if (ml==AUTO) ml = 0;
if (mr==AUTO) mr = 0;
if (l==AUTO && w==AUTO && r!=AUTO)
{
w = QMIN(QMAX(m_minWidth-pab, cw - ( r + ml + mr + pab)), m_maxWidth-pab);
l = cw - ( r + w + ml + mr + pab);
}
else
if (l==AUTO && w!=AUTO && r==AUTO)
{
if (style()->direction()==RTL)
{
r = static_distance;
l = cw - ( r + w + ml + mr + pab);
}
else
{
l = static_distance;
r = cw - ( l + w + ml + mr + pab);
}
}
else
if (l!=AUTO && w==AUTO && r==AUTO)
{
w = QMIN(QMAX(m_minWidth-pab, cw - ( l + ml + mr + pab)), m_maxWidth-pab);
r = cw - ( l + w + ml + mr + pab);
}
else
if (l==AUTO && w!=AUTO && r!=AUTO)
l = cw - ( r + w + ml + mr + pab);
else
if (l!=AUTO && w==AUTO && r!=AUTO)
w = cw - ( r + l + ml + mr + pab);
else
if (l!=AUTO && w!=AUTO && r==AUTO)
r = cw - ( l + w + ml + mr + pab);
}
m_width = w + pab;
m_marginLeft = ml;
m_marginRight = mr;
m_x = l + ml + cb->borderLeft();
}
void RenderBox::calcAbsoluteVertical()
{
const int AUTO = -666666;
int t,b,h,mt,mb,ch;
t=b=h=mt=mb=AUTO;
int pab = borderTop()+borderBottom()+paddingTop()+paddingBottom();
RenderObject* cb = container();
if (cb->isRoot()) ch = cb->availableHeight();
else
ch = cb->height() - cb->borderTop() - cb->borderBottom();
if(!style()->top().isVariable())
t = style()->top().width(ch);
if(!style()->bottom().isVariable())
b = style()->bottom().width(ch);
if (isTable() && style()->height().isVariable())
h = m_height - pab;
else if(!style()->height().isVariable())
{
h = style()->height().width(ch);
if (m_height-pab > h) {
setOverflowHeight(m_height + pab - (paddingBottom() + borderBottom()));
m_height = h+pab;
}
}
else if (isReplaced())
h = intrinsicHeight();
if(!style()->marginTop().isVariable())
mt = style()->marginTop().width(ch);
if(!style()->marginBottom().isVariable())
mb = style()->marginBottom().width(ch);
int static_top=0;
if ((t==AUTO && b==AUTO ) || style()->top().isStatic())
{
static_top = m_staticY - cb->borderTop(); RenderObject* po = parent();
for (; po && po != cb; po = po->parent())
static_top += po->yPos();
if (h==AUTO || style()->top().isStatic())
t = static_top;
}
if (t!=AUTO && h!=AUTO && b!=AUTO)
{
int ot = h + t + b + pab;
if (mt==AUTO && mb==AUTO)
{
mt = (ch - ot)/2;
mb = ch - ot - mt;
}
else if (mt==AUTO)
mt = ch - ot - mb;
else if (mb==AUTO)
mb = ch - ot - mt;
else
b = ch - ( h+t+mt+mb+pab);
}
else
{
if (mt==AUTO) mt = 0;
if (mb==AUTO) mb = 0;
if (t==AUTO && h==AUTO && b!=AUTO)
{
h = m_height-pab;
t = ch - ( h+b+mt+mb+pab);
}
else
if (t==AUTO && h!=AUTO && b==AUTO)
{
t = static_top;
b = ch - ( h+t+mt+mb+pab);
}
else
if (t!=AUTO && h==AUTO && b==AUTO)
{
h = m_height-pab;
b = ch - ( h+t+mt+mb+pab);
}
else
if (t==AUTO && h!=AUTO && b!=AUTO)
t = ch - ( h+b+mt+mb+pab);
else
if (t!=AUTO && h==AUTO && b!=AUTO)
h = ch - ( t+b+mt+mb+pab);
else
if (t!=AUTO && h!=AUTO && b==AUTO)
b = ch - ( h+t+mt+mb+pab);
}
if (m_height<h+pab) m_height = h+pab;
if (hasOverflowClip() && m_height > h+pab)
m_height = h+pab;
m_height = kMax(0, m_height);
m_marginTop = mt;
m_marginBottom = mb;
m_y = t + mt + cb->borderTop();
}
QRect RenderBox::caretRect(int offset, EAffinity affinity, int *extraWidthToEndOfLine)
{
RenderObject *child = firstChild();
if (child) {
QRect result = child->caretRect(offset, affinity, extraWidthToEndOfLine);
if (result.isEmpty())
return result;
}
int _x, _y, height;
_x = xPos() + (offset == 0 ? 0 : m_width);
InlineBox *box = inlineBoxWrapper();
if (box) {
height = box->root()->bottomOverflow() - box->root()->topOverflow();
_y = box->root()->topOverflow();
}
else {
_y = yPos();
height = m_height;
}
int fontHeight = style()->fontMetrics().height();
if (fontHeight > height || !isReplaced())
height = fontHeight;
int absx, absy;
RenderObject *cb = containingBlock();
if (cb && cb != this && cb->absolutePosition(absx,absy)) {
_x += absx;
_y += absy;
}
else {
return QRect();
}
if (extraWidthToEndOfLine)
*extraWidthToEndOfLine = m_width - _x;
return QRect(_x, _y, 1, 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;
}
#undef DEBUG_LAYOUT