2 * This file is part of the DOM implementation for KDE.
4 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5 * (C) 1999 Antti Koivisto (koivisto@kde.org)
6 * Copyright (C) 2004 Apple Computer, Inc.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
24 // -------------------------------------------------------------------------
25 //#define DEBUG_LAYOUT
30 #include "rendering/render_box.h"
31 #include "rendering/render_replaced.h"
32 #include "rendering/render_canvas.h"
33 #include "rendering/render_table.h"
34 #include "render_flexbox.h"
35 #include "render_arena.h"
37 #include "misc/htmlhashes.h"
38 #include "xml/dom_nodeimpl.h"
39 #include "xml/dom_docimpl.h"
40 #include "render_line.h"
42 #include <khtmlview.h>
48 using namespace khtml;
50 #define TABLECELLMARGIN -0x4000
52 RenderBox::RenderBox(DOM::NodeImpl* node)
58 m_width = m_height = 0;
68 m_inlineBoxWrapper = 0;
71 void RenderBox::setStyle(RenderStyle *_style)
73 RenderObject::setStyle(_style);
75 // The root always paints its background/border.
77 setShouldPaintBackgroundOrBorder(true);
79 setInline(_style->isDisplayInlineType());
81 switch(_style->position())
90 if (_style->isFloating())
93 if (_style->position() == RELATIVE)
94 setRelPositioned(true);
97 // FIXME: Note that we restrict overflow to blocks for now. One day table bodies and cells
98 // will need to support overflow.
99 // We also deal with the body scroll quirk here, since it sets the scrollbars for the document.
100 if (_style->overflow() != OVISIBLE && isBlockFlow() && !isTableCell() &&
101 (!document()->isHTMLDocument() || !isBody()))
102 setHasOverflowClip();
104 if (requiresLayer()) {
106 m_layer = new (renderArena()) RenderLayer(this);
107 m_layer->insertOnlyThisLayer();
110 else if (m_layer && !isRoot() && !isCanvas()) {
111 m_layer->removeOnlyThisLayer();
116 m_layer->styleChanged();
118 // Set the text color if we're the body.
120 element()->getDocument()->setTextColor(_style->color());
122 if (style()->outlineWidth() > 0 && style()->outlineSize() > maximalOutlineSize(PaintActionOutline))
123 static_cast<RenderCanvas*>(document()->renderer())->setMaximalOutlineSize(style()->outlineSize());
126 RenderBox::~RenderBox()
128 //kdDebug( 6040 ) << "Element destructor: this=" << nodeName().string() << endl;
131 void RenderBox::detach()
133 RenderLayer* layer = m_layer;
134 RenderArena* arena = renderArena();
136 if (m_inlineBoxWrapper) {
137 if (!documentBeingDestroyed())
138 m_inlineBoxWrapper->remove();
139 m_inlineBoxWrapper->detach(arena);
140 m_inlineBoxWrapper = 0;
143 RenderObject::detach();
146 layer->detach(arena);
149 int RenderBox::contentWidth() const
151 int w = m_width - borderLeft() - borderRight();
152 w -= paddingLeft() + paddingRight();
154 if (includeScrollbarSize())
155 w -= m_layer->verticalScrollbarWidth();
157 //kdDebug( 6040 ) << "RenderBox::contentWidth(2) = " << w << endl;
161 int RenderBox::contentHeight() const
163 int h = m_height - borderTop() - borderBottom();
164 h -= paddingTop() + paddingBottom();
166 if (includeScrollbarSize())
167 h -= m_layer->horizontalScrollbarHeight();
172 int RenderBox::overrideWidth() const
174 return m_overrideSize == -1 ? m_width : m_overrideSize;
177 int RenderBox::overrideHeight() const
179 return m_overrideSize == -1 ? m_height : m_overrideSize;
182 void RenderBox::setPos( int xPos, int yPos )
184 if (xPos == m_x && yPos == m_y)
185 return; // Optimize for the case where we don't move at all.
187 m_x = xPos; m_y = yPos;
190 int RenderBox::width() const
195 int RenderBox::height() const
201 // --------------------- painting stuff -------------------------------
203 void RenderBox::paint(PaintInfo& i, int _tx, int _ty)
208 // default implementation. Just pass paint through to the children
209 for (RenderObject* child = firstChild(); child; child = child->nextSibling())
210 child->paint(i, _tx, _ty);
213 void RenderBox::paintRootBoxDecorations(PaintInfo& i, int _tx, int _ty)
215 //kdDebug( 6040 ) << renderName() << "::paintBoxDecorations()" << _tx << "/" << _ty << endl;
216 QColor c = style()->backgroundColor();
217 CachedImage *bg = style()->backgroundImage();
219 bool canBeTransparent = true;
220 if (!c.isValid() && !bg) {
221 // Locate the <body> element using the DOM. This is easier than trying
222 // to crawl around a render tree with potential :before/:after content and
223 // anonymous blocks created by inline <body> tags etc. We can locate the <body>
224 // render object very easily via the DOM.
225 RenderObject* bodyObject = 0;
226 for (DOM::NodeImpl* elt = element()->firstChild(); elt; elt = elt->nextSibling()) {
227 if (elt->id() == ID_BODY) {
228 bodyObject = elt->renderer();
231 else if (elt->id() == ID_FRAMESET) {
232 canBeTransparent = false; // Can't scroll a frameset document anyway.
238 c = bodyObject->style()->backgroundColor();
239 bg = bodyObject->style()->backgroundImage();
243 // Only fill with a base color (e.g., white) if we're the root document, since iframes/frames with
244 // no background in the child document should show the parent's background.
245 if ((!c.isValid() || qAlpha(c.rgb()) == 0) && canvas()->view()) {
247 DOM::NodeImpl* elt = element()->getDocument()->ownerElement();
249 isTransparent = canBeTransparent && elt->id() != ID_FRAME; // Frames are never transparent.
251 isTransparent = canvas()->view()->isTransparent();
254 canvas()->view()->useSlowRepaints(); // The parent must show behind the child.
256 c = canvas()->view()->palette().active().color(QColorGroup::Base);
262 // kdDebug(0) << "width = " << w <<endl;
265 if (canvas()->view()) {
266 rw = canvas()->view()->contentsWidth();
267 rh = canvas()->view()->contentsHeight();
270 rw = canvas()->width();
271 rh = canvas()->height();
274 // kdDebug(0) << "rw = " << rw <<endl;
276 int bx = _tx - marginLeft();
277 int by = _ty - marginTop();
278 int bw = kMax(w + marginLeft() + marginRight() + borderLeft() + borderRight(), rw);
279 int bh = kMax(h + marginTop() + marginBottom() + borderTop() + borderBottom(), rh);
282 // " The background of the box generated by the root element covers the entire canvas."
283 // hence, paint the background even in the margin areas (unlike for every other element!)
284 // I just love these little inconsistencies .. :-( (Dirk)
285 int my = kMax(by, i.r.y());
287 paintBackground(i.p, c, bg, my, i.r.height(), bx, by, bw, bh);
289 if (style()->hasBorder() && style()->display() != INLINE)
290 paintBorder( i.p, _tx, _ty, w, h, style() );
293 void RenderBox::paintBoxDecorations(PaintInfo& i, int _tx, int _ty)
295 if (!shouldPaintWithinRoot(i))
298 //kdDebug( 6040 ) << renderName() << "::paintDecorations()" << endl;
300 return paintRootBoxDecorations(i, _tx, _ty);
303 int h = height() + borderTopExtra() + borderBottomExtra();
304 _ty -= borderTopExtra();
306 int my = kMax(_ty, i.r.y());
309 mh= kMax(0, h - (i.r.y() - _ty));
311 mh = kMin(i.r.height(), h);
313 // The <body> only paints its background if the root element has defined a background
314 // independent of the body. Go through the DOM to get to the root element's render object,
315 // since the root could be inline and wrapped in an anonymous block.
317 || element()->getDocument()->documentElement()->renderer()->style()->backgroundColor().isValid()
318 || element()->getDocument()->documentElement()->renderer()->style()->backgroundImage())
319 paintBackground(i.p, style()->backgroundColor(), style()->backgroundImage(), my, mh, _tx, _ty, w, h);
321 if (style()->hasBorder())
322 paintBorder(i.p, _tx, _ty, w, h, style());
325 void RenderBox::paintBackground(QPainter *p, const QColor &c, CachedImage *bg, int clipy, int cliph, int _tx, int _ty, int w, int height)
327 paintBackgroundExtended(p, c, bg, clipy, cliph, _tx, _ty, w, height,
328 borderLeft(), borderRight());
331 void RenderBox::paintBackgroundExtended(QPainter *p, const QColor &c, CachedImage *bg, int clipy, int cliph,
332 int _tx, int _ty, int w, int h,
333 int bleft, int bright)
335 if (c.isValid() && qAlpha(c.rgb()) > 0) {
336 // If we have an alpha and we are painting the root element, go ahead and blend with our default
337 // background color (typically white).
338 if (qAlpha(c.rgb()) < 0xFF && isRoot() && !canvas()->view()->isTransparent())
339 p->fillRect(_tx, clipy, w, cliph, canvas()->view()->palette().active().color(QColorGroup::Base));
340 p->fillRect(_tx, clipy, w, cliph, c);
343 // no progressive loading of the background image
344 if(bg && bg->pixmap_size() == bg->valid_rect().size() && !bg->isTransparent() && !bg->isErrorImage()) {
345 //kdDebug( 6040 ) << "painting bgimage at " << _tx << "/" << _ty << endl;
346 // ### might need to add some correct offsets
347 // ### use paddingX/Y
349 // for propagation of <body> up to <html>
350 RenderStyle* sptr = style();
351 if ((isRoot() && element() && element()->id() == ID_HTML) && firstChild() && !style()->backgroundImage())
352 sptr = firstChild()->style();
358 int vpab = bleft + bright;
359 int hpab = borderTop() + borderBottom();
361 // CSS2 chapter 14.2.1
363 if (sptr->backgroundAttachment())
369 int pixw = bg->pixmap_size().width();
370 int pixh = bg->pixmap_size().height();
371 EBackgroundRepeat bgr = sptr->backgroundRepeat();
372 if( (bgr == NO_REPEAT || bgr == REPEAT_Y) && w > pixw ) {
374 int xPosition = sptr->backgroundXPosition().minWidth(pw-pixw);
376 cx = _tx + xPosition;
393 sx = pixw - ((sptr->backgroundXPosition().minWidth(pw-pixw)) % pixw );
398 if( (bgr == NO_REPEAT || bgr == REPEAT_X) && h > pixh ) {
400 int yPosition = sptr->backgroundYPosition().minWidth(ph-pixh);
402 cy = _ty + yPosition;
420 sy = pixh - ((sptr->backgroundYPosition().minWidth(ph-pixh)) % pixh );
421 sy -= borderTop() % pixh;
428 QRect vr = viewRect();
430 int ph = vr.height();
432 int pixw = bg->pixmap_size().width();
433 int pixh = bg->pixmap_size().height();
434 EBackgroundRepeat bgr = sptr->backgroundRepeat();
435 if( (bgr == NO_REPEAT || bgr == REPEAT_Y) && pw > pixw ) {
437 cx = vr.x() + sptr->backgroundXPosition().minWidth(pw-pixw);
444 sx = pixw - ((sptr->backgroundXPosition().minWidth(pw-pixw)) % pixw );
448 if( (bgr == NO_REPEAT || bgr == REPEAT_X) && ph > pixh ) {
450 cy = vr.y() + sptr->backgroundYPosition().minWidth(ph-pixh);
457 sy = pixh - ((sptr->backgroundYPosition().minWidth(ph-pixh)) % pixh );
461 QRect fix(cx,cy,cw,ch);
462 QRect ele(_tx,_ty,w,h);
463 QRect b = fix.intersect(ele);
466 cx=b.x();cy=b.y();cw=b.width();ch=b.height();
470 // kdDebug() << "cx="<<cx << " cy="<<cy<< " cw="<<cw << " ch="<<ch << " sx="<<sx << " sy="<<sy << endl;
473 p->drawTiledPixmap(cx, cy, cw, ch, bg->tiled_pixmap(c), sx, sy);
477 void RenderBox::outlineBox(QPainter *p, int _tx, int _ty, const char *color)
479 p->setPen(QPen(QColor(color), 1, Qt::DotLine));
480 p->setBrush( Qt::NoBrush );
481 p->drawRect(_tx, _ty, m_width, m_height);
484 QRect RenderBox::getOverflowClipRect(int tx, int ty)
486 // XXX When overflow-clip (CSS3) is implemented, we'll obtain the property
488 int bl=borderLeft(),bt=borderTop(),bb=borderBottom(),br=borderRight();
491 int clipw = m_width-bl-br;
492 int cliph = m_height-bt-bb;
494 // Subtract out scrollbars if we have them.
496 clipw -= m_layer->verticalScrollbarWidth();
497 cliph -= m_layer->horizontalScrollbarHeight();
499 return QRect(clipx,clipy,clipw,cliph);
502 QRect RenderBox::getClipRect(int tx, int ty)
507 int cliph = m_height;
509 if (!style()->clipLeft().isVariable())
511 int c=style()->clipLeft().width(m_width);
516 if (!style()->clipRight().isVariable())
518 int w = style()->clipRight().width(m_width);
519 clipw -= m_width - w;
522 if (!style()->clipTop().isVariable())
524 int c=style()->clipTop().width(m_height);
528 if (!style()->clipBottom().isVariable())
530 int h = style()->clipBottom().width(m_height);
531 cliph -= m_height - h;
533 //kdDebug( 6040 ) << "setting clip("<<clipx<<","<<clipy<<","<<clipw<<","<<cliph<<")"<<endl;
535 QRect cr(clipx,clipy,clipw,cliph);
539 int RenderBox::containingBlockWidth() const
541 RenderBlock* cb = containingBlock();
545 return cb->lineWidth(m_y);
547 return cb->contentWidth();
550 bool RenderBox::absolutePosition(int &xPos, int &yPos, bool f)
552 if (style()->position() == FIXED)
554 RenderObject *o = container();
555 if (o && o->absolutePosition(xPos, yPos, f)) {
556 if (o->hasOverflowClip())
557 o->layer()->subtractScrollOffset(xPos, yPos);
559 if (!isInline() || isReplaced())
560 xPos += m_x, yPos += m_y;
562 if (isRelPositioned())
563 relativePositionOffset(xPos, yPos);
573 void RenderBox::dirtyLineBoxes(bool fullLayout, bool)
575 if (m_inlineBoxWrapper) {
577 m_inlineBoxWrapper->detach(renderArena());
578 m_inlineBoxWrapper = 0;
581 m_inlineBoxWrapper->dirtyLineBoxes();
585 void RenderBox::position(InlineBox* box, int from, int len, bool reverse)
587 if (isPositioned()) {
588 // Cache the x position only if we were an INLINE type originally.
589 bool wasInline = style()->originalDisplay() == INLINE ||
590 style()->originalDisplay() == INLINE_TABLE;
591 if (wasInline && hasStaticX()) {
592 // The value is cached in the xPos of the box. We only need this value if
593 // our object was inline originally, since otherwise it would have ended up underneath
595 m_staticX = box->xPos();
597 else if (!wasInline && hasStaticY())
598 // Our object was a block originally, so we make our normal flow position be
599 // just below the line box (as though all the inlines that came before us got
600 // wrapped in an anonymous block, which is what would have happened had we been
601 // in flow). This value was cached in the yPos() of the box.
602 m_staticY = box->yPos();
606 box->detach(renderArena());
608 else if (isReplaced()) {
611 m_inlineBoxWrapper = box;
615 // For inline replaced elements, this function returns the inline box that owns us. Enables
616 // the replaced RenderObject to quickly determine what line it is contained on and to easily
617 // iterate over structures on the line.
618 InlineBox* RenderBox::inlineBoxWrapper() const
620 return m_inlineBoxWrapper;
623 void RenderBox::deleteLineBoxWrapper()
625 if (m_inlineBoxWrapper)
626 m_inlineBoxWrapper->detach(renderArena());
627 m_inlineBoxWrapper = 0;
630 void RenderBox::setInlineBoxWrapper(InlineBox* b)
632 m_inlineBoxWrapper = b;
635 QRect RenderBox::getAbsoluteRepaintRect()
637 int ow = style() ? style()->outlineSize() : 0;
638 QRect r(-ow, -ow, overflowWidth(false)+ow*2, overflowHeight(false)+ow*2);
639 computeAbsoluteRepaintRect(r);
643 void RenderBox::computeAbsoluteRepaintRect(QRect& r, bool f)
648 // Apply the relative position offset when invalidating a rectangle. The layer
649 // is translated, but the render box isn't, so we need to do this to get the
650 // right dirty rect. Since this is called from RenderObject::setStyle, the relative position
651 // flag on the RenderObject has been cleared, so use the one on the style().
652 if (style()->position() == RELATIVE && m_layer)
653 m_layer->relativePositionOffset(x,y);
655 if (style()->position()==FIXED)
658 RenderObject* o = container();
660 // <body> may not have overflow, since it might be applying its overflow value to the
662 if (o->hasOverflowClip()) {
663 // o->height() is inaccurate if we're in the middle of a layout of |o|, so use the
664 // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint
665 // anyway if its size does change.
666 QRect boxRect(0, 0, o->layer()->width(), o->layer()->height());
667 o->layer()->subtractScrollOffset(x,y); // For overflow:auto/scroll/hidden.
668 QRect repaintRect(x, y, r.width(), r.height());
669 r = repaintRect.intersect(boxRect);
677 o->computeAbsoluteRepaintRect(r, f);
681 void RenderBox::repaintDuringLayoutIfMoved(int oldX, int oldY)
685 if (oldX != newX || oldY != newY) {
686 // The child moved. Invalidate the object's old and new positions. We have to do this
687 // since the object may not have gotten a layout.
688 m_x = oldX; m_y = oldY;
690 repaintFloatingDescendants();
691 m_x = newX; m_y = newY;
693 repaintFloatingDescendants();
697 void RenderBox::relativePositionOffset(int &tx, int &ty)
699 if(!style()->left().isVariable())
700 tx += style()->left().width(containingBlockWidth());
701 else if(!style()->right().isVariable())
702 tx -= style()->right().width(containingBlockWidth());
703 if(!style()->top().isVariable())
705 if (!style()->top().isPercent()
706 || containingBlock()->style()->height().isFixed())
707 ty += style()->top().width(containingBlockHeight());
709 else if(!style()->bottom().isVariable())
711 if (!style()->bottom().isPercent()
712 || containingBlock()->style()->height().isFixed())
713 ty -= style()->bottom().width(containingBlockHeight());
717 void RenderBox::calcWidth()
720 kdDebug( 6040 ) << "RenderBox("<<renderName()<<")::calcWidth()" << endl;
724 calcAbsoluteHorizontal();
728 // The parent box is flexing us, so it has increased or decreased our width. Use the width
729 // from the style context.
730 if (m_overrideSize != -1 && parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
731 && parent()->isFlexingChildren()) {
732 m_width = m_overrideSize;
736 bool inVerticalBox = parent()->isFlexibleBox() && parent()->style()->boxOrient() == VERTICAL;
737 bool stretching = parent()->style()->boxAlign() == BSTRETCH;
738 bool treatAsReplaced = isReplaced() && !isInlineBlockOrInlineTable() &&
739 (!inVerticalBox || !stretching);
742 w = Length( calcReplacedWidth(), Fixed );
744 w = style()->width();
746 Length ml = style()->marginLeft();
747 Length mr = style()->marginRight();
749 RenderBlock *cb = containingBlock();
750 int cw = containingBlockWidth();
757 if (isInline() && !isInlineBlockOrInlineTable())
759 // just calculate margins
760 m_marginLeft = ml.minWidth(cw);
761 m_marginRight = mr.minWidth(cw);
764 m_width = w.width(cw);
765 m_width += paddingLeft() + paddingRight() + borderLeft() + borderRight();
766 if(m_width < m_minWidth) m_width = m_minWidth;
772 LengthType widthType, minWidthType, maxWidthType;
773 if (treatAsReplaced) {
774 m_width = w.width(cw);
775 m_width += paddingLeft() + paddingRight() + borderLeft() + borderRight();
778 m_width = calcWidthUsing(Width, cw, widthType);
779 int minW = calcWidthUsing(MinWidth, cw, minWidthType);
780 int maxW = style()->maxWidth().value == UNDEFINED ?
781 m_width : calcWidthUsing(MaxWidth, cw, maxWidthType);
783 if (m_width > maxW) {
785 widthType = maxWidthType;
787 if (m_width < minW) {
789 widthType = minWidthType;
793 if (widthType == Variable) {
794 // kdDebug( 6040 ) << "variable" << endl;
795 m_marginLeft = ml.minWidth(cw);
796 m_marginRight = mr.minWidth(cw);
800 // kdDebug( 6040 ) << "non-variable " << w.type << ","<< w.value << endl;
801 calcHorizontalMargins(ml,mr,cw);
805 if (cw && cw != m_width + m_marginLeft + m_marginRight && !isFloating() && !isInline() &&
806 !cb->isFlexibleBox())
808 if (cb->style()->direction()==LTR)
809 m_marginRight = cw - m_width - m_marginLeft;
811 m_marginLeft = cw - m_width - m_marginRight;
816 kdDebug( 6040 ) << "RenderBox::calcWidth(): m_width=" << m_width << " containingBlockWidth()=" << containingBlockWidth() << endl;
817 kdDebug( 6040 ) << "m_marginLeft=" << m_marginLeft << " m_marginRight=" << m_marginRight << endl;
821 int RenderBox::calcWidthUsing(WidthType widthType, int cw, LengthType& lengthType)
825 if (widthType == Width)
826 w = style()->width();
827 else if (widthType == MinWidth)
828 w = style()->minWidth();
830 w = style()->maxWidth();
834 if (lengthType == Variable) {
835 int marginLeft = style()->marginLeft().minWidth(cw);
836 int marginRight = style()->marginRight().minWidth(cw);
837 if (cw) width = cw - marginLeft - marginRight;
839 if (sizesToMaxWidth()) {
840 if (width < m_minWidth)
842 if (width > m_maxWidth)
849 width += paddingLeft() + paddingRight() + borderLeft() + borderRight();
855 void RenderBox::calcHorizontalMargins(const Length& ml, const Length& mr, int cw)
857 if (isFloating() || isInline()) // Inline blocks/tables and floats don't have their margins increased.
859 m_marginLeft = ml.minWidth(cw);
860 m_marginRight = mr.minWidth(cw);
864 if ( (ml.type == Variable && mr.type == Variable) ||
865 (ml.type != Variable && mr.type != Variable &&
866 containingBlock()->style()->textAlign() == KHTML_CENTER) )
868 m_marginLeft = (cw - m_width)/2;
869 if (m_marginLeft<0) m_marginLeft=0;
870 m_marginRight = cw - m_width - m_marginLeft;
872 else if (mr.type == Variable ||
873 (ml.type != Variable && containingBlock()->style()->direction() == RTL &&
874 containingBlock()->style()->textAlign() == KHTML_LEFT))
876 m_marginLeft = ml.width(cw);
877 m_marginRight = cw - m_width - m_marginLeft;
879 else if (ml.type == Variable ||
880 (mr.type != Variable && containingBlock()->style()->direction() == LTR &&
881 containingBlock()->style()->textAlign() == KHTML_RIGHT))
883 m_marginRight = mr.width(cw);
884 m_marginLeft = cw - m_width - m_marginRight;
888 m_marginLeft = ml.minWidth(cw);
889 m_marginRight = mr.minWidth(cw);
894 void RenderBox::calcHeight()
898 kdDebug( 6040 ) << "RenderBox::calcHeight()" << endl;
901 // Cell height is managed by the table and inline non-replaced elements do not support a height property.
902 if (isTableCell() || (isInline() && !isReplaced()))
906 calcAbsoluteVertical();
909 calcVerticalMargins();
911 // For tables, calculate margins only
916 bool inHorizontalBox = parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL;
917 bool stretching = parent()->style()->boxAlign() == BSTRETCH;
918 bool treatAsReplaced = isReplaced() && !isInlineBlockOrInlineTable() && (!inHorizontalBox || !stretching);
919 bool checkMinMaxHeight = false;
921 // The parent box is flexing us, so it has increased or decreased our height. We have to
922 // grab our cached flexible height.
923 if (m_overrideSize != -1 && parent()->isFlexibleBox() && parent()->style()->boxOrient() == VERTICAL
924 && parent()->isFlexingChildren())
925 h = Length(m_overrideSize - borderTop() - borderBottom() - paddingTop() - paddingBottom(), Fixed);
926 else if (treatAsReplaced)
927 h = Length(calcReplacedHeight(), Fixed);
929 h = style()->height();
930 checkMinMaxHeight = true;
933 // Block children of horizontal flexible boxes fill the height of the box.
934 if (h.isVariable() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
935 && parent()->isStretchingChildren()) {
936 h = Length(parent()->contentHeight() - marginTop() - marginBottom() -
937 borderTop() - paddingTop() - borderBottom() - paddingBottom(), Fixed);
938 checkMinMaxHeight = false;
942 if (checkMinMaxHeight) {
943 height = calcHeightUsing(style()->height());
944 int minH = calcHeightUsing(style()->minHeight());
945 int maxH = style()->maxHeight().value == UNDEFINED ? height : calcHeightUsing(style()->maxHeight());
946 height = kMin(maxH, height);
947 height = kMax(minH, height);
950 // The only times we don't check min/max height are when a fixed length has
951 // been given as an override. Just use that.
952 height = h.value + borderTop() + paddingTop() + borderBottom() + paddingBottom();
956 // Unfurling marquees override with the furled height.
957 if (style()->overflow() == OMARQUEE && m_layer && m_layer->marquee() &&
958 m_layer->marquee()->isUnfurlMarquee() && !m_layer->marquee()->isHorizontal()) {
959 m_layer->marquee()->setEnd(m_height);
960 m_height = kMin(m_height, m_layer->marquee()->unfurlPos());
963 // WinIE quirk: The <html> block always fills the entire canvas in quirks mode. The <body> always fills the
964 // <html> block in quirks mode. Only apply this quirk if the block is normal flow and no height
966 if (style()->htmlHacks() && style()->height().isVariable() &&
967 !isFloatingOrPositioned() && (isRoot() || isBody())) {
968 int margins = collapsedMarginTop() + collapsedMarginBottom();
969 int visHeight = canvas()->view()->visibleHeight();
971 m_height = kMax(m_height, visHeight - margins);
973 m_height = kMax(m_height, visHeight -
974 (margins + parent()->marginTop() + parent()->marginBottom() +
975 parent()->borderTop() + parent()->borderBottom() +
976 parent()->paddingTop() + parent()->paddingBottom()));
980 int RenderBox::calcHeightUsing(const Length& h)
982 if (!h.isVariable()) {
986 else if (h.isPercent())
987 height = calcPercentageHeight(h);
989 height += borderTop() + paddingTop() + borderBottom() + paddingBottom();
996 int RenderBox::calcPercentageHeight(const Length& height)
999 bool includeBorderPadding = isTable();
1000 RenderBlock* cb = containingBlock();
1001 if (style()->htmlHacks()) {
1002 // In quirks mode, blocks with auto height are skipped, and we keep looking for an enclosing
1003 // block that may have a specified height and then use it. In strict mode, this violates the
1004 // specification, which states that percentage heights just revert to auto if the containing
1005 // block has an auto height.
1006 for ( ; !cb->isCanvas() && !cb->isBody() && !cb->isTableCell() && !cb->isPositioned() &&
1007 cb->style()->height().isVariable(); cb = cb->containingBlock());
1010 // Table cells violate what the CSS spec says to do with heights. Basically we
1011 // don't care if the cell specified a height or not. We just always make ourselves
1012 // be a percentage of the cell's current content height.
1013 if (cb->isTableCell()) {
1014 result = cb->overrideSize();
1017 includeBorderPadding = true;
1020 // Otherwise we only use our percentage height if our containing block had a specified
1022 else if (cb->style()->height().isFixed())
1023 result = cb->style()->height().value;
1024 else if (cb->style()->height().isPercent())
1025 // We need to recur and compute the percentage height for our containing block.
1026 result = cb->calcPercentageHeight(cb->style()->height());
1027 else if (cb->isCanvas() || (cb->isBody() && style()->htmlHacks())) {
1028 // Don't allow this to affect the block' m_height member variable, since this
1029 // can get called while the block is still laying out its kids.
1030 int oldHeight = cb->height();
1032 result = cb->contentHeight();
1033 cb->setHeight(oldHeight);
1036 result = height.width(result);
1037 if (includeBorderPadding) {
1038 // It is necessary to use the border-box to match WinIE's broken
1039 // box model. This is essential for sizing inside
1040 // table cells using percentage heights.
1041 result -= (borderTop() + paddingTop() + borderBottom() + paddingBottom());
1042 result = kMax(0, result);
1048 int RenderBox::calcReplacedWidth() const
1050 int width = calcReplacedWidthUsing(Width);
1051 int minW = calcReplacedWidthUsing(MinWidth);
1052 int maxW = style()->maxWidth().value == UNDEFINED ? width : calcReplacedWidthUsing(MaxWidth);
1063 int RenderBox::calcReplacedWidthUsing(WidthType widthType) const
1066 if (widthType == Width)
1067 w = style()->width();
1068 else if (widthType == MinWidth)
1069 w = style()->minWidth();
1071 w = style()->maxWidth();
1078 const int cw = containingBlockWidth();
1080 int result = w.minWidth(cw);
1086 return intrinsicWidth();
1090 int RenderBox::calcReplacedHeight() const
1092 int height = calcReplacedHeightUsing(Height);
1093 int minH = calcReplacedHeightUsing(MinHeight);
1094 int maxH = style()->maxHeight().value == UNDEFINED ? height : calcReplacedHeightUsing(MaxHeight);
1105 int RenderBox::calcReplacedHeightUsing(HeightType heightType) const
1108 if (heightType == Height)
1109 h = style()->height();
1110 else if (heightType == MinHeight)
1111 h = style()->minHeight();
1113 h = style()->maxHeight();
1116 return availableHeightUsing(h);
1120 return intrinsicHeight();
1124 int RenderBox::availableHeight() const
1126 return availableHeightUsing(style()->height());
1129 int RenderBox::availableHeightUsing(const Length& h) const
1135 return static_cast<const RenderCanvas*>(this)->viewportHeight();
1137 // We need to stop here, since we don't want to increase the height of the table
1138 // artificially. We're going to rely on this cell getting expanded to some new
1139 // height, and then when we lay out again we'll use the calculation below.
1140 if (isTableCell() && (h.isVariable() || h.isPercent())) {
1141 return overrideSize() - (borderLeft()+borderRight()+paddingLeft()+paddingRight());
1145 return h.width(containingBlock()->availableHeight());
1147 return containingBlock()->availableHeight();
1150 void RenderBox::calcVerticalMargins()
1152 if( isTableCell() ) {
1153 // table margins are basically infinite
1154 m_marginTop = TABLECELLMARGIN;
1155 m_marginBottom = TABLECELLMARGIN;
1159 Length tm = style()->marginTop();
1160 Length bm = style()->marginBottom();
1162 // margins are calculated with respect to the _width_ of
1163 // the containing block (8.3)
1164 int cw = containingBlock()->contentWidth();
1166 m_marginTop = tm.minWidth(cw);
1167 m_marginBottom = bm.minWidth(cw);
1170 void RenderBox::setStaticX(int staticX)
1172 m_staticX = staticX;
1175 void RenderBox::setStaticY(int staticY)
1177 m_staticY = staticY;
1180 void RenderBox::calcAbsoluteHorizontal()
1182 const int AUTO = -666666;
1185 int pab = borderLeft()+ borderRight()+ paddingLeft()+ paddingRight();
1189 // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
1190 RenderObject* cb = container();
1191 cw = containingBlockWidth() + cb->paddingLeft() + cb->paddingRight();
1193 if(!style()->left().isVariable())
1194 l = style()->left().width(cw);
1195 if(!style()->right().isVariable())
1196 r = style()->right().width(cw);
1197 if(!style()->width().isVariable())
1198 w = style()->width().width(cw);
1199 else if (isReplaced())
1200 w = intrinsicWidth();
1201 if(!style()->marginLeft().isVariable())
1202 ml = style()->marginLeft().width(cw);
1203 if(!style()->marginRight().isVariable())
1204 mr = style()->marginRight().width(cw);
1207 // printf("h1: w=%d, l=%d, r=%d, ml=%d, mr=%d\n",w,l,r,ml,mr);
1209 int static_distance=0;
1210 if ((parent()->style()->direction()==LTR && (l==AUTO && r==AUTO ))
1211 || style()->left().isStatic())
1213 static_distance = m_staticX - cb->borderLeft(); // Should already have been set through layout of the parent().
1214 RenderObject* po = parent();
1215 for (; po && po != cb; po = po->parent())
1216 static_distance += po->xPos();
1218 if (l==AUTO || style()->left().isStatic())
1219 l = static_distance;
1222 else if ((parent()->style()->direction()==RTL && (l==AUTO && r==AUTO ))
1223 || style()->right().isStatic())
1225 RenderObject* po = parent();
1226 static_distance = m_staticX - cb->borderLeft(); // Should already have been set through layout of the parent().
1227 while (po && po!=containingBlock()) {
1228 static_distance+=po->xPos();
1232 if (r==AUTO || style()->right().isStatic())
1233 r = static_distance;
1237 if (l!=AUTO && w!=AUTO && r!=AUTO)
1239 // left, width, right all given, play with margins
1240 int ot = l + w + r + pab;
1242 if (ml==AUTO && mr==AUTO)
1244 // both margins auto, solve for equality
1249 // solve for left margin
1252 // solve for right margin
1256 // overconstrained, solve according to dir
1257 if (style()->direction()==LTR)
1258 r = cw - ( l + w + ml + mr + pab);
1260 l = cw - ( r + w + ml + mr + pab);
1265 // one or two of (left, width, right) missing, solve
1267 // auto margins are ignored
1268 if (ml==AUTO) ml = 0;
1269 if (mr==AUTO) mr = 0;
1271 //1. solve left & width.
1272 if (l==AUTO && w==AUTO && r!=AUTO)
1274 // From section 10.3.7 of the CSS2.1 specification.
1275 // "The shrink-to-fit width is: min(max(preferred minimum width, available width), preferred width)."
1276 w = QMIN(QMAX(m_minWidth-pab, cw - ( r + ml + mr + pab)), m_maxWidth-pab);
1277 l = cw - ( r + w + ml + mr + pab);
1281 //2. solve left & right. use static positioning.
1282 if (l==AUTO && w!=AUTO && r==AUTO)
1284 if (style()->direction()==RTL)
1286 r = static_distance;
1287 l = cw - ( r + w + ml + mr + pab);
1291 l = static_distance;
1292 r = cw - ( l + w + ml + mr + pab);
1298 //3. solve width & right.
1299 if (l!=AUTO && w==AUTO && r==AUTO)
1301 // From section 10.3.7 of the CSS2.1 specification.
1302 // "The shrink-to-fit width is: min(max(preferred minimum width, available width), preferred width)."
1303 w = QMIN(QMAX(m_minWidth-pab, cw - ( l + ml + mr + pab)), m_maxWidth-pab);
1304 r = cw - ( l + w + ml + mr + pab);
1309 if (l==AUTO && w!=AUTO && r!=AUTO)
1310 l = cw - ( r + w + ml + mr + pab);
1314 if (l!=AUTO && w==AUTO && r!=AUTO)
1315 w = cw - ( r + l + ml + mr + pab);
1319 if (l!=AUTO && w!=AUTO && r==AUTO)
1320 r = cw - ( l + w + ml + mr + pab);
1326 m_x = l + ml + cb->borderLeft();
1327 // printf("h: w=%d, l=%d, r=%d, ml=%d, mr=%d\n",w,l,r,ml,mr);
1331 void RenderBox::calcAbsoluteVertical()
1333 // css2 spec 10.6.4 & 10.6.5
1336 // http://www.w3.org/Style/css2-updates/REC-CSS2-19980512-errata
1337 // (actually updated 2000-10-24)
1338 // that introduces static-position value for top, left & right
1340 const int AUTO = -666666;
1345 int pab = borderTop()+borderBottom()+paddingTop()+paddingBottom();
1347 // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
1348 RenderObject* cb = container();
1349 if (cb->isRoot()) // Even in strict mode (where we don't grow the root to fill the viewport) other browsers
1350 // position as though the root fills the viewport.
1351 ch = cb->availableHeight();
1353 ch = cb->height() - cb->borderTop() - cb->borderBottom();
1355 if(!style()->top().isVariable())
1356 t = style()->top().width(ch);
1357 if(!style()->bottom().isVariable())
1358 b = style()->bottom().width(ch);
1359 if (isTable() && style()->height().isVariable())
1360 // Height is never unsolved for tables. "auto" means shrink to fit. Use our
1363 else if(!style()->height().isVariable())
1365 h = style()->height().width(ch);
1367 if (m_height-pab > h) {
1368 setOverflowHeight(m_height + pab - (paddingBottom() + borderBottom()));
1372 else if (isReplaced())
1373 h = intrinsicHeight();
1375 if(!style()->marginTop().isVariable())
1376 mt = style()->marginTop().width(ch);
1377 if(!style()->marginBottom().isVariable())
1378 mb = style()->marginBottom().width(ch);
1381 if ((t==AUTO && b==AUTO ) || style()->top().isStatic())
1383 // calc hypothetical location in the normal flow
1384 // used for 1) top=static-position
1385 // 2) top, bottom, height are all auto -> calc top -> 3.
1386 // 3) precalc for case 2 below
1387 static_top = m_staticY - cb->borderTop(); // Should already have been set through layout of the parent().
1388 RenderObject* po = parent();
1389 for (; po && po != cb; po = po->parent())
1390 static_top += po->yPos();
1392 if (h==AUTO || style()->top().isStatic())
1396 if (t!=AUTO && h!=AUTO && b!=AUTO)
1398 // top, height, bottom all given, play with margins
1399 int ot = h + t + b + pab;
1401 if (mt==AUTO && mb==AUTO)
1403 // both margins auto, solve for equality
1408 // solve for top margin
1411 // solve for bottom margin
1414 // overconstrained, solve for bottom
1415 b = ch - ( h+t+mt+mb+pab);
1419 // one or two of (top, height, bottom) missing, solve
1421 // auto margins are ignored
1422 if (mt==AUTO) mt = 0;
1423 if (mb==AUTO) mb = 0;
1425 //1. solve top & height. use content height.
1426 if (t==AUTO && h==AUTO && b!=AUTO)
1429 t = ch - ( h+b+mt+mb+pab);
1433 //2. solve top & bottom. use static positioning.
1434 if (t==AUTO && h!=AUTO && b==AUTO)
1437 b = ch - ( h+t+mt+mb+pab);
1441 //3. solve height & bottom. use content height.
1442 if (t!=AUTO && h==AUTO && b==AUTO)
1445 b = ch - ( h+t+mt+mb+pab);
1450 if (t==AUTO && h!=AUTO && b!=AUTO)
1451 t = ch - ( h+b+mt+mb+pab);
1455 if (t!=AUTO && h==AUTO && b!=AUTO)
1456 h = ch - ( t+b+mt+mb+pab);
1460 if (t!=AUTO && h!=AUTO && b==AUTO)
1461 b = ch - ( h+t+mt+mb+pab);
1464 if (m_height<h+pab) //content must still fit
1467 if (hasOverflowClip() && m_height > h+pab)
1470 // Do not allow the height to be negative. This can happen when someone specifies both top and bottom
1471 // but the containing block height is less than top, e.g., top:20px, bottom:0, containing block height 16.
1472 m_height = kMax(0, m_height);
1475 m_marginBottom = mb;
1476 m_y = t + mt + cb->borderTop();
1478 // printf("v: h=%d, t=%d, b=%d, mt=%d, mb=%d, m_y=%d\n",h,t,b,mt,mb,m_y);
1482 QRect RenderBox::caretRect(int offset, EAffinity affinity, int *extraWidthToEndOfLine)
1484 // FIXME: Is it OK to check only first child instead of picking
1485 // right child based on offset? Is it OK to pass the same offset
1486 // along to the child instead of offset 0 or whatever?
1488 // propagate it downwards to its children, someone will feel responsible
1489 RenderObject *child = firstChild();
1491 QRect result = child->caretRect(offset, affinity, extraWidthToEndOfLine);
1492 // FIXME: in-band signalling!
1493 if (result.isEmpty())
1499 // if not, use the extents of this box
1500 // offset 0 means left, offset 1 means right
1501 _x = xPos() + (offset == 0 ? 0 : m_width);
1502 InlineBox *box = inlineBoxWrapper();
1504 height = box->root()->bottomOverflow() - box->root()->topOverflow();
1505 _y = box->root()->topOverflow();
1511 // If height of box is smaller than font height, use the latter one,
1512 // otherwise the caret might become invisible.
1514 // Also, if the box is not a replaced element, always use the font height.
1515 // This prevents the "big caret" bug described in:
1516 // <rdar://problem/3777804> Deleting all content in a document can result in giant tall-as-window insertion point
1518 // FIXME: ignoring :first-line, missing good reason to take care of
1519 int fontHeight = style()->fontMetrics().height();
1520 if (fontHeight > height || !isReplaced())
1521 height = fontHeight;
1524 RenderObject *cb = containingBlock();
1525 if (cb && cb != this && cb->absolutePosition(absx,absy)) {
1530 // we don't know our absolute position, and there is no point returning
1531 // just a relative one
1535 if (extraWidthToEndOfLine)
1536 *extraWidthToEndOfLine = m_width - _x;
1538 return QRect(_x, _y, 1, height);
1541 int RenderBox::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
1543 return includeSelf ? m_height : 0;
1546 int RenderBox::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
1548 return includeSelf ? m_width : 0;
1551 int RenderBox::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
1553 return includeSelf ? 0 : m_width;