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 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 "RenderTableCell.h"
36 #include "HTMLNames.h"
37 #include "RenderArena.h"
38 #include "RenderCanvas.h"
39 #include "RenderFlexibleBox.h"
40 #include "RenderTheme.h"
48 using namespace HTMLNames;
50 #define TABLECELLMARGIN -0x4000
52 RenderBox::RenderBox(WebCore::Node* 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())
83 case AbsolutePosition:
90 if (_style->isFloating())
93 if (_style->position() == RelativePosition)
94 setRelPositioned(true);
97 // We also handle <body> and <html>, whose overflow applies to the viewport.
98 if (_style->overflow() != OVISIBLE && !isRoot() && (!isBody() || !document()->isHTMLDocument()) &&
99 (isRenderBlock() || isTableRow() || isTableSection()))
100 setHasOverflowClip();
102 if (requiresLayer()) {
104 m_layer = new (renderArena()) RenderLayer(this);
105 m_layer->insertOnlyThisLayer();
106 if (parent() && containingBlock())
107 m_layer->updateLayerPositions();
110 else if (m_layer && !isRoot() && !isCanvas()) {
111 assert(m_layer->parent());
112 RenderLayer *layer = m_layer;
114 layer->removeOnlyThisLayer();
118 m_layer->styleChanged();
120 // Set the text color if we're the body.
122 element()->document()->setTextColor(_style->color());
124 if (style()->outlineWidth() > 0 && style()->outlineSize() > maximalOutlineSize(PaintPhaseOutline))
125 static_cast<RenderCanvas*>(document()->renderer())->setMaximalOutlineSize(style()->outlineSize());
128 RenderBox::~RenderBox()
132 void RenderBox::destroy()
134 // A lot of the code in this funtion is just pasted into
135 // RenderWidget::destroy. If anything in this function changes,
136 // be sure to fix RenderWidget::destroy() as well.
138 RenderLayer* layer = m_layer;
139 RenderArena* arena = renderArena();
141 // This must be done before we destroy the RenderObject.
143 layer->clearClipRect();
145 RenderObject::destroy();
148 layer->destroy(arena);
151 int RenderBox::contentWidth() const
153 int w = m_width - borderLeft() - borderRight();
154 w -= paddingLeft() + paddingRight();
156 if (includeScrollbarSize())
157 w -= m_layer->verticalScrollbarWidth();
162 int RenderBox::contentHeight() const
164 int h = m_height - borderTop() - borderBottom();
165 h -= paddingTop() + paddingBottom();
167 if (includeScrollbarSize())
168 h -= m_layer->horizontalScrollbarHeight();
173 int RenderBox::overrideWidth() const
175 return m_overrideSize == -1 ? m_width : m_overrideSize;
178 int RenderBox::overrideHeight() const
180 return m_overrideSize == -1 ? m_height : m_overrideSize;
183 void RenderBox::setPos( int xPos, int yPos )
185 if (xPos == m_x && yPos == m_y)
186 return; // Optimize for the case where we don't move at all.
188 m_x = xPos; m_y = yPos;
191 int RenderBox::width() const
196 int RenderBox::height() const
201 int RenderBox::calcBorderBoxWidth(int w) const
203 int toAdd = borderLeft() + borderRight() + paddingLeft() + paddingRight();
204 if (style()->boxSizing() == CONTENT_BOX)
206 return max(w, toAdd);
209 int RenderBox::calcBorderBoxHeight(int h) const
211 int toAdd = borderTop() + borderBottom() + paddingTop() + paddingBottom();
212 if (style()->boxSizing() == CONTENT_BOX)
214 return max(h, toAdd);
217 int RenderBox::calcContentBoxWidth(int w) const
219 if (style()->boxSizing() == BORDER_BOX)
220 w -= (borderLeft() + borderRight() + paddingLeft() + paddingRight());
224 int RenderBox::calcContentBoxHeight(int h) const
226 if (style()->boxSizing() == BORDER_BOX)
227 h -= (borderTop() + borderBottom() + paddingTop() + paddingBottom());
232 bool RenderBox::nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty, HitTestAction action)
238 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
239 // FIXME: We have to skip over inline flows, since they can show up inside table rows
240 // at the moment (a demoted inline <form> for example). If we ever implement a
241 // table-specific hit-test method (which we should do for performance reasons anyway),
242 // then we can remove this check.
243 if (!child->layer() && !child->isInlineFlow() && child->nodeAtPoint(info, x, y, tx, ty, action)) {
249 // Check our bounds next. For this purpose always assume that we can only be hit in the
250 // foreground phase (which is true for replaced elements like images).
251 if (action == HitTestForeground && IntRect(tx, ty, m_width, m_height).contains(x, y)) {
259 // --------------------- painting stuff -------------------------------
261 void RenderBox::paint(PaintInfo& i, int _tx, int _ty)
266 // default implementation. Just pass paint through to the children
267 for (RenderObject* child = firstChild(); child; child = child->nextSibling())
268 child->paint(i, _tx, _ty);
271 void RenderBox::paintRootBoxDecorations(PaintInfo& i, int _tx, int _ty)
273 const BackgroundLayer* bgLayer = style()->backgroundLayers();
274 Color bgColor = style()->backgroundColor();
275 if (document()->isHTMLDocument() && !style()->hasBackground()) {
276 // Locate the <body> element using the DOM. This is easier than trying
277 // to crawl around a render tree with potential :before/:after content and
278 // anonymous blocks created by inline <body> tags etc. We can locate the <body>
279 // render object very easily via the DOM.
280 HTMLElement* body = document()->body();
281 RenderObject* bodyObject = (body && body->hasLocalName(bodyTag)) ? body->renderer() : 0;
283 bgLayer = bodyObject->style()->backgroundLayers();
284 bgColor = bodyObject->style()->backgroundColor();
292 if (canvas()->view()) {
293 rw = canvas()->view()->contentsWidth();
294 rh = canvas()->view()->contentsHeight();
297 rw = canvas()->width();
298 rh = canvas()->height();
301 int bx = _tx - marginLeft();
302 int by = _ty - marginTop();
303 int bw = max(w + marginLeft() + marginRight() + borderLeft() + borderRight(), rw);
304 int bh = max(h + marginTop() + marginBottom() + borderTop() + borderBottom(), rh);
307 // " The background of the box generated by the root element covers the entire canvas."
308 // hence, paint the background even in the margin areas (unlike for every other element!)
309 // I just love these little inconsistencies .. :-( (Dirk)
310 int my = max(by, i.r.y());
312 paintBackgrounds(i.p, bgColor, bgLayer, my, i.r.height(), bx, by, bw, bh);
314 if (style()->hasBorder() && style()->display() != INLINE)
315 paintBorder( i.p, _tx, _ty, w, h, style() );
318 void RenderBox::paintBoxDecorations(PaintInfo& i, int _tx, int _ty)
320 if (!shouldPaintWithinRoot(i))
324 return paintRootBoxDecorations(i, _tx, _ty);
327 int h = height() + borderTopExtra() + borderBottomExtra();
328 _ty -= borderTopExtra();
330 int my = max(_ty, i.r.y());
333 mh = max(0, h - (i.r.y() - _ty));
335 mh = min(i.r.height(), h);
337 // If we have a native theme appearance, paint that before painting our background.
338 // The theme will tell us whether or not we should also paint the CSS background.
339 bool themePainted = style()->hasAppearance() && !theme()->paint(this, i, IntRect(_tx, _ty, w, h));
341 // The <body> only paints its background if the root element has defined a background
342 // independent of the body. Go through the DOM to get to the root element's render object,
343 // since the root could be inline and wrapped in an anonymous block.
344 if (!isBody() || !document()->isHTMLDocument() || document()->documentElement()->renderer()->style()->hasBackground())
345 paintBackgrounds(i.p, style()->backgroundColor(), style()->backgroundLayers(), my, mh, _tx, _ty, w, h);
348 // The theme will tell us whether or not we should also paint the CSS border.
349 if ((!style()->hasAppearance() || (!themePainted && theme()->paintBorderOnly(this, i, IntRect(_tx, _ty, w, h)))) && style()->hasBorder())
350 paintBorder(i.p, _tx, _ty, w, h, style());
353 void RenderBox::paintBackgrounds(GraphicsContext* p, const Color& c, const BackgroundLayer* bgLayer, int clipy, int cliph, int _tx, int _ty, int w, int height)
355 if (!bgLayer) return;
356 paintBackgrounds(p, c, bgLayer->next(), clipy, cliph, _tx, _ty, w, height);
357 paintBackground(p, c, bgLayer, clipy, cliph, _tx, _ty, w, height);
360 void RenderBox::paintBackground(GraphicsContext* p, const Color& c, const BackgroundLayer* bgLayer, int clipy, int cliph, int _tx, int _ty, int w, int height)
362 paintBackgroundExtended(p, c, bgLayer, clipy, cliph, _tx, _ty, w, height,
363 borderLeft(), borderRight(), paddingLeft(), paddingRight());
366 static void cacluateBackgroundSize(const BackgroundLayer* bgLayer, int& scaledWidth, int& scaledHeight)
368 CachedImage* bg = bgLayer->backgroundImage();
370 if (bgLayer->isBackgroundSizeSet()) {
371 Length bgWidth = bgLayer->backgroundSize().width;
372 Length bgHeight = bgLayer->backgroundSize().height;
374 if (bgWidth.isPercent())
375 scaledWidth = scaledWidth * bgWidth.value() / 100;
376 else if (bgWidth.isFixed())
377 scaledWidth = bgWidth.value();
378 else if (bgWidth.isAuto()) {
379 // If the width is auto and the height is not, we have to use the appropriate
380 // scale to maintain our aspect ratio.
381 if (bgHeight.isPercent()) {
382 int scaledH = scaledHeight * bgHeight.value() / 100;
383 scaledWidth = bg->imageSize().width() * scaledH / bg->imageSize().height();
384 } else if (bgHeight.isFixed())
385 scaledWidth = bg->imageSize().width() * bgHeight.value() / bg->imageSize().height();
388 if (bgHeight.isPercent())
389 scaledHeight = scaledHeight * bgHeight.value() / 100;
390 else if (bgHeight.isFixed())
391 scaledHeight = bgHeight.value();
392 else if (bgHeight.isAuto()) {
393 // If the height is auto and the width is not, we have to use the appropriate
394 // scale to maintain our aspect ratio.
395 if (bgWidth.isPercent())
396 scaledHeight = bg->imageSize().height() * scaledWidth / bg->imageSize().width();
397 else if (bgWidth.isFixed())
398 scaledHeight = bg->imageSize().height() * bgWidth.value() / bg->imageSize().width();
399 else if (bgWidth.isAuto()) {
400 // If both width and height are auto, we just want to use the image's
402 scaledWidth = bg->imageSize().width();
403 scaledHeight = bg->imageSize().height();
407 scaledWidth = bg->imageSize().width();
408 scaledHeight = bg->imageSize().height();
412 void RenderBox::paintBackgroundExtended(GraphicsContext* p, const Color& c, const BackgroundLayer* bgLayer, int clipy, int cliph,
413 int _tx, int _ty, int w, int h,
414 int bleft, int bright, int pleft, int pright)
416 bool clippedToBorderRadius = false;
417 if (style()->hasBorderRadius()) {
419 p->addRoundedRectClip(IntRect(_tx, _ty, w, h),
420 style()->borderTopLeftRadius(), style()->borderTopRightRadius(),
421 style()->borderBottomLeftRadius(), style()->borderBottomRightRadius());
422 clippedToBorderRadius = true;
425 if (bgLayer->backgroundClip() != BGBORDER) {
426 // Clip to the padding or content boxes as necessary.
427 bool includePadding = bgLayer->backgroundClip() == BGCONTENT;
428 int x = _tx + bleft + (includePadding ? pleft : 0);
429 int y = _ty + borderTop() + (includePadding ? paddingTop() : 0);
430 int width = w - bleft - bright - (includePadding ? pleft + pright : 0);
431 int height = h - borderTop() - borderBottom() - (includePadding ? paddingTop() + paddingBottom() : 0);
433 p->addClip(IntRect(x, y, width, height));
436 CachedImage* bg = bgLayer->backgroundImage();
437 bool shouldPaintBackgroundImage = bg && bg->canRender();
440 // When this style flag is set, change existing background colors and images to a solid white background.
441 // If there's no bg color or image, leave it untouched to avoid affecting transparency.
442 // We don't try to avoid loading the background images, because this style flag is only set
443 // when printing, and at that point we've already loaded the background images anyway. (To avoid
444 // loading the background images we'd have to do this check when applying styles rather than
446 if (style()->forceBackgroundsToWhite()) {
447 // Note that we can't reuse this variable below because the bgColor might be changed
448 bool shouldPaintBackgroundColor = !bgLayer->next() && bgColor.isValid() && bgColor.alpha() > 0;
449 if (shouldPaintBackgroundImage || shouldPaintBackgroundColor) {
450 bgColor = Color::white;
451 shouldPaintBackgroundImage = false;
455 // Only fill with a base color (e.g., white) if we're the root document, since iframes/frames with
456 // no background in the child document should show the parent's background.
457 if (!bgLayer->next() && isRoot() && !(bgColor.isValid() && bgColor.alpha() > 0) && canvas()->view()) {
459 WebCore::Node* elt = document()->ownerElement();
461 if (elt->hasTagName(frameTag))
462 isTransparent = false;
464 // Locate the <body> element using the DOM. This is easier than trying
465 // to crawl around a render tree with potential :before/:after content and
466 // anonymous blocks created by inline <body> tags etc. We can locate the <body>
467 // render object very easily via the DOM.
468 HTMLElement* body = document()->body();
469 isTransparent = !body || !body->hasLocalName(framesetTag); // Can't scroll a frameset document anyway.
472 isTransparent = canvas()->view()->isTransparent();
475 canvas()->view()->useSlowRepaints(); // The parent must show behind the child.
477 bgColor = Color::white;
480 // Paint the color first underneath all images.
481 if (!bgLayer->next() && bgColor.isValid() && bgColor.alpha() > 0) {
482 IntRect rect(_tx, clipy, w, cliph);
483 // If we have an alpha and we are painting the root element, go ahead and blend with white.
484 if (bgColor.alpha() < 0xFF && isRoot() && !canvas()->view()->isTransparent())
485 p->fillRect(rect, Color(Color::white));
486 p->fillRect(rect, bgColor);
489 // no progressive loading of the background image
490 if (shouldPaintBackgroundImage) {
495 int scaledImageWidth, scaledImageHeight;
498 // CSS2 chapter 14.2.1
500 if (bgLayer->backgroundAttachment()) {
502 int hpab = 0, vpab = 0, left = 0, top = 0; // Init to 0 for background-origin of 'border'
503 if (bgLayer->backgroundOrigin() != BGBORDER) {
504 hpab += bleft + bright;
505 vpab += borderTop() + borderBottom();
508 if (bgLayer->backgroundOrigin() == BGCONTENT) {
509 hpab += pleft + pright;
510 vpab += paddingTop() + paddingBottom();
518 scaledImageWidth = pw;
519 scaledImageHeight = ph;
520 cacluateBackgroundSize(bgLayer, scaledImageWidth, scaledImageHeight);
522 EBackgroundRepeat bgr = bgLayer->backgroundRepeat();
523 if ((bgr == NO_REPEAT || bgr == REPEAT_Y) && w > scaledImageWidth) {
524 cw = scaledImageWidth;
525 int xPosition = bgLayer->backgroundXPosition().calcMinValue(pw - scaledImageWidth);
527 cx = _tx + xPosition;
530 if (scaledImageWidth > 0) {
537 // repeat over x or background is wider than box
540 if (scaledImageWidth > 0) {
541 int xPosition = bgLayer->backgroundXPosition().calcMinValue(pw - scaledImageWidth);
542 if ((xPosition > 0) && (bgr == NO_REPEAT)) {
546 sx = scaledImageWidth - (xPosition % scaledImageWidth);
547 sx -= left % scaledImageWidth;
552 if((bgr == NO_REPEAT || bgr == REPEAT_X) && h > scaledImageHeight) {
553 ch = scaledImageHeight;
554 int yPosition = bgLayer->backgroundYPosition().calcMinValue(ph - scaledImageHeight);
556 cy = _ty + yPosition;
559 if (scaledImageHeight > 0) {
567 // repeat over y or background is taller than box
570 if (scaledImageHeight > 0) {
571 int yPosition = bgLayer->backgroundYPosition().calcMinValue(ph - scaledImageHeight);
572 if ((yPosition > 0) && (bgr == NO_REPEAT)) {
576 sy = scaledImageHeight - (yPosition % scaledImageHeight);
577 sy -= top % scaledImageHeight;
584 IntRect vr = viewRect();
586 int ph = vr.height();
587 scaledImageWidth = pw;
588 scaledImageHeight = ph;
589 cacluateBackgroundSize(bgLayer, scaledImageWidth, scaledImageHeight);
590 EBackgroundRepeat bgr = bgLayer->backgroundRepeat();
592 if ((bgr == NO_REPEAT || bgr == REPEAT_Y) && pw > scaledImageWidth) {
593 cw = scaledImageWidth;
594 cx = vr.x() + bgLayer->backgroundXPosition().calcMinValue(pw - scaledImageWidth);
598 if (scaledImageWidth > 0)
599 sx = scaledImageWidth - bgLayer->backgroundXPosition().calcMinValue(pw - scaledImageWidth) % scaledImageWidth;
602 if ((bgr == NO_REPEAT || bgr == REPEAT_X) && ph > scaledImageHeight) {
603 ch = scaledImageHeight;
604 cy = vr.y() + bgLayer->backgroundYPosition().calcMinValue(ph - scaledImageHeight);
608 if (scaledImageHeight > 0)
609 sy = scaledImageHeight - bgLayer->backgroundYPosition().calcMinValue(ph - scaledImageHeight) % scaledImageHeight;
612 IntRect b = intersection(IntRect(cx, cy, cw, ch), IntRect(_tx, _ty, w, h));
621 if (cw > 0 && ch > 0)
622 p->drawTiledImage(bg->image(), IntRect(cx, cy, cw, ch), IntPoint(sx, sy), IntSize(scaledImageWidth, scaledImageHeight));
625 if (bgLayer->backgroundClip() != BGBORDER)
626 p->restore(); // Undo the background clip
628 if (clippedToBorderRadius)
629 p->restore(); // Undo the border radius clip
632 void RenderBox::outlineBox(GraphicsContext* p, int _tx, int _ty, const char* color)
634 p->setPen(Pen(Color(color), 1, Pen::DotLine));
635 p->setFillColor(Color::transparent);
636 p->drawRect(IntRect(_tx, _ty, m_width, m_height));
639 IntRect RenderBox::getOverflowClipRect(int tx, int ty)
641 // XXX When overflow-clip (CSS3) is implemented, we'll obtain the property
643 int bl=borderLeft(),bt=borderTop(),bb=borderBottom(),br=borderRight();
646 int clipw = m_width - bl - br;
647 int cliph = m_height - bt - bb + borderTopExtra() + borderBottomExtra();
649 // Subtract out scrollbars if we have them.
651 clipw -= m_layer->verticalScrollbarWidth();
652 cliph -= m_layer->horizontalScrollbarHeight();
654 return IntRect(clipx,clipy,clipw,cliph);
657 IntRect RenderBox::getClipRect(int tx, int ty)
662 int cliph = m_height;
664 if (!style()->clipLeft().isAuto()) {
665 int c = style()->clipLeft().calcValue(m_width);
670 if (!style()->clipRight().isAuto()) {
671 int w = style()->clipRight().calcValue(m_width);
672 clipw -= m_width - w;
675 if (!style()->clipTop().isAuto()) {
676 int c = style()->clipTop().calcValue(m_height);
681 if (!style()->clipBottom().isAuto()) {
682 int h = style()->clipBottom().calcValue(m_height);
683 cliph -= m_height - h;
686 return IntRect(clipx, clipy, clipw, cliph);
689 int RenderBox::containingBlockWidth() const
691 RenderBlock* cb = containingBlock();
695 return cb->lineWidth(m_y);
697 return cb->contentWidth();
700 bool RenderBox::absolutePosition(int &xPos, int &yPos, bool f)
702 if (style()->position() == FixedPosition)
704 RenderObject *o = container();
705 if (o && o->absolutePosition(xPos, yPos, f)) {
706 yPos += o->borderTopExtra();
707 if (style()->position() == AbsolutePosition && o->isRelPositioned() && o->isInlineFlow()) {
708 // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
709 // box from the rest of the content, but only in the cases where we know we're positioned
710 // relative to the inline itself.
711 RenderFlow* flow = static_cast<RenderFlow*>(o);
714 if (flow->firstLineBox()) {
715 sx = flow->firstLineBox()->xPos();
716 sy = flow->firstLineBox()->yPos();
718 sx = flow->staticX();
719 sy = flow->staticY();
722 bool isInlineType = style()->isOriginalDisplayInlineType();
726 // This is not terribly intuitive, but we have to match other browsers. Despite being a block display type inside
727 // an inline, we still keep our x locked to the left of the relative positioned inline. Arguably the correct
728 // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers
730 if (hasStaticX() && !isInlineType)
731 // Avoid adding in the left border/padding of the containing block twice. Subtract it out.
732 xPos += sx - (containingBlock()->borderLeft() + containingBlock()->paddingLeft());
737 if (o->hasOverflowClip())
738 o->layer()->subtractScrollOffset(xPos, yPos);
740 if (!isInline() || isReplaced()) {
745 if (isRelPositioned())
746 relativePositionOffset(xPos, yPos);
756 void RenderBox::dirtyLineBoxes(bool fullLayout, bool)
758 if (m_inlineBoxWrapper) {
760 m_inlineBoxWrapper->destroy(renderArena());
761 m_inlineBoxWrapper = 0;
764 m_inlineBoxWrapper->dirtyLineBoxes();
768 void RenderBox::position(InlineBox* box, int from, int len, bool reverse, bool override)
770 if (isPositioned()) {
771 // Cache the x position only if we were an INLINE type originally.
772 bool wasInline = style()->isOriginalDisplayInlineType();
773 if (wasInline && hasStaticX()) {
774 // The value is cached in the xPos of the box. We only need this value if
775 // our object was inline originally, since otherwise it would have ended up underneath
777 m_staticX = box->xPos();
779 else if (!wasInline && hasStaticY())
780 // Our object was a block originally, so we make our normal flow position be
781 // just below the line box (as though all the inlines that came before us got
782 // wrapped in an anonymous block, which is what would have happened had we been
783 // in flow). This value was cached in the yPos() of the box.
784 m_staticY = box->yPos();
788 box->destroy(renderArena());
790 else if (isReplaced()) {
793 m_inlineBoxWrapper = box;
797 // For inline replaced elements, this function returns the inline box that owns us. Enables
798 // the replaced RenderObject to quickly determine what line it is contained on and to easily
799 // iterate over structures on the line.
800 InlineBox* RenderBox::inlineBoxWrapper() const
802 return m_inlineBoxWrapper;
805 void RenderBox::deleteLineBoxWrapper()
807 if (m_inlineBoxWrapper) {
808 if (!documentBeingDestroyed())
809 m_inlineBoxWrapper->remove();
810 m_inlineBoxWrapper->destroy(renderArena());
811 m_inlineBoxWrapper = 0;
815 void RenderBox::setInlineBoxWrapper(InlineBox* b)
817 m_inlineBoxWrapper = b;
820 IntRect RenderBox::getAbsoluteRepaintRect()
822 IntRect r = overflowRect(false);
824 if (style()->hasAppearance())
825 // The theme may wish to inflate the rect used when repainting.
826 theme()->adjustRepaintRect(this, r);
827 r.inflate(style()->outlineSize()); // FIXME: Technically the outline inflation could fit within the theme inflation.
829 computeAbsoluteRepaintRect(r);
833 void RenderBox::computeAbsoluteRepaintRect(IntRect& r, bool f)
838 // Apply the relative position offset when invalidating a rectangle. The layer
839 // is translated, but the render box isn't, so we need to do this to get the
840 // right dirty rect. Since this is called from RenderObject::setStyle, the relative position
841 // flag on the RenderObject has been cleared, so use the one on the style().
842 if (style()->position() == RelativePosition && m_layer)
843 m_layer->relativePositionOffset(x,y);
845 if (style()->position()==FixedPosition)
848 RenderObject* o = container();
850 if (style()->position() == AbsolutePosition && o->isRelPositioned() && o->isInlineFlow()) {
851 // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
852 // box from the rest of the content, but only in the cases where we know we're positioned
853 // relative to the inline itself.
854 RenderFlow* flow = static_cast<RenderFlow*>(o);
857 if (flow->firstLineBox()) {
858 sx = flow->firstLineBox()->xPos();
859 sy = flow->firstLineBox()->yPos();
861 sx = flow->staticX();
862 sy = flow->staticY();
865 bool isInlineType = style()->isOriginalDisplayInlineType();
869 // This is not terribly intuitive, but we have to match other browsers. Despite being a block display type inside
870 // an inline, we still keep our x locked to the left of the relative positioned inline. Arguably the correct
871 // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers
873 if (hasStaticX() && !isInlineType)
874 // Avoid adding in the left border/padding of the containing block twice. Subtract it out.
875 x += sx - (containingBlock()->borderLeft() + containingBlock()->paddingLeft());
880 // <body> may not have overflow, since it might be applying its overflow value to the
882 if (o->hasOverflowClip()) {
883 // o->height() is inaccurate if we're in the middle of a layout of |o|, so use the
884 // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint
885 // anyway if its size does change.
886 IntRect boxRect(0, 0, o->layer()->width(), o->layer()->height());
887 o->layer()->subtractScrollOffset(x,y); // For overflow:auto/scroll/hidden.
888 IntRect repaintRect(x, y, r.width(), r.height());
889 r = intersection(repaintRect, boxRect);
896 o->computeAbsoluteRepaintRect(r, f);
900 void RenderBox::repaintDuringLayoutIfMoved(int oldX, int oldY)
904 if (oldX != newX || oldY != newY) {
905 // The child moved. Invalidate the object's old and new positions. We have to do this
906 // since the object may not have gotten a layout.
907 m_x = oldX; m_y = oldY;
909 repaintFloatingDescendants();
910 m_x = newX; m_y = newY;
912 repaintFloatingDescendants();
916 void RenderBox::relativePositionOffset(int &tx, int &ty)
918 if(!style()->left().isAuto())
919 tx += style()->left().calcValue(containingBlockWidth());
920 else if(!style()->right().isAuto())
921 tx -= style()->right().calcValue(containingBlockWidth());
922 if(!style()->top().isAuto())
924 if (!style()->top().isPercent()
925 || containingBlock()->style()->height().isFixed())
926 ty += style()->top().calcValue(containingBlockHeight());
928 else if(!style()->bottom().isAuto())
930 if (!style()->bottom().isPercent()
931 || containingBlock()->style()->height().isFixed())
932 ty -= style()->bottom().calcValue(containingBlockHeight());
936 void RenderBox::calcWidth()
939 calcAbsoluteHorizontal();
942 // The parent box is flexing us, so it has increased or decreased our width. Use the width
943 // from the style context.
944 if (m_overrideSize != -1 && parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
945 && parent()->isFlexingChildren()) {
946 m_width = m_overrideSize;
950 bool inVerticalBox = parent()->isFlexibleBox() && parent()->style()->boxOrient() == VERTICAL;
951 bool stretching = parent()->style()->boxAlign() == BSTRETCH;
952 bool treatAsReplaced = isReplaced() && !isInlineBlockOrInlineTable() &&
953 (!inVerticalBox || !stretching);
956 w = Length( calcReplacedWidth(), Fixed );
958 w = style()->width();
960 Length ml = style()->marginLeft();
961 Length mr = style()->marginRight();
963 RenderBlock *cb = containingBlock();
964 int cw = containingBlockWidth();
971 if (isInline() && !isInlineBlockOrInlineTable()) {
972 // just calculate margins
973 m_marginLeft = ml.calcMinValue(cw);
974 m_marginRight = mr.calcMinValue(cw);
975 if (treatAsReplaced) {
976 m_width = w.calcValue(cw) + borderLeft() + borderRight() + paddingLeft() + paddingRight();
977 m_width = max(m_width, m_minWidth);
982 LengthType widthType, minWidthType, maxWidthType;
983 if (treatAsReplaced) {
984 m_width = w.calcValue(cw) + borderLeft() + borderRight() + paddingLeft() + paddingRight();
985 widthType = w.type();
987 m_width = calcWidthUsing(Width, cw, widthType);
988 int minW = calcWidthUsing(MinWidth, cw, minWidthType);
989 int maxW = style()->maxWidth().value() == undefinedLength
990 ? m_width : calcWidthUsing(MaxWidth, cw, maxWidthType);
992 if (m_width > maxW) {
994 widthType = maxWidthType;
996 if (m_width < minW) {
998 widthType = minWidthType;
1002 if (widthType == Auto) {
1003 m_marginLeft = ml.calcMinValue(cw);
1004 m_marginRight = mr.calcMinValue(cw);
1008 calcHorizontalMargins(ml,mr,cw);
1012 if (cw && cw != m_width + m_marginLeft + m_marginRight && !isFloating() && !isInline() &&
1013 !cb->isFlexibleBox())
1015 if (cb->style()->direction()==LTR)
1016 m_marginRight = cw - m_width - m_marginLeft;
1018 m_marginLeft = cw - m_width - m_marginRight;
1023 int RenderBox::calcWidthUsing(WidthType widthType, int cw, LengthType& lengthType)
1025 int width = m_width;
1027 if (widthType == Width)
1028 w = style()->width();
1029 else if (widthType == MinWidth)
1030 w = style()->minWidth();
1032 w = style()->maxWidth();
1034 lengthType = w.type();
1036 if (w.isIntrinsicOrAuto()) {
1037 int marginLeft = style()->marginLeft().calcMinValue(cw);
1038 int marginRight = style()->marginRight().calcMinValue(cw);
1039 if (cw) width = cw - marginLeft - marginRight;
1041 if (sizesToIntrinsicWidth(widthType)) {
1042 width = max(width, m_minWidth);
1043 width = min(width, m_maxWidth);
1047 width = calcBorderBoxWidth(w.calcValue(cw));
1052 bool RenderBox::sizesToIntrinsicWidth(WidthType widthType) const
1054 // Marquees in WinIE are like a mixture of blocks and inline-blocks. They size as though they're blocks,
1055 // but they allow text to sit on the same line as the marquee.
1056 if (isFloating() || (isCompact() && isInline()) ||
1057 (isInlineBlockOrInlineTable() && !isHTMLMarquee()))
1060 // This code may look a bit strange. Basically width:intrinsic should clamp the size when testing both
1061 // min-width and width. max-width is only clamped if it is also intrinsic.
1062 Length width = widthType == MaxWidth ? style()->maxWidth() : style()->width();
1063 if (width.type() == Intrinsic)
1066 // Children of a horizontal marquee do not fill the container by default.
1067 // FIXME: Need to deal with MAUTO value properly. It could be vertical.
1068 if (parent()->style()->overflow() == OMARQUEE) {
1069 EMarqueeDirection dir = parent()->style()->marqueeDirection();
1070 if (dir == MAUTO || dir == MFORWARD || dir == MBACKWARD || dir == MLEFT || dir == MRIGHT)
1074 // Flexible horizontal boxes lay out children at their intrinsic widths. Also vertical boxes
1075 // that don't stretch their kids lay out their children at their intrinsic widths.
1076 if (parent()->isFlexibleBox() &&
1077 (parent()->style()->boxOrient() == HORIZONTAL || parent()->style()->boxAlign() != BSTRETCH))
1083 void RenderBox::calcHorizontalMargins(const Length& ml, const Length& mr, int cw)
1085 if (isFloating() || isInline()) // Inline blocks/tables and floats don't have their margins increased.
1087 m_marginLeft = ml.calcMinValue(cw);
1088 m_marginRight = mr.calcMinValue(cw);
1092 if ( (ml.isAuto() && mr.isAuto() && m_width<cw) ||
1093 (!ml.isAuto() && !mr.isAuto() &&
1094 containingBlock()->style()->textAlign() == KHTML_CENTER) )
1096 m_marginLeft = (cw - m_width)/2;
1097 if (m_marginLeft<0) m_marginLeft=0;
1098 m_marginRight = cw - m_width - m_marginLeft;
1100 else if ( (mr.isAuto() && m_width<cw) ||
1101 (!ml.isAuto() && containingBlock()->style()->direction() == RTL &&
1102 containingBlock()->style()->textAlign() == KHTML_LEFT))
1104 m_marginLeft = ml.calcValue(cw);
1105 m_marginRight = cw - m_width - m_marginLeft;
1107 else if ( (ml.isAuto() && m_width<cw) ||
1108 (!mr.isAuto() && containingBlock()->style()->direction() == LTR &&
1109 containingBlock()->style()->textAlign() == KHTML_RIGHT))
1111 m_marginRight = mr.calcValue(cw);
1112 m_marginLeft = cw - m_width - m_marginRight;
1116 // this makes auto margins 0 if we failed a m_width<cw test above (css2.1, 10.3.3)
1117 m_marginLeft = ml.calcMinValue(cw);
1118 m_marginRight = mr.calcMinValue(cw);
1123 void RenderBox::calcHeight()
1125 // Cell height is managed by the table and inline non-replaced elements do not support a height property.
1126 if (isTableCell() || (isInline() && !isReplaced()))
1130 calcAbsoluteVertical();
1133 calcVerticalMargins();
1135 // For tables, calculate margins only
1140 bool inHorizontalBox = parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL;
1141 bool stretching = parent()->style()->boxAlign() == BSTRETCH;
1142 bool treatAsReplaced = isReplaced() && !isInlineBlockOrInlineTable() && (!inHorizontalBox || !stretching);
1143 bool checkMinMaxHeight = false;
1145 // The parent box is flexing us, so it has increased or decreased our height. We have to
1146 // grab our cached flexible height.
1147 if (m_overrideSize != -1 && parent()->isFlexibleBox() && parent()->style()->boxOrient() == VERTICAL
1148 && parent()->isFlexingChildren())
1149 h = Length(m_overrideSize - borderTop() - borderBottom() - paddingTop() - paddingBottom(), Fixed);
1150 else if (treatAsReplaced)
1151 h = Length(calcReplacedHeight(), Fixed);
1153 h = style()->height();
1154 checkMinMaxHeight = true;
1157 // Block children of horizontal flexible boxes fill the height of the box.
1158 if (h.isAuto() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
1159 && parent()->isStretchingChildren()) {
1160 h = Length(parent()->contentHeight() - marginTop() - marginBottom() -
1161 borderTop() - paddingTop() - borderBottom() - paddingBottom(), Fixed);
1162 checkMinMaxHeight = false;
1166 if (checkMinMaxHeight) {
1167 height = calcHeightUsing(style()->height());
1170 int minH = calcHeightUsing(style()->minHeight()); // Leave as -1 if unset.
1171 int maxH = style()->maxHeight().value() == undefinedLength ? height : calcHeightUsing(style()->maxHeight());
1174 height = min(maxH, height);
1175 height = max(minH, height);
1178 // The only times we don't check min/max height are when a fixed length has
1179 // been given as an override. Just use that. The value has already been adjusted
1181 height = h.value() + borderTop() + borderBottom() + paddingTop() + paddingBottom();
1186 // Unfurling marquees override with the furled height.
1187 if (style()->overflow() == OMARQUEE && m_layer && m_layer->marquee() &&
1188 m_layer->marquee()->isUnfurlMarquee() && !m_layer->marquee()->isHorizontal()) {
1189 m_layer->marquee()->setEnd(m_height);
1190 m_height = min(m_height, m_layer->marquee()->unfurlPos());
1193 // WinIE quirk: The <html> block always fills the entire canvas in quirks mode. The <body> always fills the
1194 // <html> block in quirks mode. Only apply this quirk if the block is normal flow and no height
1196 if (style()->htmlHacks() && style()->height().isAuto() &&
1197 !isFloatingOrPositioned() && (isRoot() || isBody())) {
1198 int margins = collapsedMarginTop() + collapsedMarginBottom();
1199 int visHeight = canvas()->view()->visibleHeight();
1201 m_height = max(m_height, visHeight - margins);
1203 m_height = max(m_height, visHeight -
1204 (margins + parent()->marginTop() + parent()->marginBottom() +
1205 parent()->borderTop() + parent()->borderBottom() +
1206 parent()->paddingTop() + parent()->paddingBottom()));
1210 int RenderBox::calcHeightUsing(const Length& h)
1216 else if (h.isPercent())
1217 height = calcPercentageHeight(h);
1219 height = calcBorderBoxHeight(height);
1226 int RenderBox::calcPercentageHeight(const Length& height)
1229 bool includeBorderPadding = isTable();
1230 RenderBlock* cb = containingBlock();
1231 if (style()->htmlHacks()) {
1232 // In quirks mode, blocks with auto height are skipped, and we keep looking for an enclosing
1233 // block that may have a specified height and then use it. In strict mode, this violates the
1234 // specification, which states that percentage heights just revert to auto if the containing
1235 // block has an auto height.
1236 for ( ; !cb->isCanvas() && !cb->isBody() && !cb->isTableCell() && !cb->isPositioned() &&
1237 cb->style()->height().isAuto(); cb = cb->containingBlock());
1240 // Table cells violate what the CSS spec says to do with heights. Basically we
1241 // don't care if the cell specified a height or not. We just always make ourselves
1242 // be a percentage of the cell's current content height.
1243 if (cb->isTableCell()) {
1244 result = cb->overrideSize();
1246 // Normally we would let the cell size intrinsically, but scrolling overflow has to be
1247 // treated differently, since WinIE lets scrolled overflow regions shrink as needed.
1248 // While we can't get all cases right, we can at least detect when the cell has a specified
1249 // height or when the table has a specified height. In these cases we want to initially have
1250 // no size and allow the flexing of the table or the cell to its specified height to cause us
1251 // to grow to fill the space. This could end up being wrong in some cases, but it is
1252 // preferable to the alternative (sizing intrinsically and making the row end up too big).
1253 RenderTableCell* cell = static_cast<RenderTableCell*>(cb);
1254 if (scrollsOverflow() &&
1255 (!cell->style()->height().isAuto() || !cell->table()->style()->height().isAuto()))
1259 includeBorderPadding = true;
1262 // Otherwise we only use our percentage height if our containing block had a specified
1264 else if (cb->style()->height().isFixed())
1265 result = cb->calcContentBoxHeight(cb->style()->height().value());
1266 else if (cb->style()->height().isPercent()) {
1267 // We need to recur and compute the percentage height for our containing block.
1268 result = cb->calcPercentageHeight(cb->style()->height());
1270 result = cb->calcContentBoxHeight(result);
1272 else if (cb->isCanvas() || (cb->isBody() && style()->htmlHacks())) {
1273 // Don't allow this to affect the block' m_height member variable, since this
1274 // can get called while the block is still laying out its kids.
1275 int oldHeight = cb->height();
1277 result = cb->contentHeight();
1278 cb->setHeight(oldHeight);
1279 } else if (cb->isRoot() && isPositioned()) {
1280 // Match the positioned objects behavior, which is that positioned objects will fill their viewport
1281 // always. Note we could only hit this case by recurring into calcPercentageHeight on a positioned containing block.
1282 result = cb->calcContentBoxHeight(cb->availableHeight());
1286 result = height.calcValue(result);
1287 if (includeBorderPadding) {
1288 // It is necessary to use the border-box to match WinIE's broken
1289 // box model. This is essential for sizing inside
1290 // table cells using percentage heights.
1291 result -= (borderTop() + paddingTop() + borderBottom() + paddingBottom());
1292 result = max(0, result);
1298 int RenderBox::calcReplacedWidth() const
1300 int width = calcReplacedWidthUsing(Width);
1301 int minW = calcReplacedWidthUsing(MinWidth);
1302 int maxW = style()->maxWidth().value() == undefinedLength ? width : calcReplacedWidthUsing(MaxWidth);
1304 return max(minW, min(width, maxW));
1307 int RenderBox::calcReplacedWidthUsing(WidthType widthType) const
1310 if (widthType == Width)
1311 w = style()->width();
1312 else if (widthType == MinWidth)
1313 w = style()->minWidth();
1315 w = style()->maxWidth();
1319 return calcContentBoxWidth(w.value());
1321 const int cw = containingBlockWidth();
1323 return calcContentBoxWidth(w.calcMinValue(cw));
1327 return intrinsicWidth();
1331 int RenderBox::calcReplacedHeight() const
1333 int height = calcReplacedHeightUsing(Height);
1334 int minH = calcReplacedHeightUsing(MinHeight);
1335 int maxH = style()->maxHeight().value() == undefinedLength ? height : calcReplacedHeightUsing(MaxHeight);
1337 return max(minH, min(height, maxH));
1340 int RenderBox::calcReplacedHeightUsing(HeightType heightType) const
1343 if (heightType == Height)
1344 h = style()->height();
1345 else if (heightType == MinHeight)
1346 h = style()->minHeight();
1348 h = style()->maxHeight();
1352 return calcContentBoxHeight(h.value());
1354 return calcContentBoxHeight(h.calcValue(containingBlock()->availableHeight()));
1356 return intrinsicHeight();
1360 int RenderBox::availableHeight() const
1362 return availableHeightUsing(style()->height());
1365 int RenderBox::availableHeightUsing(const Length& h) const
1368 return calcContentBoxHeight(h.value());
1371 return static_cast<const RenderCanvas*>(this)->view()->visibleHeight();
1373 // We need to stop here, since we don't want to increase the height of the table
1374 // artificially. We're going to rely on this cell getting expanded to some new
1375 // height, and then when we lay out again we'll use the calculation below.
1376 if (isTableCell() && (h.isAuto() || h.isPercent()))
1377 return overrideSize() - (borderLeft() + borderRight() + paddingLeft() + paddingRight());
1380 return calcContentBoxHeight(h.calcValue(containingBlock()->availableHeight()));
1382 return containingBlock()->availableHeight();
1385 void RenderBox::calcVerticalMargins()
1387 if( isTableCell() ) {
1388 // table margins are basically infinite
1389 m_marginTop = TABLECELLMARGIN;
1390 m_marginBottom = TABLECELLMARGIN;
1394 Length tm = style()->marginTop();
1395 Length bm = style()->marginBottom();
1397 // margins are calculated with respect to the _width_ of
1398 // the containing block (8.3)
1399 int cw = containingBlock()->contentWidth();
1401 m_marginTop = tm.calcMinValue(cw);
1402 m_marginBottom = bm.calcMinValue(cw);
1405 void RenderBox::setStaticX(int staticX)
1407 m_staticX = staticX;
1410 void RenderBox::setStaticY(int staticY)
1412 m_staticY = staticY;
1415 void RenderBox::calcAbsoluteHorizontal()
1417 const int AUTO = -666666;
1420 int pab = borderLeft()+ borderRight()+ paddingLeft()+ paddingRight();
1424 // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
1425 RenderObject* cb = container();
1426 cw = containingBlockWidth() + cb->paddingLeft() + cb->paddingRight();
1428 if (!style()->left().isAuto())
1429 l = style()->left().calcValue(cw);
1430 if (!style()->right().isAuto())
1431 r = style()->right().calcValue(cw);
1433 int static_distance=0;
1434 if ((parent()->style()->direction()==LTR && (l == AUTO && r == AUTO))
1435 || style()->left().isStatic())
1437 static_distance = m_staticX - cb->borderLeft(); // Should already have been set through layout of the parent().
1438 RenderObject* po = parent();
1439 for (; po && po != cb; po = po->parent())
1440 static_distance += po->xPos();
1442 l = static_distance;
1445 else if ((parent()->style()->direction()==RTL && (l==AUTO && r==AUTO ))
1446 || style()->right().isStatic())
1448 RenderObject* po = parent();
1449 static_distance = m_staticX + cw + cb->borderRight() - po->width(); // Should already have been set through layout of the parent().
1450 while (po && po!=containingBlock()) {
1451 static_distance -= po->xPos();
1455 r = static_distance;
1458 calcAbsoluteHorizontalValues(Width, cb, cw, pab, static_distance, l, r, m_width, m_marginLeft, m_marginRight, m_x);
1460 // Avoid doing any work in the common case (where the values of min-width and max-width are their defaults).
1461 int minW = m_width, minML, minMR, minX;
1462 calcAbsoluteHorizontalValues(MinWidth, cb, cw, pab, static_distance, l, r, minW, minML, minMR, minX);
1464 int maxW = m_width, maxML, maxMR, maxX;
1465 if (style()->maxWidth().value() != undefinedLength)
1466 calcAbsoluteHorizontalValues(MaxWidth, cb, cw, static_distance, pab, l, r, maxW, maxML, maxMR, maxX);
1468 if (m_width > maxW) {
1470 m_marginLeft = maxML;
1471 m_marginRight = maxMR;
1475 if (m_width < minW) {
1477 m_marginLeft = minML;
1478 m_marginRight = minMR;
1483 void RenderBox::calcAbsoluteHorizontalValues(WidthType widthType, RenderObject* cb, int cw, int pab, int static_distance,
1484 int l, int r, int& w, int& ml, int& mr, int& x)
1486 const int AUTO = -666666;
1489 if (!style()->marginLeft().isAuto())
1490 ml = style()->marginLeft().calcValue(cw);
1491 if (!style()->marginRight().isAuto())
1492 mr = style()->marginRight().calcValue(cw);
1495 if (widthType == Width)
1496 width = style()->width();
1497 else if (widthType == MinWidth)
1498 width = style()->minWidth();
1500 width = style()->maxWidth();
1502 if (!width.isIntrinsicOrAuto())
1503 w = calcContentBoxWidth(width.calcValue(cw));
1504 else if (isReplaced())
1505 w = calcReplacedWidth();
1507 if (l != AUTO && w != AUTO && r != AUTO) {
1508 // left, width, right all given, play with margins
1509 int ot = l + w + r + pab;
1511 if (ml==AUTO && mr==AUTO) {
1512 // both margins auto, solve for equality
1517 // solve for left margin
1520 // solve for right margin
1523 // overconstrained, solve according to dir
1524 if (style()->direction() == LTR)
1525 r = cw - ( l + w + ml + mr + pab);
1527 l = cw - ( r + w + ml + mr + pab);
1532 // one or two of (left, width, right) missing, solve
1534 // auto margins are ignored
1535 if (ml==AUTO) ml = 0;
1536 if (mr==AUTO) mr = 0;
1538 //1. solve left & width.
1539 if (l == AUTO && w == AUTO && r != AUTO) {
1540 // From section 10.3.7 of the CSS2.1 specification.
1541 // "The shrink-to-fit width is: min(max(preferred minimum width, available width), preferred width)."
1542 w = min(max(m_minWidth - pab, cw - (r + ml + mr + pab)), m_maxWidth - pab);
1543 l = cw - (r + w + ml + mr + pab);
1547 //2. solve left & right. use static positioning.
1548 if (l == AUTO && w != AUTO && r == AUTO) {
1549 if (style()->direction()==RTL) {
1550 r = static_distance;
1551 l = cw - (r + w + ml + mr + pab);
1554 l = static_distance;
1555 r = cw - (l + w + ml + mr + pab);
1558 } //3. solve width & right.
1559 else if (l != AUTO && w == AUTO && r == AUTO) {
1560 // From section 10.3.7 of the CSS2.1 specification.
1561 // "The shrink-to-fit width is: min(max(preferred minimum width, available width), preferred width)."
1562 w = min(max(m_minWidth - pab, cw - (l + ml + mr + pab)), m_maxWidth - pab);
1563 r = cw - (l + w + ml + mr + pab);
1568 if (l==AUTO && w!=AUTO && r!=AUTO)
1569 l = cw - (r + w + ml + mr + pab);
1572 if (l!=AUTO && w==AUTO && r!=AUTO)
1573 w = cw - (r + l + ml + mr + pab);
1577 if (l!=AUTO && w!=AUTO && r==AUTO)
1578 r = cw - (l + w + ml + mr + pab);
1582 x = l + ml + cb->borderLeft();
1585 void RenderBox::calcAbsoluteVertical()
1587 // css2 spec 10.6.4 & 10.6.5
1590 // http://www.w3.org/Style/css2-updates/REC-CSS2-19980512-errata
1591 // (actually updated 2000-10-24)
1592 // that introduces static-position value for top, left & right
1594 const int AUTO = -666666;
1599 int pab = borderTop()+borderBottom()+paddingTop()+paddingBottom();
1601 // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
1602 RenderObject* cb = container();
1603 if (cb->isRoot()) // Even in strict mode (where we don't grow the root to fill the viewport) other browsers
1604 // position as though the root fills the viewport.
1605 ch = cb->availableHeight();
1607 ch = cb->height() - cb->borderTop() - cb->borderBottom();
1609 if (!style()->top().isAuto())
1610 t = style()->top().calcValue(ch);
1611 if (!style()->bottom().isAuto())
1612 b = style()->bottom().calcValue(ch);
1615 calcAbsoluteVerticalValues(Height, cb, ch, pab, t, b, h, mt, mb, y);
1617 // Avoid doing any work in the common case (where the values of min-height and max-height are their defaults).
1618 int minH = h, minMT, minMB, minY;
1619 calcAbsoluteVerticalValues(MinHeight, cb, ch, pab, t, b, minH, minMT, minMB, minY);
1621 int maxH = h, maxMT, maxMB, maxY;
1622 if (style()->maxHeight().value() != undefinedLength)
1623 calcAbsoluteVerticalValues(MaxHeight, cb, ch, pab, t, b, maxH, maxMT, maxMB, maxY);
1639 // If our natural height exceeds the new height once we've set it, then we need to make sure to update
1640 // overflow to track the spillout.
1642 setOverflowHeight(m_height);
1644 // Set our final values.
1647 m_marginBottom = mb;
1651 void RenderBox::calcAbsoluteVerticalValues(HeightType heightType, RenderObject* cb, int ch, int pab,
1652 int t, int b, int& h, int& mt, int& mb, int& y)
1654 const int AUTO = -666666;
1657 if (!style()->marginTop().isAuto())
1658 mt = style()->marginTop().calcValue(ch);
1659 if (!style()->marginBottom().isAuto())
1660 mb = style()->marginBottom().calcValue(ch);
1663 if (heightType == Height)
1664 height = style()->height();
1665 else if (heightType == MinHeight)
1666 height = style()->minHeight();
1668 height = style()->maxHeight();
1670 int ourHeight = m_height;
1672 if (isTable() && height.isAuto())
1673 // Height is never unsolved for tables. "auto" means shrink to fit. Use our
1675 h = ourHeight - pab;
1676 else if (!height.isAuto())
1678 h = calcContentBoxHeight(height.calcValue(ch));
1679 if (ourHeight - pab > h)
1680 ourHeight = h + pab;
1682 else if (isReplaced())
1683 h = calcReplacedHeight();
1686 if ((t == AUTO && b == AUTO) || style()->top().isStatic()) {
1687 // calc hypothetical location in the normal flow
1688 // used for 1) top=static-position
1689 // 2) top, bottom, height are all auto -> calc top -> 3.
1690 // 3) precalc for case 2 below
1691 static_top = m_staticY - cb->borderTop(); // Should already have been set through layout of the parent().
1692 RenderObject* po = parent();
1693 for (; po && po != cb; po = po->parent())
1694 if (!po->isTableRow())
1695 static_top += po->yPos();
1697 if (h == AUTO || style()->top().isStatic())
1701 if (t != AUTO && h != AUTO && b != AUTO) {
1702 // top, height, bottom all given, play with margins
1703 int ot = h + t + b + pab;
1705 if (mt == AUTO && mb == AUTO) {
1706 // both margins auto, solve for equality
1711 // solve for top margin
1714 // solve for bottom margin
1717 // overconstrained, solve for bottom
1718 b = ch - (h + t + mt + mb + pab);
1721 // one or two of (top, height, bottom) missing, solve
1723 // auto margins are ignored
1729 //1. solve top & height. use content height.
1730 if (t == AUTO && h == AUTO && b != AUTO) {
1731 h = ourHeight - pab;
1732 t = ch - (h + b + mt + mb + pab);
1734 else if (t == AUTO && h != AUTO && b == AUTO) //2. solve top & bottom. use static positioning.
1737 b = ch - (h + t + mt + mb + pab);
1739 else if (t != AUTO && h == AUTO && b == AUTO) //3. solve height & bottom. use content height.
1741 h = ourHeight - pab;
1742 b = ch - (h + t + mt + mb + pab);
1746 if (t == AUTO && h != AUTO && b != AUTO)
1747 t = ch - (h + b + mt + mb + pab);
1751 if (t != AUTO && h == AUTO && b != AUTO)
1752 h = ch - (t + b + mt + mb + pab);
1756 if (t != AUTO && h != AUTO && b == AUTO)
1757 b = ch - (h + t + mt + mb + pab);
1760 if (ourHeight < h + pab) //content must still fit
1761 ourHeight = h + pab;
1763 if (hasOverflowClip() && ourHeight > h + pab)
1764 ourHeight = h + pab;
1766 // Do not allow the height to be negative. This can happen when someone specifies both top and bottom
1767 // but the containing block height is less than top, e.g., top:20px, bottom:0, containing block height 16.
1768 ourHeight = max(0, ourHeight);
1771 y = t + mt + cb->borderTop();
1774 IntRect RenderBox::caretRect(int offset, EAffinity affinity, int* extraWidthToEndOfLine)
1776 // FIXME: Is it OK to check only first child instead of picking
1777 // right child based on offset? Is it OK to pass the same offset
1778 // along to the child instead of offset 0 or whatever?
1780 // propagate it downwards to its children, someone will feel responsible
1781 if (RenderObject* child = firstChild()) {
1782 IntRect result = child->caretRect(offset, affinity, extraWidthToEndOfLine);
1783 if (!result.isEmpty())
1787 // if not, use the extents of this box
1788 // offset 0 means left, offset 1 means right
1789 // FIXME: What about border and padding?
1790 const int caretWidth = 1;
1791 IntRect rect(xPos(), yPos(), caretWidth, m_height);
1793 rect.move(IntSize(m_width - caretWidth, 0));
1794 if (InlineBox* box = inlineBoxWrapper()) {
1795 RootInlineBox* rootBox = box->root();
1796 int top = rootBox->topOverflow();
1798 rect.setHeight(rootBox->bottomOverflow() - top);
1801 // If height of box is smaller than font height, use the latter one,
1802 // otherwise the caret might become invisible.
1804 // Also, if the box is not a replaced element, always use the font height.
1805 // This prevents the "big caret" bug described in:
1806 // <rdar://problem/3777804> Deleting all content in a document can result in giant tall-as-window insertion point
1808 // FIXME: ignoring :first-line, missing good reason to take care of
1809 int fontHeight = style()->font().height();
1810 if (fontHeight > rect.height() || !isReplaced())
1811 rect.setHeight(fontHeight);
1813 RenderObject* cb = containingBlock();
1815 if (!cb || !cb->absolutePosition(cbx, cby))
1816 // No point returning a relative position.
1819 if (extraWidthToEndOfLine)
1820 *extraWidthToEndOfLine = xPos() + m_width - rect.right();
1822 rect.move(cbx, cby);
1826 int RenderBox::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
1828 return includeSelf ? m_height : 0;
1831 int RenderBox::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
1833 return includeSelf ? m_width : 0;
1836 int RenderBox::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
1838 return includeSelf ? 0 : m_width;