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 * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
7 * (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com)
8 * Copyright (C) 2005 Apple Computer, Inc.
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public License
21 * along with this library; see the file COPYING.LIB. If not, write to
22 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
28 #include "RenderBox.h"
30 #include "CachedImage.h"
32 #include "FrameView.h"
33 #include "GraphicsContext.h"
34 #include "HTMLElement.h"
35 #include "HTMLNames.h"
36 #include "RenderArena.h"
37 #include "RenderCanvas.h"
38 #include "RenderFlexibleBox.h"
39 #include "RenderTableCell.h"
40 #include "RenderTheme.h"
49 using namespace HTMLNames;
51 #define TABLECELLMARGIN -0x4000
53 RenderBox::RenderBox(WebCore::Node* node)
59 m_width = m_height = 0;
69 m_inlineBoxWrapper = 0;
72 void RenderBox::setStyle(RenderStyle *_style)
74 RenderObject::setStyle(_style);
76 // The root always paints its background/border.
78 setShouldPaintBackgroundOrBorder(true);
80 setInline(_style->isDisplayInlineType());
82 switch(_style->position())
84 case AbsolutePosition:
91 if (_style->isFloating())
94 if (_style->position() == RelativePosition)
95 setRelPositioned(true);
98 // We also handle <body> and <html>, whose overflow applies to the viewport.
99 if (_style->overflow() != OVISIBLE && !isRoot() && (!isBody() || !document()->isHTMLDocument()) &&
100 (isRenderBlock() || isTableRow() || isTableSection()))
101 setHasOverflowClip();
103 if (requiresLayer()) {
105 m_layer = new (renderArena()) RenderLayer(this);
106 m_layer->insertOnlyThisLayer();
107 if (parent() && containingBlock())
108 m_layer->updateLayerPositions();
111 else if (m_layer && !isRoot() && !isCanvas()) {
112 assert(m_layer->parent());
113 RenderLayer *layer = m_layer;
115 layer->removeOnlyThisLayer();
119 m_layer->styleChanged();
121 // Set the text color if we're the body.
123 element()->document()->setTextColor(_style->color());
125 if (style()->outlineWidth() > 0 && style()->outlineSize() > maximalOutlineSize(PaintPhaseOutline))
126 static_cast<RenderCanvas*>(document()->renderer())->setMaximalOutlineSize(style()->outlineSize());
129 RenderBox::~RenderBox()
133 void RenderBox::destroy()
135 // A lot of the code in this funtion is just pasted into
136 // RenderWidget::destroy. If anything in this function changes,
137 // be sure to fix RenderWidget::destroy() as well.
139 RenderLayer* layer = m_layer;
140 RenderArena* arena = renderArena();
142 // This must be done before we destroy the RenderObject.
144 layer->clearClipRect();
146 RenderObject::destroy();
149 layer->destroy(arena);
152 int RenderBox::contentWidth() const
154 int w = m_width - borderLeft() - borderRight();
155 w -= paddingLeft() + paddingRight();
157 if (includeScrollbarSize())
158 w -= m_layer->verticalScrollbarWidth();
163 int RenderBox::contentHeight() const
165 int h = m_height - borderTop() - borderBottom();
166 h -= paddingTop() + paddingBottom();
168 if (includeScrollbarSize())
169 h -= m_layer->horizontalScrollbarHeight();
174 int RenderBox::overrideWidth() const
176 return m_overrideSize == -1 ? m_width : m_overrideSize;
179 int RenderBox::overrideHeight() const
181 return m_overrideSize == -1 ? m_height : m_overrideSize;
184 void RenderBox::setPos( int xPos, int yPos )
186 if (xPos == m_x && yPos == m_y)
187 return; // Optimize for the case where we don't move at all.
189 m_x = xPos; m_y = yPos;
192 int RenderBox::width() const
197 int RenderBox::height() const
202 int RenderBox::calcBorderBoxWidth(int w) const
204 int toAdd = borderLeft() + borderRight() + paddingLeft() + paddingRight();
205 if (style()->boxSizing() == CONTENT_BOX)
207 return max(w, toAdd);
210 int RenderBox::calcBorderBoxHeight(int h) const
212 int toAdd = borderTop() + borderBottom() + paddingTop() + paddingBottom();
213 if (style()->boxSizing() == CONTENT_BOX)
215 return max(h, toAdd);
218 int RenderBox::calcContentBoxWidth(int w) const
220 if (style()->boxSizing() == BORDER_BOX)
221 w -= (borderLeft() + borderRight() + paddingLeft() + paddingRight());
225 int RenderBox::calcContentBoxHeight(int h) const
227 if (style()->boxSizing() == BORDER_BOX)
228 h -= (borderTop() + borderBottom() + paddingTop() + paddingBottom());
233 bool RenderBox::nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty, HitTestAction action)
239 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
240 // FIXME: We have to skip over inline flows, since they can show up inside table rows
241 // at the moment (a demoted inline <form> for example). If we ever implement a
242 // table-specific hit-test method (which we should do for performance reasons anyway),
243 // then we can remove this check.
244 if (!child->layer() && !child->isInlineFlow() && child->nodeAtPoint(info, x, y, tx, ty, action)) {
250 // Check our bounds next. For this purpose always assume that we can only be hit in the
251 // foreground phase (which is true for replaced elements like images).
252 if (action == HitTestForeground && IntRect(tx, ty, m_width, m_height).contains(x, y)) {
260 // --------------------- painting stuff -------------------------------
262 void RenderBox::paint(PaintInfo& i, int _tx, int _ty)
267 // default implementation. Just pass paint through to the children
268 for (RenderObject* child = firstChild(); child; child = child->nextSibling())
269 child->paint(i, _tx, _ty);
272 void RenderBox::paintRootBoxDecorations(PaintInfo& i, int _tx, int _ty)
274 const BackgroundLayer* bgLayer = style()->backgroundLayers();
275 Color bgColor = style()->backgroundColor();
276 if (document()->isHTMLDocument() && !style()->hasBackground()) {
277 // Locate the <body> element using the DOM. This is easier than trying
278 // to crawl around a render tree with potential :before/:after content and
279 // anonymous blocks created by inline <body> tags etc. We can locate the <body>
280 // render object very easily via the DOM.
281 HTMLElement* body = document()->body();
282 RenderObject* bodyObject = (body && body->hasLocalName(bodyTag)) ? body->renderer() : 0;
284 bgLayer = bodyObject->style()->backgroundLayers();
285 bgColor = bodyObject->style()->backgroundColor();
293 if (canvas()->view()) {
294 rw = canvas()->view()->contentsWidth();
295 rh = canvas()->view()->contentsHeight();
298 rw = canvas()->width();
299 rh = canvas()->height();
302 int bx = _tx - marginLeft();
303 int by = _ty - marginTop();
304 int bw = max(w + marginLeft() + marginRight() + borderLeft() + borderRight(), rw);
305 int bh = max(h + marginTop() + marginBottom() + borderTop() + borderBottom(), rh);
308 // " The background of the box generated by the root element covers the entire canvas."
309 // hence, paint the background even in the margin areas (unlike for every other element!)
310 // I just love these little inconsistencies .. :-( (Dirk)
311 int my = max(by, i.r.y());
313 paintBackgrounds(i.p, bgColor, bgLayer, my, i.r.height(), bx, by, bw, bh);
315 if (style()->hasBorder() && style()->display() != INLINE)
316 paintBorder( i.p, _tx, _ty, w, h, style() );
319 void RenderBox::paintBoxDecorations(PaintInfo& i, int _tx, int _ty)
321 if (!shouldPaintWithinRoot(i))
325 return paintRootBoxDecorations(i, _tx, _ty);
328 int h = height() + borderTopExtra() + borderBottomExtra();
329 _ty -= borderTopExtra();
331 int my = max(_ty, i.r.y());
334 mh = max(0, h - (i.r.y() - _ty));
336 mh = min(i.r.height(), h);
338 // If we have a native theme appearance, paint that before painting our background.
339 // The theme will tell us whether or not we should also paint the CSS background.
340 bool themePainted = style()->hasAppearance() && !theme()->paint(this, i, IntRect(_tx, _ty, w, h));
342 // The <body> only paints its background if the root element has defined a background
343 // independent of the body. Go through the DOM to get to the root element's render object,
344 // since the root could be inline and wrapped in an anonymous block.
345 if (!isBody() || !document()->isHTMLDocument() || document()->documentElement()->renderer()->style()->hasBackground())
346 paintBackgrounds(i.p, style()->backgroundColor(), style()->backgroundLayers(), my, mh, _tx, _ty, w, h);
349 // The theme will tell us whether or not we should also paint the CSS border.
350 if ((!style()->hasAppearance() || (!themePainted && theme()->paintBorderOnly(this, i, IntRect(_tx, _ty, w, h)))) && style()->hasBorder())
351 paintBorder(i.p, _tx, _ty, w, h, style());
354 void RenderBox::paintBackgrounds(GraphicsContext* p, const Color& c, const BackgroundLayer* bgLayer, int clipy, int cliph, int _tx, int _ty, int w, int height)
356 if (!bgLayer) return;
357 paintBackgrounds(p, c, bgLayer->next(), clipy, cliph, _tx, _ty, w, height);
358 paintBackground(p, c, bgLayer, clipy, cliph, _tx, _ty, w, height);
361 void RenderBox::paintBackground(GraphicsContext* p, const Color& c, const BackgroundLayer* bgLayer, int clipy, int cliph, int _tx, int _ty, int w, int height)
363 paintBackgroundExtended(p, c, bgLayer, clipy, cliph, _tx, _ty, w, height,
364 borderLeft(), borderRight(), paddingLeft(), paddingRight());
367 static void cacluateBackgroundSize(const BackgroundLayer* bgLayer, int& scaledWidth, int& scaledHeight)
369 CachedImage* bg = bgLayer->backgroundImage();
371 if (bgLayer->isBackgroundSizeSet()) {
372 Length bgWidth = bgLayer->backgroundSize().width;
373 Length bgHeight = bgLayer->backgroundSize().height;
375 if (bgWidth.isPercent())
376 scaledWidth = scaledWidth * bgWidth.value() / 100;
377 else if (bgWidth.isFixed())
378 scaledWidth = bgWidth.value();
379 else if (bgWidth.isAuto()) {
380 // If the width is auto and the height is not, we have to use the appropriate
381 // scale to maintain our aspect ratio.
382 if (bgHeight.isPercent()) {
383 int scaledH = scaledHeight * bgHeight.value() / 100;
384 scaledWidth = bg->imageSize().width() * scaledH / bg->imageSize().height();
385 } else if (bgHeight.isFixed())
386 scaledWidth = bg->imageSize().width() * bgHeight.value() / bg->imageSize().height();
389 if (bgHeight.isPercent())
390 scaledHeight = scaledHeight * bgHeight.value() / 100;
391 else if (bgHeight.isFixed())
392 scaledHeight = bgHeight.value();
393 else if (bgHeight.isAuto()) {
394 // If the height is auto and the width is not, we have to use the appropriate
395 // scale to maintain our aspect ratio.
396 if (bgWidth.isPercent())
397 scaledHeight = bg->imageSize().height() * scaledWidth / bg->imageSize().width();
398 else if (bgWidth.isFixed())
399 scaledHeight = bg->imageSize().height() * bgWidth.value() / bg->imageSize().width();
400 else if (bgWidth.isAuto()) {
401 // If both width and height are auto, we just want to use the image's
403 scaledWidth = bg->imageSize().width();
404 scaledHeight = bg->imageSize().height();
408 scaledWidth = bg->imageSize().width();
409 scaledHeight = bg->imageSize().height();
413 void RenderBox::paintBackgroundExtended(GraphicsContext* p, const Color& c, const BackgroundLayer* bgLayer, int clipy, int cliph,
414 int _tx, int _ty, int w, int h,
415 int bleft, int bright, int pleft, int pright)
417 bool clippedToBorderRadius = false;
418 if (style()->hasBorderRadius()) {
420 p->addRoundedRectClip(IntRect(_tx, _ty, w, h),
421 style()->borderTopLeftRadius(), style()->borderTopRightRadius(),
422 style()->borderBottomLeftRadius(), style()->borderBottomRightRadius());
423 clippedToBorderRadius = true;
426 if (bgLayer->backgroundClip() != BGBORDER) {
427 // Clip to the padding or content boxes as necessary.
428 bool includePadding = bgLayer->backgroundClip() == BGCONTENT;
429 int x = _tx + bleft + (includePadding ? pleft : 0);
430 int y = _ty + borderTop() + (includePadding ? paddingTop() : 0);
431 int width = w - bleft - bright - (includePadding ? pleft + pright : 0);
432 int height = h - borderTop() - borderBottom() - (includePadding ? paddingTop() + paddingBottom() : 0);
434 p->addClip(IntRect(x, y, width, height));
437 CachedImage* bg = bgLayer->backgroundImage();
438 bool shouldPaintBackgroundImage = bg && bg->canRender();
441 // When this style flag is set, change existing background colors and images to a solid white background.
442 // If there's no bg color or image, leave it untouched to avoid affecting transparency.
443 // We don't try to avoid loading the background images, because this style flag is only set
444 // when printing, and at that point we've already loaded the background images anyway. (To avoid
445 // loading the background images we'd have to do this check when applying styles rather than
447 if (style()->forceBackgroundsToWhite()) {
448 // Note that we can't reuse this variable below because the bgColor might be changed
449 bool shouldPaintBackgroundColor = !bgLayer->next() && bgColor.isValid() && bgColor.alpha() > 0;
450 if (shouldPaintBackgroundImage || shouldPaintBackgroundColor) {
451 bgColor = Color::white;
452 shouldPaintBackgroundImage = false;
456 // Only fill with a base color (e.g., white) if we're the root document, since iframes/frames with
457 // no background in the child document should show the parent's background.
458 if (!bgLayer->next() && isRoot() && !(bgColor.isValid() && bgColor.alpha() > 0) && canvas()->view()) {
460 WebCore::Node* elt = document()->ownerElement();
462 if (elt->hasTagName(frameTag))
463 isTransparent = false;
465 // Locate the <body> element using the DOM. This is easier than trying
466 // to crawl around a render tree with potential :before/:after content and
467 // anonymous blocks created by inline <body> tags etc. We can locate the <body>
468 // render object very easily via the DOM.
469 HTMLElement* body = document()->body();
470 isTransparent = !body || !body->hasLocalName(framesetTag); // Can't scroll a frameset document anyway.
473 isTransparent = canvas()->view()->isTransparent();
476 canvas()->view()->useSlowRepaints(); // The parent must show behind the child.
478 bgColor = Color::white;
481 // Paint the color first underneath all images.
482 if (!bgLayer->next() && bgColor.isValid() && bgColor.alpha() > 0) {
483 IntRect rect(_tx, clipy, w, cliph);
484 // If we have an alpha and we are painting the root element, go ahead and blend with white.
485 if (bgColor.alpha() < 0xFF && isRoot() && !canvas()->view()->isTransparent())
486 p->fillRect(rect, Color(Color::white));
487 p->fillRect(rect, bgColor);
490 // no progressive loading of the background image
491 if (shouldPaintBackgroundImage) {
496 int scaledImageWidth, scaledImageHeight;
499 // CSS2 chapter 14.2.1
501 if (bgLayer->backgroundAttachment()) {
503 int hpab = 0, vpab = 0, left = 0, top = 0; // Init to 0 for background-origin of 'border'
504 if (bgLayer->backgroundOrigin() != BGBORDER) {
505 hpab += bleft + bright;
506 vpab += borderTop() + borderBottom();
509 if (bgLayer->backgroundOrigin() == BGCONTENT) {
510 hpab += pleft + pright;
511 vpab += paddingTop() + paddingBottom();
519 scaledImageWidth = pw;
520 scaledImageHeight = ph;
521 cacluateBackgroundSize(bgLayer, scaledImageWidth, scaledImageHeight);
523 EBackgroundRepeat bgr = bgLayer->backgroundRepeat();
524 if ((bgr == NO_REPEAT || bgr == REPEAT_Y) && w > scaledImageWidth) {
525 cw = scaledImageWidth;
526 int xPosition = bgLayer->backgroundXPosition().calcMinValue(pw - scaledImageWidth);
528 cx = _tx + xPosition;
531 if (scaledImageWidth > 0) {
538 // repeat over x or background is wider than box
541 if (scaledImageWidth > 0) {
542 int xPosition = bgLayer->backgroundXPosition().calcMinValue(pw - scaledImageWidth);
543 if ((xPosition > 0) && (bgr == NO_REPEAT)) {
547 sx = scaledImageWidth - (xPosition % scaledImageWidth);
548 sx -= left % scaledImageWidth;
553 if((bgr == NO_REPEAT || bgr == REPEAT_X) && h > scaledImageHeight) {
554 ch = scaledImageHeight;
555 int yPosition = bgLayer->backgroundYPosition().calcMinValue(ph - scaledImageHeight);
557 cy = _ty + yPosition;
560 if (scaledImageHeight > 0) {
568 // repeat over y or background is taller than box
571 if (scaledImageHeight > 0) {
572 int yPosition = bgLayer->backgroundYPosition().calcMinValue(ph - scaledImageHeight);
573 if ((yPosition > 0) && (bgr == NO_REPEAT)) {
577 sy = scaledImageHeight - (yPosition % scaledImageHeight);
578 sy -= top % scaledImageHeight;
585 IntRect vr = viewRect();
587 int ph = vr.height();
588 scaledImageWidth = pw;
589 scaledImageHeight = ph;
590 cacluateBackgroundSize(bgLayer, scaledImageWidth, scaledImageHeight);
591 EBackgroundRepeat bgr = bgLayer->backgroundRepeat();
593 if ((bgr == NO_REPEAT || bgr == REPEAT_Y) && pw > scaledImageWidth) {
594 cw = scaledImageWidth;
595 cx = vr.x() + bgLayer->backgroundXPosition().calcMinValue(pw - scaledImageWidth);
599 if (scaledImageWidth > 0)
600 sx = scaledImageWidth - bgLayer->backgroundXPosition().calcMinValue(pw - scaledImageWidth) % scaledImageWidth;
603 if ((bgr == NO_REPEAT || bgr == REPEAT_X) && ph > scaledImageHeight) {
604 ch = scaledImageHeight;
605 cy = vr.y() + bgLayer->backgroundYPosition().calcMinValue(ph - scaledImageHeight);
609 if (scaledImageHeight > 0)
610 sy = scaledImageHeight - bgLayer->backgroundYPosition().calcMinValue(ph - scaledImageHeight) % scaledImageHeight;
613 IntRect b = intersection(IntRect(cx, cy, cw, ch), IntRect(_tx, _ty, w, h));
622 if (cw > 0 && ch > 0)
623 p->drawTiledImage(bg->image(), IntRect(cx, cy, cw, ch), IntPoint(sx, sy), IntSize(scaledImageWidth, scaledImageHeight));
626 if (bgLayer->backgroundClip() != BGBORDER)
627 p->restore(); // Undo the background clip
629 if (clippedToBorderRadius)
630 p->restore(); // Undo the border radius clip
633 void RenderBox::outlineBox(GraphicsContext* p, int _tx, int _ty, const char* color)
635 p->setPen(Pen(Color(color), 1, Pen::DotLine));
636 p->setFillColor(Color::transparent);
637 p->drawRect(IntRect(_tx, _ty, m_width, m_height));
640 IntRect RenderBox::getOverflowClipRect(int tx, int ty)
642 // XXX When overflow-clip (CSS3) is implemented, we'll obtain the property
644 int bl=borderLeft(),bt=borderTop(),bb=borderBottom(),br=borderRight();
647 int clipw = m_width - bl - br;
648 int cliph = m_height - bt - bb + borderTopExtra() + borderBottomExtra();
650 // Subtract out scrollbars if we have them.
652 clipw -= m_layer->verticalScrollbarWidth();
653 cliph -= m_layer->horizontalScrollbarHeight();
655 return IntRect(clipx,clipy,clipw,cliph);
658 IntRect RenderBox::getClipRect(int tx, int ty)
663 int cliph = m_height;
665 if (!style()->clipLeft().isAuto()) {
666 int c = style()->clipLeft().calcValue(m_width);
671 if (!style()->clipRight().isAuto()) {
672 int w = style()->clipRight().calcValue(m_width);
673 clipw -= m_width - w;
676 if (!style()->clipTop().isAuto()) {
677 int c = style()->clipTop().calcValue(m_height);
682 if (!style()->clipBottom().isAuto()) {
683 int h = style()->clipBottom().calcValue(m_height);
684 cliph -= m_height - h;
687 return IntRect(clipx, clipy, clipw, cliph);
690 int RenderBox::containingBlockWidth() const
692 RenderBlock* cb = containingBlock();
696 return cb->lineWidth(m_y);
698 return cb->contentWidth();
701 bool RenderBox::absolutePosition(int &xPos, int &yPos, bool f)
703 if (style()->position() == FixedPosition)
705 RenderObject *o = container();
706 if (o && o->absolutePosition(xPos, yPos, f)) {
707 yPos += o->borderTopExtra();
708 if (style()->position() == AbsolutePosition && o->isRelPositioned() && o->isInlineFlow()) {
709 // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
710 // box from the rest of the content, but only in the cases where we know we're positioned
711 // relative to the inline itself.
712 RenderFlow* flow = static_cast<RenderFlow*>(o);
715 if (flow->firstLineBox()) {
716 sx = flow->firstLineBox()->xPos();
717 sy = flow->firstLineBox()->yPos();
719 sx = flow->staticX();
720 sy = flow->staticY();
723 bool isInlineType = style()->isOriginalDisplayInlineType();
727 // This is not terribly intuitive, but we have to match other browsers. Despite being a block display type inside
728 // an inline, we still keep our x locked to the left of the relative positioned inline. Arguably the correct
729 // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers
731 if (hasStaticX() && !isInlineType)
732 // Avoid adding in the left border/padding of the containing block twice. Subtract it out.
733 xPos += sx - (containingBlock()->borderLeft() + containingBlock()->paddingLeft());
738 if (o->hasOverflowClip())
739 o->layer()->subtractScrollOffset(xPos, yPos);
741 if (!isInline() || isReplaced()) {
746 if (isRelPositioned())
747 relativePositionOffset(xPos, yPos);
757 void RenderBox::dirtyLineBoxes(bool fullLayout, bool)
759 if (m_inlineBoxWrapper) {
761 m_inlineBoxWrapper->destroy(renderArena());
762 m_inlineBoxWrapper = 0;
765 m_inlineBoxWrapper->dirtyLineBoxes();
769 void RenderBox::position(InlineBox* box, int from, int len, bool reverse, bool override)
771 if (isPositioned()) {
772 // Cache the x position only if we were an INLINE type originally.
773 bool wasInline = style()->isOriginalDisplayInlineType();
774 if (wasInline && hasStaticX()) {
775 // The value is cached in the xPos of the box. We only need this value if
776 // our object was inline originally, since otherwise it would have ended up underneath
778 m_staticX = box->xPos();
780 else if (!wasInline && hasStaticY())
781 // Our object was a block originally, so we make our normal flow position be
782 // just below the line box (as though all the inlines that came before us got
783 // wrapped in an anonymous block, which is what would have happened had we been
784 // in flow). This value was cached in the yPos() of the box.
785 m_staticY = box->yPos();
789 box->destroy(renderArena());
791 else if (isReplaced()) {
794 m_inlineBoxWrapper = box;
798 // For inline replaced elements, this function returns the inline box that owns us. Enables
799 // the replaced RenderObject to quickly determine what line it is contained on and to easily
800 // iterate over structures on the line.
801 InlineBox* RenderBox::inlineBoxWrapper() const
803 return m_inlineBoxWrapper;
806 void RenderBox::deleteLineBoxWrapper()
808 if (m_inlineBoxWrapper) {
809 if (!documentBeingDestroyed())
810 m_inlineBoxWrapper->remove();
811 m_inlineBoxWrapper->destroy(renderArena());
812 m_inlineBoxWrapper = 0;
816 void RenderBox::setInlineBoxWrapper(InlineBox* b)
818 m_inlineBoxWrapper = b;
821 IntRect RenderBox::getAbsoluteRepaintRect()
823 IntRect r = overflowRect(false);
825 if (style()->hasAppearance())
826 // The theme may wish to inflate the rect used when repainting.
827 theme()->adjustRepaintRect(this, r);
828 r.inflate(style()->outlineSize()); // FIXME: Technically the outline inflation could fit within the theme inflation.
830 computeAbsoluteRepaintRect(r);
834 void RenderBox::computeAbsoluteRepaintRect(IntRect& r, bool f)
839 // Apply the relative position offset when invalidating a rectangle. The layer
840 // is translated, but the render box isn't, so we need to do this to get the
841 // right dirty rect. Since this is called from RenderObject::setStyle, the relative position
842 // flag on the RenderObject has been cleared, so use the one on the style().
843 if (style()->position() == RelativePosition && m_layer)
844 m_layer->relativePositionOffset(x,y);
846 if (style()->position()==FixedPosition)
849 RenderObject* o = container();
851 if (style()->position() == AbsolutePosition && o->isRelPositioned() && o->isInlineFlow()) {
852 // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
853 // box from the rest of the content, but only in the cases where we know we're positioned
854 // relative to the inline itself.
855 RenderFlow* flow = static_cast<RenderFlow*>(o);
858 if (flow->firstLineBox()) {
859 sx = flow->firstLineBox()->xPos();
860 sy = flow->firstLineBox()->yPos();
862 sx = flow->staticX();
863 sy = flow->staticY();
866 bool isInlineType = style()->isOriginalDisplayInlineType();
870 // This is not terribly intuitive, but we have to match other browsers. Despite being a block display type inside
871 // an inline, we still keep our x locked to the left of the relative positioned inline. Arguably the correct
872 // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers
874 if (hasStaticX() && !isInlineType)
875 // Avoid adding in the left border/padding of the containing block twice. Subtract it out.
876 x += sx - (containingBlock()->borderLeft() + containingBlock()->paddingLeft());
881 // <body> may not have overflow, since it might be applying its overflow value to the
883 if (o->hasOverflowClip()) {
884 // o->height() is inaccurate if we're in the middle of a layout of |o|, so use the
885 // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint
886 // anyway if its size does change.
887 IntRect boxRect(0, 0, o->layer()->width(), o->layer()->height());
888 o->layer()->subtractScrollOffset(x,y); // For overflow:auto/scroll/hidden.
889 IntRect repaintRect(x, y, r.width(), r.height());
890 r = intersection(repaintRect, boxRect);
897 o->computeAbsoluteRepaintRect(r, f);
901 void RenderBox::repaintDuringLayoutIfMoved(int oldX, int oldY)
905 if (oldX != newX || oldY != newY) {
906 // The child moved. Invalidate the object's old and new positions. We have to do this
907 // since the object may not have gotten a layout.
908 m_x = oldX; m_y = oldY;
910 repaintFloatingDescendants();
911 m_x = newX; m_y = newY;
913 repaintFloatingDescendants();
917 void RenderBox::relativePositionOffset(int &tx, int &ty)
919 if(!style()->left().isAuto())
920 tx += style()->left().calcValue(containingBlockWidth());
921 else if(!style()->right().isAuto())
922 tx -= style()->right().calcValue(containingBlockWidth());
923 if(!style()->top().isAuto())
925 if (!style()->top().isPercent()
926 || containingBlock()->style()->height().isFixed())
927 ty += style()->top().calcValue(containingBlockHeight());
929 else if(!style()->bottom().isAuto())
931 if (!style()->bottom().isPercent()
932 || containingBlock()->style()->height().isFixed())
933 ty -= style()->bottom().calcValue(containingBlockHeight());
937 void RenderBox::calcWidth()
940 calcAbsoluteHorizontal();
943 // The parent box is flexing us, so it has increased or decreased our width. Use the width
944 // from the style context.
945 if (m_overrideSize != -1 && parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
946 && parent()->isFlexingChildren()) {
947 m_width = m_overrideSize;
951 bool inVerticalBox = parent()->isFlexibleBox() && parent()->style()->boxOrient() == VERTICAL;
952 bool stretching = parent()->style()->boxAlign() == BSTRETCH;
953 bool treatAsReplaced = isReplaced() && !isInlineBlockOrInlineTable() &&
954 (!inVerticalBox || !stretching);
957 w = Length( calcReplacedWidth(), Fixed );
959 w = style()->width();
961 Length ml = style()->marginLeft();
962 Length mr = style()->marginRight();
964 RenderBlock *cb = containingBlock();
965 int cw = containingBlockWidth();
972 if (isInline() && !isInlineBlockOrInlineTable()) {
973 // just calculate margins
974 m_marginLeft = ml.calcMinValue(cw);
975 m_marginRight = mr.calcMinValue(cw);
976 if (treatAsReplaced) {
977 m_width = w.calcValue(cw) + borderLeft() + borderRight() + paddingLeft() + paddingRight();
978 m_width = max(m_width, m_minWidth);
983 LengthType widthType, minWidthType, maxWidthType;
984 if (treatAsReplaced) {
985 m_width = w.calcValue(cw) + borderLeft() + borderRight() + paddingLeft() + paddingRight();
986 widthType = w.type();
988 m_width = calcWidthUsing(Width, cw, widthType);
989 int minW = calcWidthUsing(MinWidth, cw, minWidthType);
990 int maxW = style()->maxWidth().value() == undefinedLength
991 ? m_width : calcWidthUsing(MaxWidth, cw, maxWidthType);
993 if (m_width > maxW) {
995 widthType = maxWidthType;
997 if (m_width < minW) {
999 widthType = minWidthType;
1003 if (widthType == Auto) {
1004 m_marginLeft = ml.calcMinValue(cw);
1005 m_marginRight = mr.calcMinValue(cw);
1009 calcHorizontalMargins(ml,mr,cw);
1013 if (cw && cw != m_width + m_marginLeft + m_marginRight && !isFloating() && !isInline() &&
1014 !cb->isFlexibleBox())
1016 if (cb->style()->direction()==LTR)
1017 m_marginRight = cw - m_width - m_marginLeft;
1019 m_marginLeft = cw - m_width - m_marginRight;
1024 int RenderBox::calcWidthUsing(WidthType widthType, int cw, LengthType& lengthType)
1026 int width = m_width;
1028 if (widthType == Width)
1029 w = style()->width();
1030 else if (widthType == MinWidth)
1031 w = style()->minWidth();
1033 w = style()->maxWidth();
1035 lengthType = w.type();
1037 if (w.isIntrinsicOrAuto()) {
1038 int marginLeft = style()->marginLeft().calcMinValue(cw);
1039 int marginRight = style()->marginRight().calcMinValue(cw);
1040 if (cw) width = cw - marginLeft - marginRight;
1042 if (sizesToIntrinsicWidth(widthType)) {
1043 width = max(width, m_minWidth);
1044 width = min(width, m_maxWidth);
1048 width = calcBorderBoxWidth(w.calcValue(cw));
1053 bool RenderBox::sizesToIntrinsicWidth(WidthType widthType) const
1055 // Marquees in WinIE are like a mixture of blocks and inline-blocks. They size as though they're blocks,
1056 // but they allow text to sit on the same line as the marquee.
1057 if (isFloating() || (isCompact() && isInline()) ||
1058 (isInlineBlockOrInlineTable() && !isHTMLMarquee()))
1061 // This code may look a bit strange. Basically width:intrinsic should clamp the size when testing both
1062 // min-width and width. max-width is only clamped if it is also intrinsic.
1063 Length width = widthType == MaxWidth ? style()->maxWidth() : style()->width();
1064 if (width.type() == Intrinsic)
1067 // Children of a horizontal marquee do not fill the container by default.
1068 // FIXME: Need to deal with MAUTO value properly. It could be vertical.
1069 if (parent()->style()->overflow() == OMARQUEE) {
1070 EMarqueeDirection dir = parent()->style()->marqueeDirection();
1071 if (dir == MAUTO || dir == MFORWARD || dir == MBACKWARD || dir == MLEFT || dir == MRIGHT)
1075 // Flexible horizontal boxes lay out children at their intrinsic widths. Also vertical boxes
1076 // that don't stretch their kids lay out their children at their intrinsic widths.
1077 if (parent()->isFlexibleBox() &&
1078 (parent()->style()->boxOrient() == HORIZONTAL || parent()->style()->boxAlign() != BSTRETCH))
1084 void RenderBox::calcHorizontalMargins(const Length& ml, const Length& mr, int cw)
1086 if (isFloating() || isInline()) // Inline blocks/tables and floats don't have their margins increased.
1088 m_marginLeft = ml.calcMinValue(cw);
1089 m_marginRight = mr.calcMinValue(cw);
1093 if ( (ml.isAuto() && mr.isAuto() && m_width<cw) ||
1094 (!ml.isAuto() && !mr.isAuto() &&
1095 containingBlock()->style()->textAlign() == KHTML_CENTER) )
1097 m_marginLeft = (cw - m_width)/2;
1098 if (m_marginLeft<0) m_marginLeft=0;
1099 m_marginRight = cw - m_width - m_marginLeft;
1101 else if ( (mr.isAuto() && m_width<cw) ||
1102 (!ml.isAuto() && containingBlock()->style()->direction() == RTL &&
1103 containingBlock()->style()->textAlign() == KHTML_LEFT))
1105 m_marginLeft = ml.calcValue(cw);
1106 m_marginRight = cw - m_width - m_marginLeft;
1108 else if ( (ml.isAuto() && m_width<cw) ||
1109 (!mr.isAuto() && containingBlock()->style()->direction() == LTR &&
1110 containingBlock()->style()->textAlign() == KHTML_RIGHT))
1112 m_marginRight = mr.calcValue(cw);
1113 m_marginLeft = cw - m_width - m_marginRight;
1117 // this makes auto margins 0 if we failed a m_width<cw test above (css2.1, 10.3.3)
1118 m_marginLeft = ml.calcMinValue(cw);
1119 m_marginRight = mr.calcMinValue(cw);
1124 void RenderBox::calcHeight()
1126 // Cell height is managed by the table and inline non-replaced elements do not support a height property.
1127 if (isTableCell() || (isInline() && !isReplaced()))
1131 calcAbsoluteVertical();
1134 calcVerticalMargins();
1136 // For tables, calculate margins only
1141 bool inHorizontalBox = parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL;
1142 bool stretching = parent()->style()->boxAlign() == BSTRETCH;
1143 bool treatAsReplaced = isReplaced() && !isInlineBlockOrInlineTable() && (!inHorizontalBox || !stretching);
1144 bool checkMinMaxHeight = false;
1146 // The parent box is flexing us, so it has increased or decreased our height. We have to
1147 // grab our cached flexible height.
1148 if (m_overrideSize != -1 && parent()->isFlexibleBox() && parent()->style()->boxOrient() == VERTICAL
1149 && parent()->isFlexingChildren())
1150 h = Length(m_overrideSize - borderTop() - borderBottom() - paddingTop() - paddingBottom(), Fixed);
1151 else if (treatAsReplaced)
1152 h = Length(calcReplacedHeight(), Fixed);
1154 h = style()->height();
1155 checkMinMaxHeight = true;
1158 // Block children of horizontal flexible boxes fill the height of the box.
1159 if (h.isAuto() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
1160 && parent()->isStretchingChildren()) {
1161 h = Length(parent()->contentHeight() - marginTop() - marginBottom() -
1162 borderTop() - paddingTop() - borderBottom() - paddingBottom(), Fixed);
1163 checkMinMaxHeight = false;
1167 if (checkMinMaxHeight) {
1168 height = calcHeightUsing(style()->height());
1171 int minH = calcHeightUsing(style()->minHeight()); // Leave as -1 if unset.
1172 int maxH = style()->maxHeight().value() == undefinedLength ? height : calcHeightUsing(style()->maxHeight());
1175 height = min(maxH, height);
1176 height = max(minH, height);
1179 // The only times we don't check min/max height are when a fixed length has
1180 // been given as an override. Just use that. The value has already been adjusted
1182 height = h.value() + borderTop() + borderBottom() + paddingTop() + paddingBottom();
1187 // Unfurling marquees override with the furled height.
1188 if (style()->overflow() == OMARQUEE && m_layer && m_layer->marquee() &&
1189 m_layer->marquee()->isUnfurlMarquee() && !m_layer->marquee()->isHorizontal()) {
1190 m_layer->marquee()->setEnd(m_height);
1191 m_height = min(m_height, m_layer->marquee()->unfurlPos());
1194 // WinIE quirk: The <html> block always fills the entire canvas in quirks mode. The <body> always fills the
1195 // <html> block in quirks mode. Only apply this quirk if the block is normal flow and no height
1197 if (style()->htmlHacks() && style()->height().isAuto() &&
1198 !isFloatingOrPositioned() && (isRoot() || isBody())) {
1199 int margins = collapsedMarginTop() + collapsedMarginBottom();
1200 int visHeight = canvas()->view()->visibleHeight();
1202 m_height = max(m_height, visHeight - margins);
1204 m_height = max(m_height, visHeight -
1205 (margins + parent()->marginTop() + parent()->marginBottom() +
1206 parent()->borderTop() + parent()->borderBottom() +
1207 parent()->paddingTop() + parent()->paddingBottom()));
1211 int RenderBox::calcHeightUsing(const Length& h)
1217 else if (h.isPercent())
1218 height = calcPercentageHeight(h);
1220 height = calcBorderBoxHeight(height);
1227 int RenderBox::calcPercentageHeight(const Length& height)
1230 bool includeBorderPadding = isTable();
1231 RenderBlock* cb = containingBlock();
1232 if (style()->htmlHacks()) {
1233 // In quirks mode, blocks with auto height are skipped, and we keep looking for an enclosing
1234 // block that may have a specified height and then use it. In strict mode, this violates the
1235 // specification, which states that percentage heights just revert to auto if the containing
1236 // block has an auto height.
1237 for ( ; !cb->isCanvas() && !cb->isBody() && !cb->isTableCell() && !cb->isPositioned() &&
1238 cb->style()->height().isAuto(); cb = cb->containingBlock());
1241 // Table cells violate what the CSS spec says to do with heights. Basically we
1242 // don't care if the cell specified a height or not. We just always make ourselves
1243 // be a percentage of the cell's current content height.
1244 if (cb->isTableCell()) {
1245 result = cb->overrideSize();
1247 // Normally we would let the cell size intrinsically, but scrolling overflow has to be
1248 // treated differently, since WinIE lets scrolled overflow regions shrink as needed.
1249 // While we can't get all cases right, we can at least detect when the cell has a specified
1250 // height or when the table has a specified height. In these cases we want to initially have
1251 // no size and allow the flexing of the table or the cell to its specified height to cause us
1252 // to grow to fill the space. This could end up being wrong in some cases, but it is
1253 // preferable to the alternative (sizing intrinsically and making the row end up too big).
1254 RenderTableCell* cell = static_cast<RenderTableCell*>(cb);
1255 if (scrollsOverflow() &&
1256 (!cell->style()->height().isAuto() || !cell->table()->style()->height().isAuto()))
1260 includeBorderPadding = true;
1263 // Otherwise we only use our percentage height if our containing block had a specified
1265 else if (cb->style()->height().isFixed())
1266 result = cb->calcContentBoxHeight(cb->style()->height().value());
1267 else if (cb->style()->height().isPercent()) {
1268 // We need to recur and compute the percentage height for our containing block.
1269 result = cb->calcPercentageHeight(cb->style()->height());
1271 result = cb->calcContentBoxHeight(result);
1273 else if (cb->isCanvas() || (cb->isBody() && style()->htmlHacks())) {
1274 // Don't allow this to affect the block' m_height member variable, since this
1275 // can get called while the block is still laying out its kids.
1276 int oldHeight = cb->height();
1278 result = cb->contentHeight();
1279 cb->setHeight(oldHeight);
1280 } else if (cb->isRoot() && isPositioned()) {
1281 // Match the positioned objects behavior, which is that positioned objects will fill their viewport
1282 // always. Note we could only hit this case by recurring into calcPercentageHeight on a positioned containing block.
1283 result = cb->calcContentBoxHeight(cb->availableHeight());
1287 result = height.calcValue(result);
1288 if (includeBorderPadding) {
1289 // It is necessary to use the border-box to match WinIE's broken
1290 // box model. This is essential for sizing inside
1291 // table cells using percentage heights.
1292 result -= (borderTop() + paddingTop() + borderBottom() + paddingBottom());
1293 result = max(0, result);
1299 int RenderBox::calcReplacedWidth() const
1301 int width = calcReplacedWidthUsing(Width);
1302 int minW = calcReplacedWidthUsing(MinWidth);
1303 int maxW = style()->maxWidth().value() == undefinedLength ? width : calcReplacedWidthUsing(MaxWidth);
1305 return max(minW, min(width, maxW));
1308 int RenderBox::calcReplacedWidthUsing(WidthType widthType) const
1311 if (widthType == Width)
1312 w = style()->width();
1313 else if (widthType == MinWidth)
1314 w = style()->minWidth();
1316 w = style()->maxWidth();
1320 return calcContentBoxWidth(w.value());
1322 const int cw = containingBlockWidth();
1324 return calcContentBoxWidth(w.calcMinValue(cw));
1328 return intrinsicWidth();
1332 int RenderBox::calcReplacedHeight() const
1334 int height = calcReplacedHeightUsing(Height);
1335 int minH = calcReplacedHeightUsing(MinHeight);
1336 int maxH = style()->maxHeight().value() == undefinedLength ? height : calcReplacedHeightUsing(MaxHeight);
1338 return max(minH, min(height, maxH));
1341 int RenderBox::calcReplacedHeightUsing(HeightType heightType) const
1344 if (heightType == Height)
1345 h = style()->height();
1346 else if (heightType == MinHeight)
1347 h = style()->minHeight();
1349 h = style()->maxHeight();
1353 return calcContentBoxHeight(h.value());
1355 return calcContentBoxHeight(h.calcValue(containingBlock()->availableHeight()));
1357 return intrinsicHeight();
1361 int RenderBox::availableHeight() const
1363 return availableHeightUsing(style()->height());
1366 int RenderBox::availableHeightUsing(const Length& h) const
1369 return calcContentBoxHeight(h.value());
1372 return static_cast<const RenderCanvas*>(this)->view()->visibleHeight();
1374 // We need to stop here, since we don't want to increase the height of the table
1375 // artificially. We're going to rely on this cell getting expanded to some new
1376 // height, and then when we lay out again we'll use the calculation below.
1377 if (isTableCell() && (h.isAuto() || h.isPercent()))
1378 return overrideSize() - (borderLeft() + borderRight() + paddingLeft() + paddingRight());
1381 return calcContentBoxHeight(h.calcValue(containingBlock()->availableHeight()));
1383 return containingBlock()->availableHeight();
1386 void RenderBox::calcVerticalMargins()
1388 if( isTableCell() ) {
1389 // table margins are basically infinite
1390 m_marginTop = TABLECELLMARGIN;
1391 m_marginBottom = TABLECELLMARGIN;
1395 Length tm = style()->marginTop();
1396 Length bm = style()->marginBottom();
1398 // margins are calculated with respect to the _width_ of
1399 // the containing block (8.3)
1400 int cw = containingBlock()->contentWidth();
1402 m_marginTop = tm.calcMinValue(cw);
1403 m_marginBottom = bm.calcMinValue(cw);
1406 void RenderBox::setStaticX(int staticX)
1408 m_staticX = staticX;
1411 void RenderBox::setStaticY(int staticY)
1413 m_staticY = staticY;
1416 void RenderBox::calcAbsoluteHorizontal()
1419 calcAbsoluteHorizontalReplaced();
1425 // FIXME 1: Which RenderObject's 'direction' property should used: the
1426 // containing block (cb) as the spec seems to imply, the parent (parent()) as
1427 // was previously done in calculating the static distances, or ourself, which
1428 // was also previously done for deciding what to override when you had
1429 // over-constrained margins? Also note that the container block is used
1430 // in similar situations in other parts of the RenderBox class (see calcWidth()
1431 // and calcHorizontalMargins()).
1433 // FIXME 2: Should we still deal with these the cases of 'left' or 'right' having
1434 // the type 'static' in determining whether to calculate the static distance?
1435 // NOTE: 'static' is not a legal value for 'left' or 'right' as of CSS 2.1.
1437 // FIXME 3: Can perhaps optimize out cases when max-width/min-width are greater
1438 // than or less than the computed m_width. Be careful of box-sizing and
1439 // percentage issues.
1441 // The following is based off of the W3C Working Draft from April 11, 2006 of
1442 // CSS 2.1: Section 10.3.7 "Absolutely positioned, non-replaced elements"
1443 // <http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width>
1444 // (block-style-comments in this function and in calcAbsoluteHorizontalValues()
1445 // correspond to text from the spec)
1448 // We don't use containingBlock(), since we may be positioned by an enclosing
1449 // relative positioned inline.
1450 const RenderObject* containerBlock = container();
1452 // FIXME: This is incorrect for cases where the container block is a relatively
1453 // positioned inline.
1454 const int containerWidth = containingBlockWidth() + containerBlock->paddingLeft() + containerBlock->paddingRight();
1456 const int bordersPlusPadding = borderLeft() + borderRight() + paddingLeft() + paddingRight();
1457 const Length marginLeft = style()->marginLeft();
1458 const Length marginRight = style()->marginRight();
1459 Length left = style()->left();
1460 Length right = style()->right();
1462 /*---------------------------------------------------------------------------*\
1463 * For the purposes of this section and the next, the term "static position"
1464 * (of an element) refers, roughly, to the position an element would have had
1465 * in the normal flow. More precisely:
1467 * * The static position for 'left' is the distance from the left edge of the
1468 * containing block to the left margin edge of a hypothetical box that would
1469 * have been the first box of the element if its 'position' property had
1470 * been 'static' and 'float' had been 'none'. The value is negative if the
1471 * hypothetical box is to the left of the containing block.
1472 * * The static position for 'right' is the distance from the right edge of the
1473 * containing block to the right margin edge of the same hypothetical box as
1474 * above. The value is positive if the hypothetical box is to the left of the
1475 * containing block's edge.
1477 * But rather than actually calculating the dimensions of that hypothetical box,
1478 * user agents are free to make a guess at its probable position.
1480 * For the purposes of calculating the static position, the containing block of
1481 * fixed positioned elements is the initial containing block instead of the
1482 * viewport, and all scrollable boxes should be assumed to be scrolled to their
1484 \*---------------------------------------------------------------------------*/
1487 // Calculate the static distance if needed.
1488 if (left.isAuto() && right.isAuto()) {
1489 if (containerBlock->style()->direction() == LTR) {
1490 // 'm_staticX' should already have been set through layout of the parent.
1491 int staticPosition = m_staticX - containerBlock->borderLeft();
1492 for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent())
1493 staticPosition += po->xPos();
1494 left.setValue(Fixed, staticPosition);
1496 RenderObject* po = parent();
1497 // 'm_staticX' should already have been set through layout of the parent.
1498 int staticPosition = m_staticX + containerWidth + containerBlock->borderRight() - po->width();
1499 for (; po && po != containerBlock; po = po->parent())
1500 staticPosition -= po->xPos();
1501 right.setValue(Fixed, staticPosition);
1505 // Calculate constraint equation values for 'width' case.
1506 calcAbsoluteHorizontalValues(style()->width(), containerBlock, containerWidth, bordersPlusPadding,
1507 left, right, marginLeft, marginRight,
1508 m_width, m_marginLeft, m_marginRight, m_x);
1510 // Calculate constraint equation values for 'max-width' case.calcContentBoxWidth(width.calcValue(containerWidth));
1511 if (style()->maxWidth().value() != undefinedLength) {
1517 calcAbsoluteHorizontalValues(style()->maxWidth(), containerBlock, containerWidth, bordersPlusPadding,
1518 left, right, marginLeft, marginRight,
1519 maxWidth, maxMarginLeft, maxMarginRight, maxXPos);
1521 if (m_width > maxWidth) {
1523 m_marginLeft = maxMarginLeft;
1524 m_marginRight = maxMarginRight;
1529 // Calculate constraint equation values for 'min-width' case.
1530 if (style()->minWidth().value()) {
1536 calcAbsoluteHorizontalValues(style()->minWidth(), containerBlock, containerWidth, bordersPlusPadding,
1537 left, right, marginLeft, marginRight,
1538 minWidth, minMarginLeft, minMarginRight, minXPos);
1540 if (m_width < minWidth) {
1542 m_marginLeft = minMarginLeft;
1543 m_marginRight = minMarginRight;
1548 // Put m_width into correct form.
1549 m_width += bordersPlusPadding;
1552 void RenderBox::calcAbsoluteHorizontalValues(Length width, const RenderObject* containerBlock,
1553 const int containerWidth, const int bordersPlusPadding,
1554 const Length left, const Length right, const Length marginLeft, const Length marginRight,
1555 int& widthValue, int& marginLeftValue, int& marginRightValue, int& xPos)
1557 // 'left' and 'right' cannot both be 'auto' because one would of been
1558 // converted to the static postion already
1559 ASSERT(!(left.isAuto() && right.isAuto()));
1563 bool widthIsAuto = width.isIntrinsicOrAuto();
1564 bool leftIsAuto = left.isAuto();
1565 bool rightIsAuto = right.isAuto();
1567 if (!leftIsAuto && !widthIsAuto && !rightIsAuto) {
1568 /*-----------------------------------------------------------------------*\
1569 * If none of the three is 'auto': If both 'margin-left' and 'margin-
1570 * right' are 'auto', solve the equation under the extra constraint that
1571 * the two margins get equal values, unless this would make them negative,
1572 * in which case when direction of the containing block is 'ltr' ('rtl'),
1573 * set 'margin-left' ('margin-right') to zero and solve for 'margin-right'
1574 * ('margin-left'). If one of 'margin-left' or 'margin-right' is 'auto',
1575 * solve the equation for that value. If the values are over-constrained,
1576 * ignore the value for 'left' (in case the 'direction' property of the
1577 * containing block is 'rtl') or 'right' (in case 'direction' is 'ltr')
1578 * and solve for that value.
1579 \*-----------------------------------------------------------------------*/
1580 // NOTE: It is not necessary to solve for 'right' in the over constrained
1581 // case because the value is not used for any further calculations.
1583 leftValue = left.calcValue(containerWidth);
1584 widthValue = calcContentBoxWidth(width.calcValue(containerWidth));
1586 const int availableSpace = containerWidth - (leftValue + widthValue + right.calcValue(containerWidth) + bordersPlusPadding);
1588 // Margins are now the only unknown
1589 if (marginLeft.isAuto() && marginRight.isAuto()) {
1590 // Both margins auto, solve for equality
1591 if (availableSpace >= 0) {
1592 marginLeftValue = availableSpace / 2; // split the diference
1593 marginRightValue = availableSpace - marginLeftValue; // account for odd valued differences
1596 if (containerBlock->style()->direction() == LTR) {
1597 marginLeftValue = 0;
1598 marginRightValue = availableSpace; // will be negative
1600 marginLeftValue = availableSpace; // will be negative
1601 marginRightValue = 0;
1604 } else if (marginLeft.isAuto()) {
1605 // Solve for left margin
1606 marginRightValue = marginRight.calcValue(containerWidth);
1607 marginLeftValue = availableSpace - marginRightValue;
1608 } else if (marginRight.isAuto()) {
1609 // Solve for right margin
1610 marginLeftValue = marginLeft.calcValue(containerWidth);
1611 marginRightValue = availableSpace - marginLeftValue;
1613 // Over-constrained, solve for left if direction is RTL
1614 marginLeftValue = marginLeft.calcValue(containerWidth);
1615 marginRightValue = marginRight.calcValue(containerWidth);
1617 // see FIXME 1 -- used to be "this->style()->direction()"
1618 if (containerBlock->style()->direction() == RTL)
1619 leftValue = (availableSpace + leftValue) - marginLeftValue - marginRightValue;
1622 /*--------------------------------------------------------------------*\
1623 * Otherwise, set 'auto' values for 'margin-left' and 'margin-right'
1624 * to 0, and pick the one of the following six rules that applies.
1626 * 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the
1627 * width is shrink-to-fit. Then solve for 'left'
1629 * OMIT RULE 2 AS IT SHOULD NEVER BE HIT
1630 * ------------------------------------------------------------------
1631 * 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if
1632 * the 'direction' property of the containing block is 'ltr' set
1633 * 'left' to the static position, otherwise set 'right' to the
1634 * static position. Then solve for 'left' (if 'direction is 'rtl')
1635 * or 'right' (if 'direction' is 'ltr').
1636 * ------------------------------------------------------------------
1638 * 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the
1639 * width is shrink-to-fit . Then solve for 'right'
1640 * 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve
1642 * 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve
1644 * 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve
1647 * Calculation of the shrink-to-fit width is similar to calculating the
1648 * width of a table cell using the automatic table layout algorithm.
1649 * Roughly: calculate the preferred width by formatting the content
1650 * without breaking lines other than where explicit line breaks occur,
1651 * and also calculate the preferred minimum width, e.g., by trying all
1652 * possible line breaks. CSS 2.1 does not define the exact algorithm.
1653 * Thirdly, calculate the available width: this is found by solving
1654 * for 'width' after setting 'left' (in case 1) or 'right' (in case 3)
1657 * Then the shrink-to-fit width is:
1658 * min(max(preferred minimum width, available width), preferred width).
1659 \*--------------------------------------------------------------------*/
1660 // NOTE: For rules 3 and 6 it is not necessary to solve for 'right'
1661 // because the value is not used for any further calculations.
1663 // Calculate margins, 'auto' margins are ignored.
1664 marginLeftValue = marginLeft.calcMinValue(containerWidth);
1665 marginRightValue = marginRight.calcMinValue(containerWidth);
1667 const int availableSpace = containerWidth - (marginLeftValue + marginRightValue + bordersPlusPadding);
1669 // FIXME: Is there a faster way to find the correct case?
1670 // Use rule/case that applies.
1671 if (leftIsAuto && widthIsAuto && !rightIsAuto) {
1672 // RULE 1: (use shrink-to-fit for width, and solve of left)
1673 int rightValue = right.calcValue(containerWidth);
1675 // FIXME: would it be better to have shrink-to-fit in one step?
1676 int preferredWidth = m_maxWidth - bordersPlusPadding;
1677 int preferredMinWidth = m_minWidth - bordersPlusPadding;
1678 int availableWidth = availableSpace - rightValue;
1679 widthValue = min(max(preferredMinWidth, availableWidth), preferredWidth);
1680 leftValue = availableSpace - (widthValue + rightValue);
1681 } else if (!leftIsAuto && widthIsAuto && rightIsAuto) {
1682 // RULE 3: (use shrink-to-fit for width, and no need solve of right)
1683 leftValue = left.calcValue(containerWidth);
1685 // FIXME: would it be better to have shrink-to-fit in one step?
1686 int preferredWidth = m_maxWidth - bordersPlusPadding;
1687 int preferredMinWidth = m_minWidth - bordersPlusPadding;
1688 int availableWidth = availableSpace - leftValue;
1689 widthValue = min(max(preferredMinWidth, availableWidth), preferredWidth);
1690 } else if (leftIsAuto && !width.isAuto() && !rightIsAuto) {
1691 // RULE 4: (solve for left)
1692 widthValue = calcContentBoxWidth(width.calcValue(containerWidth));
1693 leftValue = availableSpace - (widthValue + right.calcValue(containerWidth));
1694 } else if (!leftIsAuto && widthIsAuto && !rightIsAuto) {
1695 // RULE 5: (solve for width)
1696 leftValue = left.calcValue(containerWidth);
1697 widthValue = availableSpace - (leftValue + right.calcValue(containerWidth));
1698 } else if (!leftIsAuto&& !widthIsAuto && rightIsAuto) {
1699 // RULE 6: (no need solve for right)
1700 leftValue = left.calcValue(containerWidth);
1701 widthValue = calcContentBoxWidth(width.calcValue(containerWidth));
1705 // Use computed values to calculate the horizontal position.
1706 xPos = leftValue + marginLeftValue + containerBlock->borderLeft();
1709 void RenderBox::calcAbsoluteVertical()
1712 calcAbsoluteVerticalReplaced();
1716 // The following is based off of the W3C Working Draft from April 11, 2006 of
1717 // CSS 2.1: Section 10.6.4 "Absolutely positioned, non-replaced elements"
1718 // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-non-replaced-height>
1719 // (block-style-comments in this function and in calcAbsoluteVerticalValues()
1720 // correspond to text from the spec)
1723 // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
1724 const RenderObject* containerBlock = container();
1726 // Even in strict mode (where we don't grow the root to fill the viewport) other browsers
1727 // position as though the root fills the viewport.
1728 const int containerHeight = containerBlock->isRoot() ? containerBlock->availableHeight() : (containerBlock->height() - containerBlock->borderTop() - containerBlock->borderBottom());
1730 const int bordersPlusPadding = borderTop() + borderBottom() + paddingTop() + paddingBottom();
1731 const Length marginTop = style()->marginTop();
1732 const Length marginBottom = style()->marginBottom();
1733 Length top = style()->top();
1734 Length bottom = style()->bottom();
1736 /*---------------------------------------------------------------------------*\
1737 * For the purposes of this section and the next, the term "static position"
1738 * (of an element) refers, roughly, to the position an element would have had
1739 * in the normal flow. More precisely, the static position for 'top' is the
1740 * distance from the top edge of the containing block to the top margin edge
1741 * of a hypothetical box that would have been the first box of the element if
1742 * its 'position' property had been 'static' and 'float' had been 'none'. The
1743 * value is negative if the hypothetical box is above the containing block.
1745 * But rather than actually calculating the dimensions of that hypothetical
1746 * box, user agents are free to make a guess at its probable position.
1748 * For the purposes of calculating the static position, the containing block
1749 * of fixed positioned elements is the initial containing block instead of
1751 \*---------------------------------------------------------------------------*/
1754 // Calculate the static distance if needed.
1755 if (top.isAuto() && bottom.isAuto()) {
1756 // m_staticY should already have been set through layout of the parent()
1757 int staticTop = m_staticY - containerBlock->borderTop();
1758 for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) {
1759 if (!po->isTableRow())
1760 staticTop += po->yPos();
1762 top.setValue(Fixed, staticTop);
1766 int height; // Needed to compute overflow.
1768 // Calculate constraint equation values for 'height' case.
1769 calcAbsoluteVerticalValues(style()->height(), containerBlock, containerHeight, bordersPlusPadding,
1770 top, bottom, marginTop, marginBottom,
1771 height, m_marginTop, m_marginBottom, m_y);
1773 // Avoid doing any work in the common case (where the values of min-height and max-height are their defaults).
1776 // Calculate constraint equation values for 'max-height' case.
1777 if (style()->maxHeight().value() != undefinedLength) {
1780 int maxMarginBottom;
1783 calcAbsoluteVerticalValues(style()->maxHeight(), containerBlock, containerHeight, bordersPlusPadding,
1784 top, bottom, marginTop, marginBottom,
1785 maxHeight, maxMarginTop, maxMarginBottom, maxYPos);
1787 if (height > maxHeight) {
1789 m_marginTop = maxMarginTop;
1790 m_marginBottom = maxMarginBottom;
1795 // Calculate constraint equation values for 'min-height' case.
1796 if (style()->minHeight().value()) {
1799 int minMarginBottom;
1802 calcAbsoluteVerticalValues(style()->minHeight(), containerBlock, containerHeight, bordersPlusPadding,
1803 top, bottom, marginTop, marginBottom,
1804 minHeight, minMarginTop, minMarginBottom, minYPos);
1806 if (height < minHeight) {
1808 m_marginTop = minMarginTop;
1809 m_marginBottom = minMarginBottom;
1814 // If our natural height exceeds the new height once we've set it, then we
1815 // need to make sure to update overflow to track the spillout.
1816 if (m_height > height)
1817 setOverflowHeight(m_height);
1819 // Set final height value.
1823 void RenderBox::calcAbsoluteVerticalValues(Length height, const RenderObject* containerBlock,
1824 const int containerHeight, const int bordersPlusPadding,
1825 const Length top, const Length bottom, const Length marginTop, const Length marginBottom,
1826 int& heightValue, int& marginTopValue, int& marginBottomValue, int& yPos)
1828 // 'top' and 'bottom' cannot both be 'auto' because 'top would of been
1829 // converted to the static position in calcAbsoluteVertical()
1830 ASSERT(!(top.isAuto() && bottom.isAuto()));
1832 int contentHeight = m_height - bordersPlusPadding;
1836 bool heightIsAuto = height.isAuto();
1837 bool topIsAuto = top.isAuto();
1838 bool bottomIsAuto = bottom.isAuto();
1840 // Height is never unsolved for tables.
1841 if (isTable() && heightIsAuto) {
1842 height.setValue(Fixed, contentHeight);
1843 heightIsAuto = false;
1844 } else if (!heightIsAuto)
1845 contentHeight = min(contentHeight, calcContentBoxHeight(height.calcValue(containerHeight)));
1847 if (!topIsAuto && !heightIsAuto && !bottomIsAuto) {
1848 /*-----------------------------------------------------------------------*\
1849 * If none of the three are 'auto': If both 'margin-top' and 'margin-
1850 * bottom' are 'auto', solve the equation under the extra constraint that
1851 * the two margins get equal values. If one of 'margin-top' or 'margin-
1852 * bottom' is 'auto', solve the equation for that value. If the values
1853 * are over-constrained, ignore the value for 'bottom' and solve for that
1855 \*-----------------------------------------------------------------------*/
1856 // NOTE: It is not necessary to solve for 'bottom' in the over constrained
1857 // case because the value is not used for any further calculations.
1859 heightValue = calcContentBoxHeight(height.calcValue(containerHeight));
1860 topValue = top.calcValue(containerHeight);
1862 const int availableSpace = containerHeight - (topValue + heightValue + bottom.calcValue(containerHeight) + bordersPlusPadding);
1864 // Margins are now the only unknown
1865 if (marginTop.isAuto() && marginBottom.isAuto()) {
1866 // Both margins auto, solve for equality
1867 // NOTE: This may result in negative values.
1868 marginTopValue = availableSpace / 2; // split the diference
1869 marginBottomValue = availableSpace - marginTopValue; // account for odd valued differences
1870 } else if (marginTop.isAuto()) {
1871 // Solve for top margin
1872 marginBottomValue = marginBottom.calcValue(containerHeight);
1873 marginTopValue = availableSpace - marginBottomValue;
1874 } else if (marginBottom.isAuto()) {
1875 // Solve for bottom margin
1876 marginTopValue = marginTop.calcValue(containerHeight);
1877 marginBottomValue = availableSpace - marginTopValue;
1879 // Over-constrained, (no need solve for bottom)
1880 marginTopValue = marginTop.calcValue(containerHeight);
1881 marginBottomValue = marginBottom.calcValue(containerHeight);
1884 /*--------------------------------------------------------------------*\
1885 * Otherwise, set 'auto' values for 'margin-top' and 'margin-bottom'
1886 * to 0, and pick the one of the following six rules that applies.
1888 * 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then
1889 * the height is based on the content, and solve for 'top'.
1891 * OMIT RULE 2 AS IT SHOULD NEVER BE HIT
1892 * ------------------------------------------------------------------
1893 * 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then
1894 * set 'top' to the static position, and solve for 'bottom'.
1895 * ------------------------------------------------------------------
1897 * 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then
1898 * the height is based on the content, and solve for 'bottom'.
1899 * 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', and
1901 * 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', and
1902 * solve for 'height'.
1903 * 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', and
1904 * solve for 'bottom'.
1905 \*--------------------------------------------------------------------*/
1906 // NOTE: For rules 3 and 6 it is not necessary to solve for 'bottom'
1907 // because the value is not used for any further calculations.
1909 // Calculate margins, 'auto' margins are ignored.
1910 marginTopValue = marginTop.calcMinValue(containerHeight);
1911 marginBottomValue = marginBottom.calcMinValue(containerHeight);
1913 const int availableSpace = containerHeight - (marginTopValue + marginBottomValue + bordersPlusPadding);
1915 // Use rule/case that applies.
1916 if (topIsAuto && heightIsAuto && !bottomIsAuto) {
1917 // RULE 1: (height is content based, solve of top)
1918 heightValue = contentHeight;
1919 topValue = availableSpace - (heightValue + bottom.calcValue(containerHeight));
1920 } else if (!topIsAuto && heightIsAuto && bottomIsAuto) {
1921 // RULE 3: (height is content based, no need solve of bottom)
1922 topValue = top.calcValue(containerHeight);
1923 heightValue = contentHeight;
1924 } else if (topIsAuto && !heightIsAuto && !bottomIsAuto) {
1925 // RULE 4: (solve of top)
1926 heightValue = calcContentBoxHeight(height.calcValue(containerHeight));
1927 topValue = availableSpace - (heightValue + bottom.calcValue(containerHeight));
1928 } else if (!topIsAuto && heightIsAuto && !bottomIsAuto) {
1929 // RULE 5: (solve of height)
1930 topValue = top.calcValue(containerHeight);
1931 heightValue = availableSpace - (topValue + bottom.calcValue(containerHeight));
1932 } else if (!topIsAuto && !heightIsAuto && bottomIsAuto) {
1933 // RULE 6: (no need solve of bottom)
1934 heightValue = calcContentBoxHeight(height.calcValue(containerHeight));
1935 topValue = top.calcValue(containerHeight);
1939 // Make final adjustments to height.
1940 if (!(contentHeight < heightValue) && !(hasOverflowClip() && contentHeight > heightValue))
1941 heightValue = contentHeight;
1943 // Do not allow the height to be negative. This can happen when someone
1944 // specifies both top and bottom but the containing block height is less
1945 // than top, e.g., top: 20px, bottom: 0, containing block height 16.
1946 heightValue = max(0, heightValue + bordersPlusPadding);
1948 // Use computed values to calculate the vertical position.
1949 yPos = topValue + marginTopValue + containerBlock->borderTop();
1952 void RenderBox::calcAbsoluteHorizontalReplaced()
1954 // The following is based off of the W3C Working Draft from April 11, 2006 of
1955 // CSS 2.1: Section 10.3.8 "Absolutly positioned, replaced elements"
1956 // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-width>
1957 // (block-style-comments in this function correspond to text from the spec and
1958 // the numbers correspond to numbers in spec)
1960 // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
1961 const RenderObject* containerBlock = container();
1962 const int containerWidth = containingBlockWidth() + containerBlock->paddingLeft() + containerBlock->paddingRight();
1964 // Variables to solve.
1965 Length left = style()->left();
1966 Length right = style()->right();
1967 Length marginLeft = style()->marginLeft();
1968 Length marginRight = style()->marginRight();
1971 /*-----------------------------------------------------------------------*\
1972 * 1. The used value of 'width' is determined as for inline replaced
1974 \*-----------------------------------------------------------------------*/
1975 // NOTE: This value of width is FINAL in that the min/max width calculations
1976 // are dealt with in calcReplacedWidth(). This means that the steps to produce
1977 // correct max/min in the non-replaced version, are not necessary.
1978 m_width = calcReplacedWidth() + borderLeft() + borderRight() + paddingLeft() + paddingRight();
1979 const int availableSpace = containerWidth - m_width;
1981 /*-----------------------------------------------------------------------*\
1982 * 2. If both 'left' and 'right' have the value 'auto', then if 'direction'
1983 * of the containing block is 'ltr', set 'left' to the static position;
1984 * else if 'direction' is 'rtl', set 'right' to the static position.
1985 \*-----------------------------------------------------------------------*/
1987 if (left.isAuto() && right.isAuto()) {
1989 if (containerBlock->style()->direction() == LTR) {
1990 // 'm_staticX' should already have been set through layout of the parent.
1991 int staticPosition = m_staticX - containerBlock->borderLeft();
1992 for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent())
1993 staticPosition += po->xPos();
1994 left.setValue(Fixed, staticPosition);
1996 RenderObject* po = parent();
1997 // 'm_staticX' should already have been set through layout of the parent.
1998 int staticPosition = m_staticX + containerWidth + containerBlock->borderRight() - po->width();
1999 for (; po && po != containerBlock; po = po->parent())
2000 staticPosition -= po->xPos();
2001 right.setValue(Fixed, staticPosition);
2005 /*-----------------------------------------------------------------------*\
2006 * 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left'
2007 * or 'margin-right' with '0'.
2008 \*-----------------------------------------------------------------------*/
2009 if (left.isAuto() || right.isAuto()) {
2010 if (marginLeft.isAuto())
2011 marginLeft.setValue(Fixed, 0);
2012 if (marginRight.isAuto())
2013 marginRight.setValue(Fixed, 0);
2016 /*-----------------------------------------------------------------------*\
2017 * 4. If at this point both 'margin-left' and 'margin-right' are still
2018 * 'auto', solve the equation under the extra constraint that the two
2019 * margins must get equal values, unless this would make them negative,
2020 * in which case when the direction of the containing block is 'ltr'
2021 * ('rtl'), set 'margin-left' ('margin-right') to zero and solve for
2022 * 'margin-right' ('margin-left').
2023 \*-----------------------------------------------------------------------*/
2027 if (marginLeft.isAuto() && marginRight.isAuto()) {
2028 // 'left' and 'right' cannot be 'auto' due to step 3
2029 ASSERT(!(left.isAuto() && right.isAuto()));
2031 leftValue = left.calcValue(containerWidth);
2032 rightValue = right.calcValue(containerWidth);
2034 int difference = availableSpace - (leftValue + rightValue);
2035 if (difference > 0) {
2036 m_marginLeft = difference / 2; // split the diference
2037 m_marginRight = difference - m_marginLeft; // account for odd valued differences
2040 if (containerBlock->style()->direction() == LTR) {
2042 m_marginRight = difference; // will be negative
2044 m_marginLeft = difference; // will be negative
2049 /*-----------------------------------------------------------------------*\
2050 * 5. If at this point there is an 'auto' left, solve the equation for
2052 \*-----------------------------------------------------------------------*/
2053 } else if (left.isAuto()) {
2054 m_marginLeft = marginLeft.calcValue(containerWidth);
2055 m_marginRight = marginRight.calcValue(containerWidth);
2056 rightValue = right.calcValue(containerWidth);
2059 leftValue = availableSpace - (rightValue + m_marginLeft + m_marginRight);
2060 } else if (right.isAuto()) {
2061 m_marginLeft = marginLeft.calcValue(containerWidth);
2062 m_marginRight = marginRight.calcValue(containerWidth);
2063 leftValue = left.calcValue(containerWidth);
2065 // Solve for 'right'
2066 rightValue = availableSpace - (leftValue + m_marginLeft + m_marginRight);
2067 } else if (marginLeft.isAuto()) {
2068 m_marginRight = marginRight.calcValue(containerWidth);
2069 leftValue = left.calcValue(containerWidth);
2070 rightValue = right.calcValue(containerWidth);
2072 // Solve for 'margin-left'
2073 m_marginLeft = availableSpace - (leftValue + rightValue + m_marginRight);
2074 } else if (marginRight.isAuto()) {
2075 m_marginLeft = marginLeft.calcValue(containerWidth);
2076 leftValue = left.calcValue(containerWidth);
2077 rightValue = right.calcValue(containerWidth);
2079 // Solve for 'margin-right'
2080 m_marginRight = availableSpace - (leftValue + rightValue + m_marginLeft);
2083 /*-----------------------------------------------------------------------*\
2084 * 6. If at this point the values are over-constrained, ignore the value
2085 * for either 'left' (in case the 'direction' property of the
2086 * containing block is 'rtl') or 'right' (in case 'direction' is
2087 * 'ltr') and solve for that value.
2088 \*-----------------------------------------------------------------------*/
2089 // NOTE: It is not necessary to solve for 'right' when the direction is
2090 // LTR because the value is not used.
2091 int totalWidth = m_width + leftValue + rightValue + m_marginLeft + m_marginRight;
2093 if (totalWidth > containerWidth && (containerBlock->style()->direction() == RTL))
2094 leftValue = containerWidth - (totalWidth - leftValue);
2097 // Use computed values to caluculate the horizontal position.
2098 m_x = leftValue + m_marginLeft + containerBlock->borderLeft();
2101 void RenderBox::calcAbsoluteVerticalReplaced()
2103 // The following is based off of the W3C Working Draft from April 11, 2006 of
2104 // CSS 2.1: Section 10.6.5 "Absolutly positioned, replaced elements"
2105 // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-height>
2106 // (block-style-comments in this function correspond to text from the spec and
2107 // the numbers correspond to numbers in spec)
2109 // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
2110 const RenderObject* containerBlock = container();
2112 // Even in strict mode (where we don't grow the root to fill the viewport)
2113 // other browsers position as though the root fills the viewport.
2114 const int containerHeight = containerBlock->isRoot() ? containerBlock->availableHeight() : (containerBlock->height() - containerBlock->borderTop() - containerBlock->borderBottom());
2116 // Variables to solve.
2117 Length top = style()->top();
2118 Length bottom = style()->bottom();
2119 Length marginTop = style()->marginTop();
2120 Length marginBottom = style()->marginBottom();
2123 /*-----------------------------------------------------------------------*\
2124 * 1. The used value of 'height' is determined as for inline replaced
2126 \*-----------------------------------------------------------------------*/
2127 // NOTE: This value of height is FINAL in that the min/max height calculations
2128 // are dealt with in calcReplacedHeight(). This means that the steps to produce
2129 // correct max/min in the non-replaced version, are not necessary.
2130 int heightValue = calcReplacedHeight() + borderTop() + borderBottom() + paddingTop() + paddingBottom();
2131 int availableSpace = containerHeight - heightValue;
2133 /*-----------------------------------------------------------------------*\
2134 * 2. If both 'top' and 'bottom' have the value 'auto', replace 'top'
2135 * with the element's static position.
2136 \*-----------------------------------------------------------------------*/
2138 if (top.isAuto() && bottom.isAuto()) {
2139 // m_staticY should already have been set through layout of the parent().
2140 int staticTop = m_staticY - containerBlock->borderTop();
2141 for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) {
2142 if (!po->isTableRow())
2143 staticTop += po->yPos();
2145 top.setValue(Fixed, staticTop);
2148 /*-----------------------------------------------------------------------*\
2149 * 3. If 'bottom' is 'auto', replace any 'auto' on 'margin-top' or
2150 * 'margin-bottom' with '0'.
2151 \*-----------------------------------------------------------------------*/
2152 // FIXME: The spec. says that this step should only be taken when bottom is
2153 // auto, but if only top is auto, this makes step 4 impossible.
2154 if (top.isAuto() || bottom.isAuto()) {
2155 if (marginTop.isAuto())
2156 marginTop.setValue(Fixed, 0);
2157 if (marginBottom.isAuto())
2158 marginBottom.setValue(Fixed, 0);
2161 /*-----------------------------------------------------------------------*\
2162 * 4. If at this point both 'margin-top' and 'margin-bottom' are still
2163 * 'auto', solve the equation under the extra constraint that the two
2164 * margins must get equal values.
2165 \*-----------------------------------------------------------------------*/
2169 if (marginTop.isAuto() && marginBottom.isAuto()) {
2170 // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combinded.
2171 ASSERT(!(top.isAuto() && bottom.isAuto()));
2173 topValue = top.calcValue(containerHeight);
2174 bottomValue = bottom.calcValue(containerHeight);
2176 int difference = availableSpace - (topValue + bottomValue);
2177 // NOTE: This may result in negative values.
2178 m_marginTop = difference / 2; // split the difference
2179 m_marginBottom = difference - m_marginTop; // account for odd valued differences
2181 /*-----------------------------------------------------------------------*\
2182 * 5. If at this point there is only one 'auto' left, solve the equation
2184 \*-----------------------------------------------------------------------*/
2185 } else if (top.isAuto()) {
2186 m_marginTop = marginTop.calcValue(containerHeight);
2187 m_marginBottom = marginBottom.calcValue(containerHeight);
2188 bottomValue = bottom.calcValue(containerHeight);
2191 topValue = availableSpace - (bottomValue + m_marginTop + m_marginBottom);
2192 } else if (bottom.isAuto()) {
2193 m_marginTop = marginTop.calcValue(containerHeight);
2194 m_marginBottom = marginBottom.calcValue(containerHeight);
2195 topValue = top.calcValue(containerHeight);
2197 // Solve for 'bottom'
2198 // NOTE: It is not necessary to solve for 'bottom' because we don't ever
2200 } else if (marginTop.isAuto()) {
2201 m_marginBottom = marginBottom.calcValue(containerHeight);
2202 topValue = top.calcValue(containerHeight);
2203 bottomValue = bottom.calcValue(containerHeight);
2205 // Solve for 'margin-top'
2206 m_marginTop = availableSpace - (topValue + bottomValue + m_marginBottom);
2207 } else if (marginBottom.isAuto()) {
2208 m_marginTop = marginTop.calcValue(containerHeight);
2209 topValue = top.calcValue(containerHeight);
2210 bottomValue = bottom.calcValue(containerHeight);
2212 // Solve for 'margin-bottom'
2213 m_marginBottom = availableSpace - (topValue + bottomValue + m_marginTop);
2216 /*-----------------------------------------------------------------------*\
2217 * 6. If at this point the values are over-constrained, ignore the value
2218 * for 'bottom' and solve for that value.
2219 \*-----------------------------------------------------------------------*/
2220 // NOTE: It is not necessary to do this step because we don't end up using
2221 // the value of 'bottom' regardless of whether the values are over-constrained
2225 // Make final adjustments to height.
2226 int contentHeight = m_height;
2227 if ((contentHeight < heightValue) || (hasOverflowClip() && contentHeight > heightValue))
2228 contentHeight = heightValue;
2230 // Do not allow the height to be negative. This can happen when someone
2231 // specifies both top and bottom but the containing block height is less
2232 // than top, e.g., top: 20px, bottom: 0, containing block height 16.
2233 heightValue = max(0, contentHeight);
2235 // If our content height exceeds the new height once we've set it, then we
2236 // need to make sure to update overflow to track the spillout.
2237 if (m_height > heightValue)
2238 setOverflowHeight(m_height);
2240 // Set final values.
2241 m_height = heightValue;
2243 // Use computed values to caluculate the vertical position.
2244 m_y = topValue + m_marginTop + containerBlock->borderTop();
2247 IntRect RenderBox::caretRect(int offset, EAffinity affinity, int* extraWidthToEndOfLine)
2249 // FIXME: Is it OK to check only first child instead of picking
2250 // right child based on offset? Is it OK to pass the same offset
2251 // along to the child instead of offset 0 or whatever?
2253 // propagate it downwards to its children, someone will feel responsible
2254 if (RenderObject* child = firstChild()) {
2255 IntRect result = child->caretRect(offset, affinity, extraWidthToEndOfLine);
2256 if (!result.isEmpty())
2260 // if not, use the extents of this box
2261 // offset 0 means left, offset 1 means right
2262 // FIXME: What about border and padding?
2263 const int caretWidth = 1;
2264 IntRect rect(xPos(), yPos(), caretWidth, m_height);
2266 rect.move(IntSize(m_width - caretWidth, 0));
2267 if (InlineBox* box = inlineBoxWrapper()) {
2268 RootInlineBox* rootBox = box->root();
2269 int top = rootBox->topOverflow();
2271 rect.setHeight(rootBox->bottomOverflow() - top);
2274 // If height of box is smaller than font height, use the latter one,
2275 // otherwise the caret might become invisible.
2277 // Also, if the box is not a replaced element, always use the font height.
2278 // This prevents the "big caret" bug described in:
2279 // <rdar://problem/3777804> Deleting all content in a document can result in giant tall-as-window insertion point
2281 // FIXME: ignoring :first-line, missing good reason to take care of
2282 int fontHeight = style()->font().height();
2283 if (fontHeight > rect.height() || !isReplaced())
2284 rect.setHeight(fontHeight);
2286 RenderObject* cb = containingBlock();
2288 if (!cb || !cb->absolutePosition(cbx, cby))
2289 // No point returning a relative position.
2292 if (extraWidthToEndOfLine)
2293 *extraWidthToEndOfLine = xPos() + m_width - rect.right();
2295 rect.move(cbx, cby);
2299 int RenderBox::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
2301 return includeSelf ? m_height : 0;
2304 int RenderBox::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
2306 return includeSelf ? m_width : 0;
2309 int RenderBox::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
2311 return includeSelf ? 0 : m_width;