• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
5  *           (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com)
6  * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  */
24 
25 #include "config.h"
26 #include "RenderBox.h"
27 
28 #include "CachedImage.h"
29 #include "ChromeClient.h"
30 #include "Document.h"
31 #include "FrameView.h"
32 #include "GraphicsContext.h"
33 #include "htmlediting.h"
34 #include "HTMLElement.h"
35 #include "HTMLNames.h"
36 #include "ImageBuffer.h"
37 #include "FloatQuad.h"
38 #include "Frame.h"
39 #include "Page.h"
40 #include "RenderArena.h"
41 #include "RenderFlexibleBox.h"
42 #include "RenderInline.h"
43 #include "RenderLayer.h"
44 #include "RenderTableCell.h"
45 #include "RenderTheme.h"
46 #ifdef ANDROID_LAYOUT
47 #include "Settings.h"
48 #endif
49 #include "RenderView.h"
50 #include "TransformState.h"
51 #include <algorithm>
52 #include <math.h>
53 
54 #if ENABLE(WML)
55 #include "WMLNames.h"
56 #endif
57 
58 using namespace std;
59 
60 namespace WebCore {
61 
62 using namespace HTMLNames;
63 
64 // Used by flexible boxes when flexing this element.
65 typedef WTF::HashMap<const RenderBox*, int> OverrideSizeMap;
66 static OverrideSizeMap* gOverrideSizeMap = 0;
67 
68 bool RenderBox::s_hadOverflowClip = false;
69 
RenderBox(Node * node)70 RenderBox::RenderBox(Node* node)
71     : RenderBoxModelObject(node)
72 #ifdef ANDROID_LAYOUT
73     , m_visibleWidth(0)
74 #endif
75     , m_marginLeft(0)
76     , m_marginRight(0)
77     , m_marginTop(0)
78     , m_marginBottom(0)
79     , m_minPrefWidth(-1)
80     , m_maxPrefWidth(-1)
81     , m_inlineBoxWrapper(0)
82 {
83     setIsBox();
84 }
85 
~RenderBox()86 RenderBox::~RenderBox()
87 {
88 }
89 
destroy()90 void RenderBox::destroy()
91 {
92     // A lot of the code in this function is just pasted into
93     // RenderWidget::destroy. If anything in this function changes,
94     // be sure to fix RenderWidget::destroy() as well.
95     if (hasOverrideSize())
96         gOverrideSizeMap->remove(this);
97 
98     if (style() && (style()->height().isPercent() || style()->minHeight().isPercent() || style()->maxHeight().isPercent()))
99         RenderBlock::removePercentHeightDescendant(this);
100 
101     RenderBoxModelObject::destroy();
102 }
103 
removeFloatingOrPositionedChildFromBlockLists()104 void RenderBox::removeFloatingOrPositionedChildFromBlockLists()
105 {
106     ASSERT(isFloatingOrPositioned());
107 
108     if (documentBeingDestroyed())
109         return;
110 
111     if (isFloating()) {
112         RenderBlock* outermostBlock = containingBlock();
113         for (RenderBlock* p = outermostBlock; p && !p->isRenderView(); p = p->containingBlock()) {
114             if (p->containsFloat(this))
115                 outermostBlock = p;
116         }
117 
118         if (outermostBlock)
119             outermostBlock->markAllDescendantsWithFloatsForLayout(this, false);
120     }
121 
122     if (isPositioned()) {
123         RenderObject* p;
124         for (p = parent(); p; p = p->parent()) {
125             if (p->isRenderBlock())
126                 toRenderBlock(p)->removePositionedObject(this);
127         }
128     }
129 }
130 
styleWillChange(StyleDifference diff,const RenderStyle * newStyle)131 void RenderBox::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
132 {
133     s_hadOverflowClip = hasOverflowClip();
134 
135     if (style()) {
136         // The background of the root element or the body element could propagate up to
137         // the canvas.  Just dirty the entire canvas when our style changes substantially.
138         if (diff >= StyleDifferenceRepaint && node() &&
139                 (node()->hasTagName(htmlTag) || node()->hasTagName(bodyTag)))
140             view()->repaint();
141 
142         // When a layout hint happens and an object's position style changes, we have to do a layout
143         // to dirty the render tree using the old position value now.
144         if (diff == StyleDifferenceLayout && parent() && style()->position() != newStyle->position()) {
145             markContainingBlocksForLayout();
146             if (style()->position() == StaticPosition)
147                 repaint();
148             if (isFloating() && !isPositioned() && (newStyle->position() == AbsolutePosition || newStyle->position() == FixedPosition))
149                 removeFloatingOrPositionedChildFromBlockLists();
150         }
151     }
152 
153     RenderBoxModelObject::styleWillChange(diff, newStyle);
154 }
155 
styleDidChange(StyleDifference diff,const RenderStyle * oldStyle)156 void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
157 {
158     RenderBoxModelObject::styleDidChange(diff, oldStyle);
159 
160     if (needsLayout() && oldStyle && (oldStyle->height().isPercent() || oldStyle->minHeight().isPercent() || oldStyle->maxHeight().isPercent()))
161         RenderBlock::removePercentHeightDescendant(this);
162 
163     // If our zoom factor changes and we have a defined scrollLeft/Top, we need to adjust that value into the
164     // new zoomed coordinate space.
165     if (hasOverflowClip() && oldStyle && style() && oldStyle->effectiveZoom() != style()->effectiveZoom()) {
166         int left = scrollLeft();
167         if (left) {
168             left = (left / oldStyle->effectiveZoom()) * style()->effectiveZoom();
169             setScrollLeft(left);
170         }
171         int top = scrollTop();
172         if (top) {
173             top = (top / oldStyle->effectiveZoom()) * style()->effectiveZoom();
174             setScrollTop(top);
175         }
176     }
177 
178     // Set the text color if we're the body.
179     if (isBody())
180         document()->setTextColor(style()->color());
181 }
182 
updateBoxModelInfoFromStyle()183 void RenderBox::updateBoxModelInfoFromStyle()
184 {
185     RenderBoxModelObject::updateBoxModelInfoFromStyle();
186 
187     bool isRootObject = isRoot();
188     bool isViewObject = isRenderView();
189 
190     // The root and the RenderView always paint their backgrounds/borders.
191     if (isRootObject || isViewObject)
192         setHasBoxDecorations(true);
193 
194     setPositioned(style()->position() == AbsolutePosition || style()->position() == FixedPosition);
195     setFloating(!isPositioned() && style()->isFloating());
196 
197     // We also handle <body> and <html>, whose overflow applies to the viewport.
198     if (style()->overflowX() != OVISIBLE && !isRootObject && (isRenderBlock() || isTableRow() || isTableSection())) {
199         bool boxHasOverflowClip = true;
200         if (isBody()) {
201             // Overflow on the body can propagate to the viewport under the following conditions.
202             // (1) The root element is <html>.
203             // (2) We are the primary <body> (can be checked by looking at document.body).
204             // (3) The root element has visible overflow.
205             if (document()->documentElement()->hasTagName(htmlTag) &&
206                 document()->body() == node() &&
207                 document()->documentElement()->renderer()->style()->overflowX() == OVISIBLE)
208                 boxHasOverflowClip = false;
209         }
210 
211         // Check for overflow clip.
212         // It's sufficient to just check one direction, since it's illegal to have visible on only one overflow value.
213         if (boxHasOverflowClip) {
214             if (!s_hadOverflowClip)
215                 // Erase the overflow
216                 repaint();
217             setHasOverflowClip();
218         }
219     }
220 
221     setHasTransform(style()->hasTransformRelatedProperty());
222     setHasReflection(style()->boxReflect());
223 }
224 
layout()225 void RenderBox::layout()
226 {
227     ASSERT(needsLayout());
228 
229     RenderObject* child = firstChild();
230     if (!child) {
231         setNeedsLayout(false);
232         return;
233     }
234 
235     LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()));
236     while (child) {
237         child->layoutIfNeeded();
238         ASSERT(!child->needsLayout());
239         child = child->nextSibling();
240     }
241     statePusher.pop();
242     setNeedsLayout(false);
243 }
244 
245 // More IE extensions.  clientWidth and clientHeight represent the interior of an object
246 // excluding border and scrollbar.
clientWidth() const247 int RenderBox::clientWidth() const
248 {
249     return width() - borderLeft() - borderRight() - verticalScrollbarWidth();
250 }
251 
clientHeight() const252 int RenderBox::clientHeight() const
253 {
254     return height() - borderTop() - borderBottom() - horizontalScrollbarHeight();
255 }
256 
scrollWidth() const257 int RenderBox::scrollWidth() const
258 {
259     if (hasOverflowClip())
260         return layer()->scrollWidth();
261     // For objects with visible overflow, this matches IE.
262     if (style()->direction() == LTR)
263         return max(clientWidth(), rightmostPosition(true, false) - borderLeft());
264     return clientWidth() - min(0, leftmostPosition(true, false) - borderLeft());
265 }
266 
scrollHeight() const267 int RenderBox::scrollHeight() const
268 {
269     if (hasOverflowClip())
270         return layer()->scrollHeight();
271     // For objects with visible overflow, this matches IE.
272     return max(clientHeight(), lowestPosition(true, false) - borderTop());
273 }
274 
scrollLeft() const275 int RenderBox::scrollLeft() const
276 {
277     return hasOverflowClip() ? layer()->scrollXOffset() : 0;
278 }
279 
scrollTop() const280 int RenderBox::scrollTop() const
281 {
282     return hasOverflowClip() ? layer()->scrollYOffset() : 0;
283 }
284 
setScrollLeft(int newLeft)285 void RenderBox::setScrollLeft(int newLeft)
286 {
287     if (hasOverflowClip())
288         layer()->scrollToXOffset(newLeft);
289 }
290 
setScrollTop(int newTop)291 void RenderBox::setScrollTop(int newTop)
292 {
293     if (hasOverflowClip())
294         layer()->scrollToYOffset(newTop);
295 }
296 
absoluteRects(Vector<IntRect> & rects,int tx,int ty)297 void RenderBox::absoluteRects(Vector<IntRect>& rects, int tx, int ty)
298 {
299     rects.append(IntRect(tx, ty, width(), height()));
300 }
301 
absoluteQuads(Vector<FloatQuad> & quads)302 void RenderBox::absoluteQuads(Vector<FloatQuad>& quads)
303 {
304     quads.append(localToAbsoluteQuad(FloatRect(0, 0, width(), height())));
305 }
306 
absoluteContentBox() const307 IntRect RenderBox::absoluteContentBox() const
308 {
309     IntRect rect = contentBoxRect();
310     FloatPoint absPos = localToAbsolute(FloatPoint());
311     rect.move(absPos.x(), absPos.y());
312     return rect;
313 }
314 
absoluteContentQuad() const315 FloatQuad RenderBox::absoluteContentQuad() const
316 {
317     IntRect rect = contentBoxRect();
318     return localToAbsoluteQuad(FloatRect(rect));
319 }
320 
outlineBoundsForRepaint(RenderBoxModelObject * repaintContainer) const321 IntRect RenderBox::outlineBoundsForRepaint(RenderBoxModelObject* repaintContainer) const
322 {
323     IntRect box = borderBoundingBox();
324     adjustRectForOutlineAndShadow(box);
325 
326     FloatQuad containerRelativeQuad = localToContainerQuad(FloatRect(box), repaintContainer);
327     box = containerRelativeQuad.enclosingBoundingBox();
328 
329     // FIXME: layoutDelta needs to be applied in parts before/after transforms and
330     // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
331     box.move(view()->layoutDelta());
332 
333     return box;
334 }
335 
addFocusRingRects(GraphicsContext * graphicsContext,int tx,int ty)336 void RenderBox::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty)
337 {
338     graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height()));
339 }
340 
341 
reflectionBox() const342 IntRect RenderBox::reflectionBox() const
343 {
344     IntRect result;
345     if (!style()->boxReflect())
346         return result;
347     IntRect box = borderBoxRect();
348     result = box;
349     switch (style()->boxReflect()->direction()) {
350         case ReflectionBelow:
351             result.move(0, box.height() + reflectionOffset());
352             break;
353         case ReflectionAbove:
354             result.move(0, -box.height() - reflectionOffset());
355             break;
356         case ReflectionLeft:
357             result.move(-box.width() - reflectionOffset(), 0);
358             break;
359         case ReflectionRight:
360             result.move(box.width() + reflectionOffset(), 0);
361             break;
362     }
363     return result;
364 }
365 
reflectionOffset() const366 int RenderBox::reflectionOffset() const
367 {
368     if (!style()->boxReflect())
369         return 0;
370     if (style()->boxReflect()->direction() == ReflectionLeft || style()->boxReflect()->direction() == ReflectionRight)
371         return style()->boxReflect()->offset().calcValue(borderBoxRect().width());
372     return style()->boxReflect()->offset().calcValue(borderBoxRect().height());
373 }
374 
reflectedRect(const IntRect & r) const375 IntRect RenderBox::reflectedRect(const IntRect& r) const
376 {
377     if (!style()->boxReflect())
378         return IntRect();
379 
380     IntRect box = borderBoxRect();
381     IntRect result = r;
382     switch (style()->boxReflect()->direction()) {
383         case ReflectionBelow:
384             result.setY(box.bottom() + reflectionOffset() + (box.bottom() - r.bottom()));
385             break;
386         case ReflectionAbove:
387             result.setY(box.y() - reflectionOffset() - box.height() + (box.bottom() - r.bottom()));
388             break;
389         case ReflectionLeft:
390             result.setX(box.x() - reflectionOffset() - box.width() + (box.right() - r.right()));
391             break;
392         case ReflectionRight:
393             result.setX(box.right() + reflectionOffset() + (box.right() - r.right()));
394             break;
395     }
396     return result;
397 }
398 
verticalScrollbarWidth() const399 int RenderBox::verticalScrollbarWidth() const
400 {
401     return includeVerticalScrollbarSize() ? layer()->verticalScrollbarWidth() : 0;
402 }
403 
horizontalScrollbarHeight() const404 int RenderBox::horizontalScrollbarHeight() const
405 {
406     return includeHorizontalScrollbarSize() ? layer()->horizontalScrollbarHeight() : 0;
407 }
408 
scroll(ScrollDirection direction,ScrollGranularity granularity,float multiplier)409 bool RenderBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
410 {
411     RenderLayer* l = layer();
412     if (l && l->scroll(direction, granularity, multiplier))
413         return true;
414     RenderBlock* b = containingBlock();
415     if (b && !b->isRenderView())
416         return b->scroll(direction, granularity, multiplier);
417     return false;
418 }
419 
canBeProgramaticallyScrolled(bool) const420 bool RenderBox::canBeProgramaticallyScrolled(bool) const
421 {
422     return (hasOverflowClip() && (scrollsOverflow() || (node() && node()->isContentEditable()))) || (node() && node()->isDocumentNode());
423 }
424 
autoscroll()425 void RenderBox::autoscroll()
426 {
427     if (layer())
428         layer()->autoscroll();
429 }
430 
panScroll(const IntPoint & source)431 void RenderBox::panScroll(const IntPoint& source)
432 {
433     if (layer())
434         layer()->panScrollFromPoint(source);
435 }
436 
minPrefWidth() const437 int RenderBox::minPrefWidth() const
438 {
439     if (prefWidthsDirty())
440         const_cast<RenderBox*>(this)->calcPrefWidths();
441 
442     return m_minPrefWidth;
443 }
444 
maxPrefWidth() const445 int RenderBox::maxPrefWidth() const
446 {
447     if (prefWidthsDirty())
448         const_cast<RenderBox*>(this)->calcPrefWidths();
449 
450     return m_maxPrefWidth;
451 }
452 
overrideSize() const453 int RenderBox::overrideSize() const
454 {
455     if (!hasOverrideSize())
456         return -1;
457     return gOverrideSizeMap->get(this);
458 }
459 
setOverrideSize(int s)460 void RenderBox::setOverrideSize(int s)
461 {
462     if (s == -1) {
463         if (hasOverrideSize()) {
464             setHasOverrideSize(false);
465             gOverrideSizeMap->remove(this);
466         }
467     } else {
468         if (!gOverrideSizeMap)
469             gOverrideSizeMap = new OverrideSizeMap();
470         setHasOverrideSize(true);
471         gOverrideSizeMap->set(this, s);
472     }
473 }
474 
overrideWidth() const475 int RenderBox::overrideWidth() const
476 {
477     return hasOverrideSize() ? overrideSize() : width();
478 }
479 
overrideHeight() const480 int RenderBox::overrideHeight() const
481 {
482     return hasOverrideSize() ? overrideSize() : height();
483 }
484 
calcBorderBoxWidth(int width) const485 int RenderBox::calcBorderBoxWidth(int width) const
486 {
487     int bordersPlusPadding = borderLeft() + borderRight() + paddingLeft() + paddingRight();
488     if (style()->boxSizing() == CONTENT_BOX)
489         return width + bordersPlusPadding;
490     return max(width, bordersPlusPadding);
491 }
492 
calcBorderBoxHeight(int height) const493 int RenderBox::calcBorderBoxHeight(int height) const
494 {
495     int bordersPlusPadding = borderTop() + borderBottom() + paddingTop() + paddingBottom();
496     if (style()->boxSizing() == CONTENT_BOX)
497         return height + bordersPlusPadding;
498     return max(height, bordersPlusPadding);
499 }
500 
calcContentBoxWidth(int width) const501 int RenderBox::calcContentBoxWidth(int width) const
502 {
503     if (style()->boxSizing() == BORDER_BOX)
504         width -= (borderLeft() + borderRight() + paddingLeft() + paddingRight());
505     return max(0, width);
506 }
507 
calcContentBoxHeight(int height) const508 int RenderBox::calcContentBoxHeight(int height) const
509 {
510     if (style()->boxSizing() == BORDER_BOX)
511         height -= (borderTop() + borderBottom() + paddingTop() + paddingBottom());
512     return max(0, height);
513 }
514 
515 // Hit Testing
nodeAtPoint(const HitTestRequest & request,HitTestResult & result,int xPos,int yPos,int tx,int ty,HitTestAction action)516 bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int xPos, int yPos, int tx, int ty, HitTestAction action)
517 {
518     tx += x();
519     ty += y();
520 
521     // Check kids first.
522     for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
523         if (!child->hasLayer() && child->nodeAtPoint(request, result, xPos, yPos, tx, ty, action)) {
524             updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty));
525             return true;
526         }
527     }
528 
529     // Check our bounds next. For this purpose always assume that we can only be hit in the
530     // foreground phase (which is true for replaced elements like images).
531     if (visibleToHitTesting() && action == HitTestForeground && IntRect(tx, ty, width(), height()).contains(xPos, yPos)) {
532         updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty));
533         return true;
534     }
535 
536     return false;
537 }
538 
539 // --------------------- painting stuff -------------------------------
540 
paint(PaintInfo & paintInfo,int tx,int ty)541 void RenderBox::paint(PaintInfo& paintInfo, int tx, int ty)
542 {
543     tx += x();
544     ty += y();
545 
546     // default implementation. Just pass paint through to the children
547     PaintInfo childInfo(paintInfo);
548     childInfo.paintingRoot = paintingRootForChildren(paintInfo);
549     for (RenderObject* child = firstChild(); child; child = child->nextSibling())
550         child->paint(childInfo, tx, ty);
551 }
552 
paintRootBoxDecorations(PaintInfo & paintInfo,int tx,int ty)553 void RenderBox::paintRootBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
554 {
555     const FillLayer* bgLayer = style()->backgroundLayers();
556     Color bgColor = style()->backgroundColor();
557     if (!style()->hasBackground() && node() && node()->hasTagName(HTMLNames::htmlTag)) {
558         // Locate the <body> element using the DOM.  This is easier than trying
559         // to crawl around a render tree with potential :before/:after content and
560         // anonymous blocks created by inline <body> tags etc.  We can locate the <body>
561         // render object very easily via the DOM.
562         HTMLElement* body = document()->body();
563         RenderObject* bodyObject = (body && body->hasLocalName(bodyTag)) ? body->renderer() : 0;
564         if (bodyObject) {
565             bgLayer = bodyObject->style()->backgroundLayers();
566             bgColor = bodyObject->style()->backgroundColor();
567         }
568     }
569 
570     int w = width();
571     int h = height();
572 
573     int rw;
574     int rh;
575     if (view()->frameView()) {
576         rw = view()->frameView()->contentsWidth();
577         rh = view()->frameView()->contentsHeight();
578     } else {
579         rw = view()->width();
580         rh = view()->height();
581     }
582 
583     // CSS2 14.2:
584     // The background of the box generated by the root element covers the entire canvas including
585     // its margins.
586     int bx = tx - marginLeft();
587     int by = ty - marginTop();
588     int bw = max(w + marginLeft() + marginRight() + borderLeft() + borderRight(), rw);
589     int bh = max(h + marginTop() + marginBottom() + borderTop() + borderBottom(), rh);
590 
591     paintFillLayers(paintInfo, bgColor, bgLayer, bx, by, bw, bh);
592 
593     if (style()->hasBorder() && style()->display() != INLINE)
594         paintBorder(paintInfo.context, tx, ty, w, h, style());
595 }
596 
paintBoxDecorations(PaintInfo & paintInfo,int tx,int ty)597 void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
598 {
599     if (!shouldPaintWithinRoot(paintInfo))
600         return;
601 
602     if (isRoot()) {
603         paintRootBoxDecorations(paintInfo, tx, ty);
604         return;
605     }
606 
607     int w = width();
608     int h = height();
609 
610     // border-fit can adjust where we paint our border and background.  If set, we snugly fit our line box descendants.  (The iChat
611     // balloon layout is an example of this).
612     borderFitAdjust(tx, w);
613 
614     // FIXME: Should eventually give the theme control over whether the box shadow should paint, since controls could have
615     // custom shadows of their own.
616     paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Normal);
617 
618     // If we have a native theme appearance, paint that before painting our background.
619     // The theme will tell us whether or not we should also paint the CSS background.
620     bool themePainted = style()->hasAppearance() && !theme()->paint(this, paintInfo, IntRect(tx, ty, w, h));
621     if (!themePainted) {
622         // The <body> only paints its background if the root element has defined a background
623         // independent of the body.  Go through the DOM to get to the root element's render object,
624         // since the root could be inline and wrapped in an anonymous block.
625         if (!isBody() || document()->documentElement()->renderer()->style()->hasBackground())
626             paintFillLayers(paintInfo, style()->backgroundColor(), style()->backgroundLayers(), tx, ty, w, h);
627         if (style()->hasAppearance())
628             theme()->paintDecorations(this, paintInfo, IntRect(tx, ty, w, h));
629     }
630     paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Inset);
631 
632     // The theme will tell us whether or not we should also paint the CSS border.
633     if ((!style()->hasAppearance() || (!themePainted && theme()->paintBorderOnly(this, paintInfo, IntRect(tx, ty, w, h)))) && style()->hasBorder())
634         paintBorder(paintInfo.context, tx, ty, w, h, style());
635 }
636 
paintMask(PaintInfo & paintInfo,int tx,int ty)637 void RenderBox::paintMask(PaintInfo& paintInfo, int tx, int ty)
638 {
639     if (!shouldPaintWithinRoot(paintInfo) || style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
640         return;
641 
642     int w = width();
643     int h = height();
644 
645     // border-fit can adjust where we paint our border and background.  If set, we snugly fit our line box descendants.  (The iChat
646     // balloon layout is an example of this).
647     borderFitAdjust(tx, w);
648 
649     paintMaskImages(paintInfo, tx, ty, w, h);
650 }
651 
paintMaskImages(const PaintInfo & paintInfo,int tx,int ty,int w,int h)652 void RenderBox::paintMaskImages(const PaintInfo& paintInfo, int tx, int ty, int w, int h)
653 {
654     // Figure out if we need to push a transparency layer to render our mask.
655     bool pushTransparencyLayer = false;
656     StyleImage* maskBoxImage = style()->maskBoxImage().image();
657     if (maskBoxImage && style()->maskLayers()->hasImage()) {
658         pushTransparencyLayer = true;
659     } else {
660         // We have to use an extra image buffer to hold the mask. Multiple mask images need
661         // to composite together using source-over so that they can then combine into a single unified mask that
662         // can be composited with the content using destination-in.  SVG images need to be able to set compositing modes
663         // as they draw images contained inside their sub-document, so we paint all our images into a separate buffer
664         // and composite that buffer as the mask.
665         // We have to check that the mask images to be rendered contain at least one image that can be actually used in rendering
666         // before pushing the transparency layer.
667         for (const FillLayer* fillLayer = style()->maskLayers()->next(); fillLayer; fillLayer = fillLayer->next()) {
668             if (fillLayer->hasImage() && fillLayer->image()->canRender(style()->effectiveZoom())) {
669                 pushTransparencyLayer = true;
670                 // We found one image that can be used in rendering, exit the loop
671                 break;
672             }
673         }
674     }
675 
676     CompositeOperator compositeOp = CompositeDestinationIn;
677     if (pushTransparencyLayer) {
678         paintInfo.context->setCompositeOperation(CompositeDestinationIn);
679         paintInfo.context->beginTransparencyLayer(1.0f);
680         compositeOp = CompositeSourceOver;
681     }
682 
683     paintFillLayers(paintInfo, Color(), style()->maskLayers(), tx, ty, w, h, compositeOp);
684     paintNinePieceImage(paintInfo.context, tx, ty, w, h, style(), style()->maskBoxImage(), compositeOp);
685 
686     if (pushTransparencyLayer)
687         paintInfo.context->endTransparencyLayer();
688 }
689 
maskClipRect()690 IntRect RenderBox::maskClipRect()
691 {
692     IntRect bbox = borderBoxRect();
693     if (style()->maskBoxImage().image())
694         return bbox;
695 
696     IntRect result;
697     for (const FillLayer* maskLayer = style()->maskLayers(); maskLayer; maskLayer = maskLayer->next()) {
698         if (maskLayer->image()) {
699             IntRect maskRect;
700             IntPoint phase;
701             IntSize tileSize;
702             calculateBackgroundImageGeometry(maskLayer, bbox.x(), bbox.y(), bbox.width(), bbox.height(), maskRect, phase, tileSize);
703             result.unite(maskRect);
704         }
705     }
706     return result;
707 }
708 
paintFillLayers(const PaintInfo & paintInfo,const Color & c,const FillLayer * fillLayer,int tx,int ty,int width,int height,CompositeOperator op)709 void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int width, int height, CompositeOperator op)
710 {
711     if (!fillLayer)
712         return;
713 
714     paintFillLayers(paintInfo, c, fillLayer->next(), tx, ty, width, height, op);
715     paintFillLayer(paintInfo, c, fillLayer, tx, ty, width, height, op);
716 }
717 
paintFillLayer(const PaintInfo & paintInfo,const Color & c,const FillLayer * fillLayer,int tx,int ty,int width,int height,CompositeOperator op)718 void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int width, int height, CompositeOperator op)
719 {
720     paintFillLayerExtended(paintInfo, c, fillLayer, tx, ty, width, height, 0, op);
721 }
722 
imageChanged(WrappedImagePtr image,const IntRect *)723 void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*)
724 {
725     if (!parent())
726         return;
727 
728     if ((style()->borderImage().image() && style()->borderImage().image()->data() == image) ||
729         (style()->maskBoxImage().image() && style()->maskBoxImage().image()->data() == image)) {
730         repaint();
731         return;
732     }
733 
734     bool didFullRepaint = repaintLayerRectsForImage(image, style()->backgroundLayers(), true);
735     if (!didFullRepaint)
736         repaintLayerRectsForImage(image, style()->maskLayers(), false);
737 }
738 
repaintLayerRectsForImage(WrappedImagePtr image,const FillLayer * layers,bool drawingBackground)739 bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer* layers, bool drawingBackground)
740 {
741     IntRect rendererRect;
742     RenderBox* layerRenderer = 0;
743 
744     for (const FillLayer* curLayer = layers; curLayer; curLayer = curLayer->next()) {
745         if (curLayer->image() && image == curLayer->image()->data() && curLayer->image()->canRender(style()->effectiveZoom())) {
746             // Now that we know this image is being used, compute the renderer and the rect
747             // if we haven't already
748             if (!layerRenderer) {
749                 bool drawingRootBackground = drawingBackground && (isRoot() || (isBody() && !document()->documentElement()->renderer()->style()->hasBackground()));
750                 if (drawingRootBackground) {
751                     layerRenderer = view();
752 
753                     int rw;
754                     int rh;
755 
756                     if (FrameView* frameView = toRenderView(layerRenderer)->frameView()) {
757                         rw = frameView->contentsWidth();
758                         rh = frameView->contentsHeight();
759                     } else {
760                         rw = layerRenderer->width();
761                         rh = layerRenderer->height();
762                     }
763                     rendererRect = IntRect(-layerRenderer->marginLeft(),
764                         -layerRenderer->marginTop(),
765                         max(layerRenderer->width() + layerRenderer->marginLeft() + layerRenderer->marginRight() + layerRenderer->borderLeft() + layerRenderer->borderRight(), rw),
766                         max(layerRenderer->height() + layerRenderer->marginTop() + layerRenderer->marginBottom() + layerRenderer->borderTop() + layerRenderer->borderBottom(), rh));
767                 } else {
768                     layerRenderer = this;
769                     rendererRect = borderBoxRect();
770                 }
771             }
772 
773             IntRect repaintRect;
774             IntPoint phase;
775             IntSize tileSize;
776             layerRenderer->calculateBackgroundImageGeometry(curLayer, rendererRect.x(), rendererRect.y(), rendererRect.width(), rendererRect.height(), repaintRect, phase, tileSize);
777             layerRenderer->repaintRectangle(repaintRect);
778             if (repaintRect == rendererRect)
779                 return true;
780         }
781     }
782     return false;
783 }
784 
785 #if PLATFORM(MAC)
786 
paintCustomHighlight(int tx,int ty,const AtomicString & type,bool behindText)787 void RenderBox::paintCustomHighlight(int tx, int ty, const AtomicString& type, bool behindText)
788 {
789     Frame* frame = document()->frame();
790     if (!frame)
791         return;
792     Page* page = frame->page();
793     if (!page)
794         return;
795 
796     InlineBox* boxWrap = inlineBoxWrapper();
797     RootInlineBox* r = boxWrap ? boxWrap->root() : 0;
798     if (r) {
799         FloatRect rootRect(tx + r->x(), ty + r->selectionTop(), r->width(), r->selectionHeight());
800         FloatRect imageRect(tx + x(), rootRect.y(), width(), rootRect.height());
801         page->chrome()->client()->paintCustomHighlight(node(), type, imageRect, rootRect, behindText, false);
802     } else {
803         FloatRect imageRect(tx + x(), ty + y(), width(), height());
804         page->chrome()->client()->paintCustomHighlight(node(), type, imageRect, imageRect, behindText, false);
805     }
806 }
807 
808 #endif
809 
pushContentsClip(PaintInfo & paintInfo,int tx,int ty)810 bool RenderBox::pushContentsClip(PaintInfo& paintInfo, int tx, int ty)
811 {
812     if (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == PaintPhaseSelfOutline || paintInfo.phase == PaintPhaseMask)
813         return false;
814 
815     bool isControlClip = hasControlClip();
816     bool isOverflowClip = hasOverflowClip() && !layer()->isSelfPaintingLayer();
817 
818     if (!isControlClip && !isOverflowClip)
819         return false;
820 
821     if (paintInfo.phase == PaintPhaseOutline)
822         paintInfo.phase = PaintPhaseChildOutlines;
823     else if (paintInfo.phase == PaintPhaseChildBlockBackground) {
824         paintInfo.phase = PaintPhaseBlockBackground;
825         paintObject(paintInfo, tx, ty);
826         paintInfo.phase = PaintPhaseChildBlockBackgrounds;
827     }
828     IntRect clipRect(isControlClip ? controlClipRect(tx, ty) : overflowClipRect(tx, ty));
829     paintInfo.context->save();
830     if (style()->hasBorderRadius()) {
831         IntSize topLeft, topRight, bottomLeft, bottomRight;
832         IntRect borderRect = IntRect(tx, ty, width(), height());
833         style()->getBorderRadiiForRect(borderRect, topLeft, topRight, bottomLeft, bottomRight);
834 
835         paintInfo.context->addRoundedRectClip(borderRect, topLeft, topRight, bottomLeft, bottomRight);
836     }
837 
838     paintInfo.context->clip(clipRect);
839     return true;
840 }
841 
popContentsClip(PaintInfo & paintInfo,PaintPhase originalPhase,int tx,int ty)842 void RenderBox::popContentsClip(PaintInfo& paintInfo, PaintPhase originalPhase, int tx, int ty)
843 {
844     ASSERT(hasControlClip() || (hasOverflowClip() && !layer()->isSelfPaintingLayer()));
845 
846     paintInfo.context->restore();
847     if (originalPhase == PaintPhaseOutline) {
848         paintInfo.phase = PaintPhaseSelfOutline;
849         paintObject(paintInfo, tx, ty);
850         paintInfo.phase = originalPhase;
851     } else if (originalPhase == PaintPhaseChildBlockBackground)
852         paintInfo.phase = originalPhase;
853 }
854 
overflowClipRect(int tx,int ty)855 IntRect RenderBox::overflowClipRect(int tx, int ty)
856 {
857     // FIXME: When overflow-clip (CSS3) is implemented, we'll obtain the property
858     // here.
859 
860     int bLeft = borderLeft();
861     int bTop = borderTop();
862 
863     int clipX = tx + bLeft;
864     int clipY = ty + bTop;
865     int clipWidth = width() - bLeft - borderRight();
866     int clipHeight = height() - bTop - borderBottom();
867 
868     // Subtract out scrollbars if we have them.
869     if (layer()) {
870         clipWidth -= layer()->verticalScrollbarWidth();
871         clipHeight -= layer()->horizontalScrollbarHeight();
872     }
873 
874     return IntRect(clipX, clipY, clipWidth, clipHeight);
875 }
876 
clipRect(int tx,int ty)877 IntRect RenderBox::clipRect(int tx, int ty)
878 {
879     int clipX = tx;
880     int clipY = ty;
881     int clipWidth = width();
882     int clipHeight = height();
883 
884     if (!style()->clipLeft().isAuto()) {
885         int c = style()->clipLeft().calcValue(width());
886         clipX += c;
887         clipWidth -= c;
888     }
889 
890     if (!style()->clipRight().isAuto())
891         clipWidth -= width() - style()->clipRight().calcValue(width());
892 
893     if (!style()->clipTop().isAuto()) {
894         int c = style()->clipTop().calcValue(height());
895         clipY += c;
896         clipHeight -= c;
897     }
898 
899     if (!style()->clipBottom().isAuto())
900         clipHeight -= height() - style()->clipBottom().calcValue(height());
901 
902     return IntRect(clipX, clipY, clipWidth, clipHeight);
903 }
904 
containingBlockWidthForContent() const905 int RenderBox::containingBlockWidthForContent() const
906 {
907     RenderBlock* cb = containingBlock();
908     if (shrinkToAvoidFloats())
909         return cb->lineWidth(y(), false);
910     return cb->availableWidth();
911 }
912 
mapLocalToContainer(RenderBoxModelObject * repaintContainer,bool fixed,bool useTransforms,TransformState & transformState) const913 void RenderBox::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState) const
914 {
915     if (repaintContainer == this)
916         return;
917 
918     if (RenderView* v = view()) {
919         if (v->layoutStateEnabled() && !repaintContainer) {
920             LayoutState* layoutState = v->layoutState();
921             IntSize offset = layoutState->m_offset;
922             offset.expand(x(), y());
923             if (style()->position() == RelativePosition && layer())
924                 offset += layer()->relativePositionOffset();
925             transformState.move(offset);
926             return;
927         }
928     }
929 
930     if (style()->position() == FixedPosition)
931         fixed = true;
932 
933     RenderObject* o = container();
934     if (!o)
935         return;
936 
937     bool hasTransform = hasLayer() && layer()->transform();
938     if (hasTransform)
939         fixed = false;  // Elements with transforms act as a containing block for fixed position descendants
940 
941     IntSize containerOffset = offsetFromContainer(o);
942 
943     bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
944     if (useTransforms && shouldUseTransformFromContainer(o)) {
945         TransformationMatrix t;
946         getTransformFromContainer(o, containerOffset, t);
947         transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
948     } else
949         transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
950 
951     o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState);
952 }
953 
mapAbsoluteToLocalPoint(bool fixed,bool useTransforms,TransformState & transformState) const954 void RenderBox::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const
955 {
956     // We don't expect absoluteToLocal() to be called during layout (yet)
957     ASSERT(!view() || !view()->layoutStateEnabled());
958 
959     if (style()->position() == FixedPosition)
960         fixed = true;
961 
962     bool hasTransform = hasLayer() && layer()->transform();
963     if (hasTransform)
964         fixed = false;  // Elements with transforms act as a containing block for fixed position descendants
965 
966     RenderObject* o = container();
967     if (!o)
968         return;
969 
970     o->mapAbsoluteToLocalPoint(fixed, useTransforms, transformState);
971 
972     IntSize containerOffset = offsetFromContainer(o);
973 
974     bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
975     if (useTransforms && shouldUseTransformFromContainer(o)) {
976         TransformationMatrix t;
977         getTransformFromContainer(o, containerOffset, t);
978         transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
979     } else
980         transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
981 }
982 
offsetFromContainer(RenderObject * o) const983 IntSize RenderBox::offsetFromContainer(RenderObject* o) const
984 {
985     ASSERT(o == container());
986 
987     IntSize offset;
988     if (isRelPositioned())
989         offset += relativePositionOffset();
990 
991     if (!isInline() || isReplaced()) {
992         RenderBlock* cb;
993         if (o->isBlockFlow() && style()->position() != AbsolutePosition && style()->position() != FixedPosition
994                 && (cb = toRenderBlock(o))->hasColumns()) {
995             IntRect rect(x(), y(), 1, 1);
996             cb->adjustRectForColumns(rect);
997             offset.expand(rect.x(), rect.y());
998         } else
999             offset.expand(x(), y());
1000     }
1001 
1002     if (o->hasOverflowClip())
1003         offset -= toRenderBox(o)->layer()->scrolledContentOffset();
1004 
1005     if (style()->position() == AbsolutePosition && o->isRelPositioned() && o->isRenderInline())
1006         offset += toRenderInline(o)->relativePositionedInlineOffset(this);
1007 
1008     return offset;
1009 }
1010 
createInlineBox()1011 InlineBox* RenderBox::createInlineBox()
1012 {
1013     return new (renderArena()) InlineBox(this);
1014 }
1015 
dirtyLineBoxes(bool fullLayout)1016 void RenderBox::dirtyLineBoxes(bool fullLayout)
1017 {
1018     if (m_inlineBoxWrapper) {
1019         if (fullLayout) {
1020             m_inlineBoxWrapper->destroy(renderArena());
1021             m_inlineBoxWrapper = 0;
1022         } else
1023             m_inlineBoxWrapper->dirtyLineBoxes();
1024     }
1025 }
1026 
positionLineBox(InlineBox * box)1027 void RenderBox::positionLineBox(InlineBox* box)
1028 {
1029     if (isPositioned()) {
1030         // Cache the x position only if we were an INLINE type originally.
1031         bool wasInline = style()->isOriginalDisplayInlineType();
1032         if (wasInline && style()->hasStaticX()) {
1033             // The value is cached in the xPos of the box.  We only need this value if
1034             // our object was inline originally, since otherwise it would have ended up underneath
1035             // the inlines.
1036             layer()->setStaticX(box->x());
1037             setChildNeedsLayout(true, false); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
1038         } else if (!wasInline && style()->hasStaticY()) {
1039             // Our object was a block originally, so we make our normal flow position be
1040             // just below the line box (as though all the inlines that came before us got
1041             // wrapped in an anonymous block, which is what would have happened had we been
1042             // in flow).  This value was cached in the y() of the box.
1043             layer()->setStaticY(box->y());
1044             setChildNeedsLayout(true, false); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
1045         }
1046 
1047         // Nuke the box.
1048         box->remove();
1049         box->destroy(renderArena());
1050     } else if (isReplaced()) {
1051         setLocation(box->x(), box->y());
1052         m_inlineBoxWrapper = box;
1053     }
1054 }
1055 
deleteLineBoxWrapper()1056 void RenderBox::deleteLineBoxWrapper()
1057 {
1058     if (m_inlineBoxWrapper) {
1059         if (!documentBeingDestroyed())
1060             m_inlineBoxWrapper->remove();
1061         m_inlineBoxWrapper->destroy(renderArena());
1062         m_inlineBoxWrapper = 0;
1063     }
1064 }
1065 
clippedOverflowRectForRepaint(RenderBoxModelObject * repaintContainer)1066 IntRect RenderBox::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
1067 {
1068     if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent())
1069         return IntRect();
1070 
1071     IntRect r = overflowRect(false);
1072 
1073     RenderView* v = view();
1074     if (v) {
1075         // FIXME: layoutDelta needs to be applied in parts before/after transforms and
1076         // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
1077         r.move(v->layoutDelta());
1078     }
1079 
1080     if (style()) {
1081         if (style()->hasAppearance())
1082             // The theme may wish to inflate the rect used when repainting.
1083             theme()->adjustRepaintRect(this, r);
1084 
1085         // We have to use maximalOutlineSize() because a child might have an outline
1086         // that projects outside of our overflowRect.
1087         if (v) {
1088             ASSERT(style()->outlineSize() <= v->maximalOutlineSize());
1089             r.inflate(v->maximalOutlineSize());
1090         }
1091     }
1092     computeRectForRepaint(repaintContainer, r);
1093     return r;
1094 }
1095 
computeRectForRepaint(RenderBoxModelObject * repaintContainer,IntRect & rect,bool fixed)1096 void RenderBox::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& rect, bool fixed)
1097 {
1098     if (RenderView* v = view()) {
1099         // LayoutState is only valid for root-relative repainting
1100         if (v->layoutStateEnabled() && !repaintContainer) {
1101             LayoutState* layoutState = v->layoutState();
1102 
1103             if (layer() && layer()->transform())
1104                 rect = layer()->transform()->mapRect(rect);
1105 
1106             if (style()->position() == RelativePosition && layer())
1107                 rect.move(layer()->relativePositionOffset());
1108 
1109             rect.move(x(), y());
1110             rect.move(layoutState->m_offset);
1111             if (layoutState->m_clipped)
1112                 rect.intersect(layoutState->m_clipRect);
1113             return;
1114         }
1115     }
1116 
1117     if (hasReflection())
1118         rect.unite(reflectedRect(rect));
1119 
1120     if (repaintContainer == this)
1121         return;
1122 
1123     RenderObject* o = container();
1124     if (!o)
1125         return;
1126 
1127     IntPoint topLeft = rect.location();
1128     topLeft.move(x(), y());
1129 
1130     if (style()->position() == FixedPosition)
1131         fixed = true;
1132 
1133     if (o->isBlockFlow() && style()->position() != AbsolutePosition && style()->position() != FixedPosition) {
1134         RenderBlock* cb = toRenderBlock(o);
1135         if (cb->hasColumns()) {
1136             IntRect repaintRect(topLeft, rect.size());
1137             cb->adjustRectForColumns(repaintRect);
1138             topLeft = repaintRect.location();
1139             rect = repaintRect;
1140         }
1141     }
1142 
1143     // We are now in our parent container's coordinate space.  Apply our transform to obtain a bounding box
1144     // in the parent's coordinate space that encloses us.
1145     if (layer() && layer()->transform()) {
1146         fixed = false;
1147         rect = layer()->transform()->mapRect(rect);
1148         // FIXME: this clobbers topLeft adjustment done for multicol above
1149         topLeft = rect.location();
1150         topLeft.move(x(), y());
1151     }
1152 
1153     if (style()->position() == AbsolutePosition && o->isRelPositioned() && o->isRenderInline())
1154         topLeft += toRenderInline(o)->relativePositionedInlineOffset(this);
1155     else if (style()->position() == RelativePosition && layer()) {
1156         // Apply the relative position offset when invalidating a rectangle.  The layer
1157         // is translated, but the render box isn't, so we need to do this to get the
1158         // right dirty rect.  Since this is called from RenderObject::setStyle, the relative position
1159         // flag on the RenderObject has been cleared, so use the one on the style().
1160         topLeft += layer()->relativePositionOffset();
1161     }
1162 
1163     // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
1164     // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
1165     if (o->hasOverflowClip()) {
1166         RenderBox* containerBox = toRenderBox(o);
1167 
1168         // o->height() is inaccurate if we're in the middle of a layout of |o|, so use the
1169         // layer's size instead.  Even if the layer's size is wrong, the layer itself will repaint
1170         // anyway if its size does change.
1171         topLeft -= containerBox->layer()->scrolledContentOffset(); // For overflow:auto/scroll/hidden.
1172 
1173         IntRect repaintRect(topLeft, rect.size());
1174         IntRect boxRect(0, 0, containerBox->layer()->width(), containerBox->layer()->height());
1175         rect = intersection(repaintRect, boxRect);
1176         if (rect.isEmpty())
1177             return;
1178     } else
1179         rect.setLocation(topLeft);
1180 
1181     o->computeRectForRepaint(repaintContainer, rect, fixed);
1182 }
1183 
repaintDuringLayoutIfMoved(const IntRect & rect)1184 void RenderBox::repaintDuringLayoutIfMoved(const IntRect& rect)
1185 {
1186     int newX = x();
1187     int newY = y();
1188     int newWidth = width();
1189     int newHeight = height();
1190     if (rect.x() != newX || rect.y() != newY) {
1191         // The child moved.  Invalidate the object's old and new positions.  We have to do this
1192         // since the object may not have gotten a layout.
1193         m_frameRect = rect;
1194         repaint();
1195         repaintOverhangingFloats(true);
1196         m_frameRect = IntRect(newX, newY, newWidth, newHeight);
1197         repaint();
1198         repaintOverhangingFloats(true);
1199     }
1200 }
1201 
calcWidth()1202 void RenderBox::calcWidth()
1203 {
1204 #ifdef ANDROID_LAYOUT
1205     if (view()->frameView()) {
1206         const Settings* settings = document()->settings();
1207         ASSERT(settings);
1208         if (settings->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen) {
1209             m_visibleWidth = view()->frameView()->screenWidth();
1210         }
1211     }
1212 #endif
1213 
1214     if (isPositioned()) {
1215         calcAbsoluteHorizontal();
1216         return;
1217     }
1218 
1219     // If layout is limited to a subtree, the subtree root's width does not change.
1220     if (node() && view()->frameView() && view()->frameView()->layoutRoot(true) == this)
1221         return;
1222 
1223     // The parent box is flexing us, so it has increased or decreased our
1224     // width.  Use the width from the style context.
1225     if (hasOverrideSize() &&  parent()->style()->boxOrient() == HORIZONTAL
1226             && parent()->isFlexibleBox() && parent()->isFlexingChildren()) {
1227         setWidth(overrideSize());
1228         return;
1229     }
1230 
1231     bool inVerticalBox = parent()->isFlexibleBox() && (parent()->style()->boxOrient() == VERTICAL);
1232     bool stretching = (parent()->style()->boxAlign() == BSTRETCH);
1233     bool treatAsReplaced = shouldCalculateSizeAsReplaced() && (!inVerticalBox || !stretching);
1234 
1235     Length w = (treatAsReplaced) ? Length(calcReplacedWidth(), Fixed) : style()->width();
1236 
1237     RenderBlock* cb = containingBlock();
1238     int containerWidth = max(0, containingBlockWidthForContent());
1239 
1240     Length marginLeft = style()->marginLeft();
1241     Length marginRight = style()->marginRight();
1242 
1243     if (isInline() && !isInlineBlockOrInlineTable()) {
1244         // just calculate margins
1245         m_marginLeft = marginLeft.calcMinValue(containerWidth);
1246         m_marginRight = marginRight.calcMinValue(containerWidth);
1247 #ifdef ANDROID_LAYOUT
1248         if (treatAsReplaced) {
1249 #else
1250         if (treatAsReplaced)
1251 #endif
1252             setWidth(max(w.value() + borderLeft() + borderRight() + paddingLeft() + paddingRight(), minPrefWidth()));
1253 #ifdef ANDROID_LAYOUT
1254             // in SSR mode with replaced box, if the box width is wider than the container width,
1255             // it will be shrinked to fit to the container.
1256             if (containerWidth && (width() + m_marginLeft + m_marginRight) > containerWidth &&
1257                     document()->frame()->settings()->layoutAlgorithm() == Settings::kLayoutSSR) {
1258                 m_marginLeft = m_marginRight = 0;
1259                 setWidth(containerWidth);
1260                 m_minPrefWidth = m_maxPrefWidth = containerWidth;
1261             }
1262         }
1263 #endif
1264         return;
1265     }
1266 
1267     // Width calculations
1268     if (treatAsReplaced)
1269         setWidth(w.value() + borderLeft() + borderRight() + paddingLeft() + paddingRight());
1270     else {
1271         // Calculate Width
1272         setWidth(calcWidthUsing(Width, containerWidth));
1273 
1274         // Calculate MaxWidth
1275         if (!style()->maxWidth().isUndefined()) {
1276             int maxW = calcWidthUsing(MaxWidth, containerWidth);
1277             if (width() > maxW) {
1278                 setWidth(maxW);
1279                 w = style()->maxWidth();
1280             }
1281         }
1282 
1283         // Calculate MinWidth
1284         int minW = calcWidthUsing(MinWidth, containerWidth);
1285         if (width() < minW) {
1286             setWidth(minW);
1287             w = style()->minWidth();
1288         }
1289     }
1290 
1291     if (stretchesToMinIntrinsicWidth()) {
1292         setWidth(max(width(), minPrefWidth()));
1293         w = Length(width(), Fixed);
1294     }
1295 
1296     // Margin calculations
1297     if (w.isAuto()) {
1298         m_marginLeft = marginLeft.calcMinValue(containerWidth);
1299         m_marginRight = marginRight.calcMinValue(containerWidth);
1300     } else {
1301         m_marginLeft = 0;
1302         m_marginRight = 0;
1303         calcHorizontalMargins(marginLeft, marginRight, containerWidth);
1304     }
1305 #ifdef ANDROID_LAYOUT
1306     // in SSR mode with non-replaced box, we use ANDROID_SSR_MARGIN_PADDING for left/right margin.
1307     // If the box width is wider than the container width, it will be shrinked to fit to the container.
1308     if (containerWidth && !treatAsReplaced &&
1309             document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR) {
1310         setWidth(width() + m_marginLeft + m_marginRight);
1311         m_marginLeft = m_marginLeft > ANDROID_SSR_MARGIN_PADDING ? ANDROID_SSR_MARGIN_PADDING : m_marginLeft;
1312         m_marginRight = m_marginRight > ANDROID_SSR_MARGIN_PADDING ? ANDROID_SSR_MARGIN_PADDING : m_marginRight;
1313         if (width() > containerWidth) {
1314             m_minPrefWidth = m_maxPrefWidth = containerWidth-(m_marginLeft + m_marginRight);
1315             setWidth(m_minPrefWidth);
1316         } else
1317             setWidth(width() -(m_marginLeft + m_marginRight));
1318     }
1319 #endif
1320 
1321     if (containerWidth && containerWidth != (width() + m_marginLeft + m_marginRight)
1322             && !isFloating() && !isInline() && !cb->isFlexibleBox()) {
1323         if (cb->style()->direction() == LTR)
1324             m_marginRight = containerWidth - width() - m_marginLeft;
1325         else
1326             m_marginLeft = containerWidth - width() - m_marginRight;
1327     }
1328 }
1329 
calcWidthUsing(WidthType widthType,int cw)1330 int RenderBox::calcWidthUsing(WidthType widthType, int cw)
1331 {
1332     int widthResult = width();
1333     Length w;
1334     if (widthType == Width)
1335         w = style()->width();
1336     else if (widthType == MinWidth)
1337         w = style()->minWidth();
1338     else
1339         w = style()->maxWidth();
1340 
1341     if (w.isIntrinsicOrAuto()) {
1342         int marginLeft = style()->marginLeft().calcMinValue(cw);
1343         int marginRight = style()->marginRight().calcMinValue(cw);
1344         if (cw)
1345             widthResult = cw - marginLeft - marginRight;
1346 
1347         if (sizesToIntrinsicWidth(widthType)) {
1348             widthResult = max(widthResult, minPrefWidth());
1349             widthResult = min(widthResult, maxPrefWidth());
1350         }
1351     } else
1352         widthResult = calcBorderBoxWidth(w.calcValue(cw));
1353 
1354     return widthResult;
1355 }
1356 
sizesToIntrinsicWidth(WidthType widthType) const1357 bool RenderBox::sizesToIntrinsicWidth(WidthType widthType) const
1358 {
1359     // Marquees in WinIE are like a mixture of blocks and inline-blocks.  They size as though they're blocks,
1360     // but they allow text to sit on the same line as the marquee.
1361     if (isFloating() || (isInlineBlockOrInlineTable() && !isHTMLMarquee()))
1362         return true;
1363 
1364     // This code may look a bit strange.  Basically width:intrinsic should clamp the size when testing both
1365     // min-width and width.  max-width is only clamped if it is also intrinsic.
1366     Length width = (widthType == MaxWidth) ? style()->maxWidth() : style()->width();
1367     if (width.type() == Intrinsic)
1368         return true;
1369 
1370     // Children of a horizontal marquee do not fill the container by default.
1371     // FIXME: Need to deal with MAUTO value properly.  It could be vertical.
1372     if (parent()->style()->overflowX() == OMARQUEE) {
1373         EMarqueeDirection dir = parent()->style()->marqueeDirection();
1374         if (dir == MAUTO || dir == MFORWARD || dir == MBACKWARD || dir == MLEFT || dir == MRIGHT)
1375             return true;
1376     }
1377 
1378     // Flexible horizontal boxes lay out children at their intrinsic widths.  Also vertical boxes
1379     // that don't stretch their kids lay out their children at their intrinsic widths.
1380     if (parent()->isFlexibleBox()
1381             && (parent()->style()->boxOrient() == HORIZONTAL || parent()->style()->boxAlign() != BSTRETCH))
1382         return true;
1383 
1384     return false;
1385 }
1386 
calcHorizontalMargins(const Length & marginLeft,const Length & marginRight,int containerWidth)1387 void RenderBox::calcHorizontalMargins(const Length& marginLeft, const Length& marginRight, int containerWidth)
1388 {
1389     if (isFloating() || isInline()) {
1390         // Inline blocks/tables and floats don't have their margins increased.
1391         m_marginLeft = marginLeft.calcMinValue(containerWidth);
1392         m_marginRight = marginRight.calcMinValue(containerWidth);
1393         return;
1394     }
1395 
1396     if ((marginLeft.isAuto() && marginRight.isAuto() && width() < containerWidth)
1397             || (!marginLeft.isAuto() && !marginRight.isAuto() && containingBlock()->style()->textAlign() == WEBKIT_CENTER)) {
1398         m_marginLeft = max(0, (containerWidth - width()) / 2);
1399         m_marginRight = containerWidth - width() - m_marginLeft;
1400     } else if ((marginRight.isAuto() && width() < containerWidth)
1401             || (!marginLeft.isAuto() && containingBlock()->style()->direction() == RTL && containingBlock()->style()->textAlign() == WEBKIT_LEFT)) {
1402         m_marginLeft = marginLeft.calcValue(containerWidth);
1403         m_marginRight = containerWidth - width() - m_marginLeft;
1404     } else if ((marginLeft.isAuto() && width() < containerWidth)
1405             || (!marginRight.isAuto() && containingBlock()->style()->direction() == LTR && containingBlock()->style()->textAlign() == WEBKIT_RIGHT)) {
1406         m_marginRight = marginRight.calcValue(containerWidth);
1407         m_marginLeft = containerWidth - width() - m_marginRight;
1408     } else {
1409         // This makes auto margins 0 if we failed a width() < containerWidth test above (css2.1, 10.3.3).
1410         m_marginLeft = marginLeft.calcMinValue(containerWidth);
1411         m_marginRight = marginRight.calcMinValue(containerWidth);
1412     }
1413 }
1414 
calcHeight()1415 void RenderBox::calcHeight()
1416 {
1417     // Cell height is managed by the table and inline non-replaced elements do not support a height property.
1418     if (isTableCell() || (isInline() && !isReplaced()))
1419         return;
1420 
1421     Length h;
1422     if (isPositioned())
1423         calcAbsoluteVertical();
1424     else {
1425         calcVerticalMargins();
1426 
1427         // For tables, calculate margins only.
1428         if (isTable())
1429             return;
1430 
1431         bool inHorizontalBox = parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL;
1432         bool stretching = parent()->style()->boxAlign() == BSTRETCH;
1433         bool treatAsReplaced = shouldCalculateSizeAsReplaced() && (!inHorizontalBox || !stretching);
1434         bool checkMinMaxHeight = false;
1435 
1436         // The parent box is flexing us, so it has increased or decreased our height.  We have to
1437         // grab our cached flexible height.
1438         if (hasOverrideSize() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == VERTICAL
1439                 && parent()->isFlexingChildren())
1440             h = Length(overrideSize() - borderTop() - borderBottom() - paddingTop() - paddingBottom(), Fixed);
1441         else if (treatAsReplaced)
1442             h = Length(calcReplacedHeight(), Fixed);
1443         else {
1444             h = style()->height();
1445             checkMinMaxHeight = true;
1446         }
1447 
1448         // Block children of horizontal flexible boxes fill the height of the box.
1449         if (h.isAuto() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
1450                 && parent()->isStretchingChildren()) {
1451             h = Length(parentBox()->contentHeight() - marginTop() - marginBottom() -
1452                        borderTop() - paddingTop() - borderBottom() - paddingBottom(), Fixed);
1453             checkMinMaxHeight = false;
1454         }
1455 
1456         int heightResult;
1457         if (checkMinMaxHeight) {
1458 #ifdef ANDROID_LAYOUT
1459             // in SSR mode, ignore CSS height as layout is so different
1460             if (document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR)
1461                 heightResult = -1;
1462             else
1463 #endif
1464             heightResult = calcHeightUsing(style()->height());
1465             if (heightResult == -1)
1466                 heightResult = height();
1467             int minH = calcHeightUsing(style()->minHeight()); // Leave as -1 if unset.
1468             int maxH = style()->maxHeight().isUndefined() ? heightResult : calcHeightUsing(style()->maxHeight());
1469             if (maxH == -1)
1470                 maxH = heightResult;
1471             heightResult = min(maxH, heightResult);
1472             heightResult = max(minH, heightResult);
1473         } else {
1474             // The only times we don't check min/max height are when a fixed length has
1475             // been given as an override.  Just use that.  The value has already been adjusted
1476             // for box-sizing.
1477             heightResult = h.value() + borderTop() + borderBottom() + paddingTop() + paddingBottom();
1478         }
1479 
1480         setHeight(heightResult);
1481     }
1482 
1483     // WinIE quirk: The <html> block always fills the entire canvas in quirks mode.  The <body> always fills the
1484     // <html> block in quirks mode.  Only apply this quirk if the block is normal flow and no height
1485     // is specified. When we're printing, we also need this quirk if the body or root has a percentage
1486     // height since we don't set a height in RenderView when we're printing. So without this quirk, the
1487     // height has nothing to be a percentage of, and it ends up being 0. That is bad.
1488     bool printingNeedsBaseHeight = document()->printing() && h.isPercent()
1489         && (isRoot() || isBody() && document()->documentElement()->renderer()->style()->height().isPercent());
1490     if (stretchesToViewHeight() || printingNeedsBaseHeight) {
1491         int margins = collapsedMarginTop() + collapsedMarginBottom();
1492         int visHeight = document()->printing() ? view()->frameView()->visibleHeight() : view()->viewHeight();
1493         if (isRoot())
1494             setHeight(max(height(), visHeight - margins));
1495         else {
1496             int marginsBordersPadding = margins + parentBox()->marginTop() + parentBox()->marginBottom()
1497                 + parentBox()->borderTop() + parentBox()->borderBottom()
1498                 + parentBox()->paddingTop() + parentBox()->paddingBottom();
1499             setHeight(max(height(), visHeight - marginsBordersPadding));
1500         }
1501     }
1502 }
1503 
calcHeightUsing(const Length & h)1504 int RenderBox::calcHeightUsing(const Length& h)
1505 {
1506     int height = -1;
1507     if (!h.isAuto()) {
1508         if (h.isFixed())
1509             height = h.value();
1510         else if (h.isPercent())
1511             height = calcPercentageHeight(h);
1512         if (height != -1) {
1513             height = calcBorderBoxHeight(height);
1514             return height;
1515         }
1516     }
1517     return height;
1518 }
1519 
calcPercentageHeight(const Length & height)1520 int RenderBox::calcPercentageHeight(const Length& height)
1521 {
1522     int result = -1;
1523     bool includeBorderPadding = isTable();
1524     RenderBlock* cb = containingBlock();
1525     if (style()->htmlHacks()) {
1526         // In quirks mode, blocks with auto height are skipped, and we keep looking for an enclosing
1527         // block that may have a specified height and then use it.  In strict mode, this violates the
1528         // specification, which states that percentage heights just revert to auto if the containing
1529         // block has an auto height.
1530         while (!cb->isRenderView() && !cb->isBody() && !cb->isTableCell() && !cb->isPositioned() && cb->style()->height().isAuto()) {
1531             cb = cb->containingBlock();
1532             cb->addPercentHeightDescendant(this);
1533         }
1534     }
1535 
1536     // A positioned element that specified both top/bottom or that specifies height should be treated as though it has a height
1537     // explicitly specified that can be used for any percentage computations.
1538     bool isPositionedWithSpecifiedHeight = cb->isPositioned() && (!cb->style()->height().isAuto() || (!cb->style()->top().isAuto() && !cb->style()->bottom().isAuto()));
1539 
1540     // Table cells violate what the CSS spec says to do with heights.  Basically we
1541     // don't care if the cell specified a height or not.  We just always make ourselves
1542     // be a percentage of the cell's current content height.
1543     if (cb->isTableCell()) {
1544         result = cb->overrideSize();
1545         if (result == -1) {
1546             // Normally we would let the cell size intrinsically, but scrolling overflow has to be
1547             // treated differently, since WinIE lets scrolled overflow regions shrink as needed.
1548             // While we can't get all cases right, we can at least detect when the cell has a specified
1549             // height or when the table has a specified height.  In these cases we want to initially have
1550             // no size and allow the flexing of the table or the cell to its specified height to cause us
1551             // to grow to fill the space.  This could end up being wrong in some cases, but it is
1552             // preferable to the alternative (sizing intrinsically and making the row end up too big).
1553             RenderTableCell* cell = toRenderTableCell(cb);
1554             if (scrollsOverflowY() && (!cell->style()->height().isAuto() || !cell->table()->style()->height().isAuto()))
1555                 return 0;
1556             return -1;
1557         }
1558         includeBorderPadding = true;
1559     }
1560     // Otherwise we only use our percentage height if our containing block had a specified
1561     // height.
1562     else if (cb->style()->height().isFixed())
1563         result = cb->calcContentBoxHeight(cb->style()->height().value());
1564     else if (cb->style()->height().isPercent() && !isPositionedWithSpecifiedHeight) {
1565         // We need to recur and compute the percentage height for our containing block.
1566         result = cb->calcPercentageHeight(cb->style()->height());
1567         if (result != -1)
1568             result = cb->calcContentBoxHeight(result);
1569     } else if (cb->isRenderView() || (cb->isBody() && style()->htmlHacks()) || isPositionedWithSpecifiedHeight) {
1570         // Don't allow this to affect the block' height() member variable, since this
1571         // can get called while the block is still laying out its kids.
1572         int oldHeight = cb->height();
1573         cb->calcHeight();
1574         result = cb->contentHeight();
1575         cb->setHeight(oldHeight);
1576     } else if (cb->isRoot() && isPositioned())
1577         // Match the positioned objects behavior, which is that positioned objects will fill their viewport
1578         // always.  Note we could only hit this case by recurring into calcPercentageHeight on a positioned containing block.
1579         result = cb->calcContentBoxHeight(cb->availableHeight());
1580 
1581     if (result != -1) {
1582         result = height.calcValue(result);
1583         if (includeBorderPadding) {
1584             // It is necessary to use the border-box to match WinIE's broken
1585             // box model.  This is essential for sizing inside
1586             // table cells using percentage heights.
1587             result -= (borderTop() + paddingTop() + borderBottom() + paddingBottom());
1588             result = max(0, result);
1589         }
1590     }
1591     return result;
1592 }
1593 
calcReplacedWidth(bool includeMaxWidth) const1594 int RenderBox::calcReplacedWidth(bool includeMaxWidth) const
1595 {
1596     int width = calcReplacedWidthUsing(style()->width());
1597     int minW = calcReplacedWidthUsing(style()->minWidth());
1598     int maxW = !includeMaxWidth || style()->maxWidth().isUndefined() ? width : calcReplacedWidthUsing(style()->maxWidth());
1599 
1600     return max(minW, min(width, maxW));
1601 }
1602 
calcReplacedWidthUsing(Length width) const1603 int RenderBox::calcReplacedWidthUsing(Length width) const
1604 {
1605     switch (width.type()) {
1606         case Fixed:
1607             return calcContentBoxWidth(width.value());
1608         case Percent: {
1609             const int cw = isPositioned() ? containingBlockWidthForPositioned(toRenderBoxModelObject(container())) : containingBlockWidthForContent();
1610             if (cw > 0)
1611                 return calcContentBoxWidth(width.calcMinValue(cw));
1612         }
1613         // fall through
1614         default:
1615             return intrinsicSize().width();
1616      }
1617 }
1618 
calcReplacedHeight() const1619 int RenderBox::calcReplacedHeight() const
1620 {
1621     int height = calcReplacedHeightUsing(style()->height());
1622     int minH = calcReplacedHeightUsing(style()->minHeight());
1623     int maxH = style()->maxHeight().isUndefined() ? height : calcReplacedHeightUsing(style()->maxHeight());
1624 
1625     return max(minH, min(height, maxH));
1626 }
1627 
calcReplacedHeightUsing(Length height) const1628 int RenderBox::calcReplacedHeightUsing(Length height) const
1629 {
1630     switch (height.type()) {
1631         case Fixed:
1632             return calcContentBoxHeight(height.value());
1633         case Percent:
1634         {
1635             RenderObject* cb = isPositioned() ? container() : containingBlock();
1636             while (cb->isAnonymous()) {
1637                 cb = cb->containingBlock();
1638                 toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this));
1639             }
1640 
1641             if (cb->isPositioned() && cb->style()->height().isAuto() && !(cb->style()->top().isAuto() || cb->style()->bottom().isAuto())) {
1642                 ASSERT(cb->isRenderBlock());
1643                 RenderBlock* block = toRenderBlock(cb);
1644                 int oldHeight = block->height();
1645                 block->calcHeight();
1646                 int newHeight = block->calcContentBoxHeight(block->contentHeight());
1647                 block->setHeight(oldHeight);
1648                 return calcContentBoxHeight(height.calcValue(newHeight));
1649             }
1650 
1651             int availableHeight = isPositioned() ? containingBlockHeightForPositioned(toRenderBoxModelObject(cb)) : toRenderBox(cb)->availableHeight();
1652 
1653             // It is necessary to use the border-box to match WinIE's broken
1654             // box model.  This is essential for sizing inside
1655             // table cells using percentage heights.
1656             if (cb->isTableCell() && (cb->style()->height().isAuto() || cb->style()->height().isPercent())) {
1657                 // Don't let table cells squeeze percent-height replaced elements
1658                 // <http://bugs.webkit.org/show_bug.cgi?id=15359>
1659                 availableHeight = max(availableHeight, intrinsicSize().height());
1660                 return height.calcValue(availableHeight - (borderTop() + borderBottom()
1661                     + paddingTop() + paddingBottom()));
1662             }
1663 
1664             return calcContentBoxHeight(height.calcValue(availableHeight));
1665         }
1666         default:
1667             return intrinsicSize().height();
1668     }
1669 }
1670 
availableHeight() const1671 int RenderBox::availableHeight() const
1672 {
1673     return availableHeightUsing(style()->height());
1674 }
1675 
availableHeightUsing(const Length & h) const1676 int RenderBox::availableHeightUsing(const Length& h) const
1677 {
1678     if (h.isFixed())
1679         return calcContentBoxHeight(h.value());
1680 
1681     if (isRenderView())
1682         return toRenderView(this)->frameView()->visibleHeight();
1683 
1684     // We need to stop here, since we don't want to increase the height of the table
1685     // artificially.  We're going to rely on this cell getting expanded to some new
1686     // height, and then when we lay out again we'll use the calculation below.
1687     if (isTableCell() && (h.isAuto() || h.isPercent()))
1688         return overrideSize() - (borderLeft() + borderRight() + paddingLeft() + paddingRight());
1689 
1690     if (h.isPercent())
1691        return calcContentBoxHeight(h.calcValue(containingBlock()->availableHeight()));
1692 
1693     if (isRenderBlock() && isPositioned() && style()->height().isAuto() && !(style()->top().isAuto() || style()->bottom().isAuto())) {
1694         RenderBlock* block = const_cast<RenderBlock*>(toRenderBlock(this));
1695         int oldHeight = block->height();
1696         block->calcHeight();
1697         int newHeight = block->calcContentBoxHeight(block->contentHeight());
1698         block->setHeight(oldHeight);
1699         return calcContentBoxHeight(newHeight);
1700     }
1701 
1702     return containingBlock()->availableHeight();
1703 }
1704 
calcVerticalMargins()1705 void RenderBox::calcVerticalMargins()
1706 {
1707     if (isTableCell()) {
1708         m_marginTop = 0;
1709         m_marginBottom = 0;
1710         return;
1711     }
1712 
1713     // margins are calculated with respect to the _width_ of
1714     // the containing block (8.3)
1715     int cw = containingBlock()->contentWidth();
1716 
1717     m_marginTop = style()->marginTop().calcMinValue(cw);
1718     m_marginBottom = style()->marginBottom().calcMinValue(cw);
1719 }
1720 
containingBlockWidthForPositioned(const RenderBoxModelObject * containingBlock) const1721 int RenderBox::containingBlockWidthForPositioned(const RenderBoxModelObject* containingBlock) const
1722 {
1723     if (containingBlock->isBox()) {
1724         const RenderBox* containingBlockBox = toRenderBox(containingBlock);
1725         return containingBlockBox->width() - containingBlockBox->borderLeft() - containingBlockBox->borderRight() - containingBlockBox->verticalScrollbarWidth();
1726     }
1727 
1728     ASSERT(containingBlock->isRenderInline() && containingBlock->isRelPositioned());
1729 
1730     const RenderInline* flow = toRenderInline(containingBlock);
1731     InlineFlowBox* first = flow->firstLineBox();
1732     InlineFlowBox* last = flow->lastLineBox();
1733 
1734     // If the containing block is empty, return a width of 0.
1735     if (!first || !last)
1736         return 0;
1737 
1738     int fromLeft;
1739     int fromRight;
1740     if (containingBlock->style()->direction() == LTR) {
1741         fromLeft = first->x() + first->borderLeft();
1742         fromRight = last->x() + last->width() - last->borderRight();
1743     } else {
1744         fromRight = first->x() + first->width() - first->borderRight();
1745         fromLeft = last->x() + last->borderLeft();
1746     }
1747 
1748     return max(0, (fromRight - fromLeft));
1749 }
1750 
containingBlockHeightForPositioned(const RenderBoxModelObject * containingBlock) const1751 int RenderBox::containingBlockHeightForPositioned(const RenderBoxModelObject* containingBlock) const
1752 {
1753     int heightResult = 0;
1754     if (containingBlock->isBox())
1755          heightResult = toRenderBox(containingBlock)->height();
1756     else if (containingBlock->isRenderInline()) {
1757         ASSERT(containingBlock->isRelPositioned());
1758         heightResult = toRenderInline(containingBlock)->linesBoundingBox().height();
1759     }
1760     return heightResult - containingBlock->borderTop() - containingBlock->borderBottom();
1761 }
1762 
calcAbsoluteHorizontal()1763 void RenderBox::calcAbsoluteHorizontal()
1764 {
1765     if (isReplaced()) {
1766         calcAbsoluteHorizontalReplaced();
1767         return;
1768     }
1769 
1770     // QUESTIONS
1771     // FIXME 1: Which RenderObject's 'direction' property should used: the
1772     // containing block (cb) as the spec seems to imply, the parent (parent()) as
1773     // was previously done in calculating the static distances, or ourself, which
1774     // was also previously done for deciding what to override when you had
1775     // over-constrained margins?  Also note that the container block is used
1776     // in similar situations in other parts of the RenderBox class (see calcWidth()
1777     // and calcHorizontalMargins()). For now we are using the parent for quirks
1778     // mode and the containing block for strict mode.
1779 
1780     // FIXME 2: Should we still deal with these the cases of 'left' or 'right' having
1781     // the type 'static' in determining whether to calculate the static distance?
1782     // NOTE: 'static' is not a legal value for 'left' or 'right' as of CSS 2.1.
1783 
1784     // FIXME 3: Can perhaps optimize out cases when max-width/min-width are greater
1785     // than or less than the computed width().  Be careful of box-sizing and
1786     // percentage issues.
1787 
1788     // The following is based off of the W3C Working Draft from April 11, 2006 of
1789     // CSS 2.1: Section 10.3.7 "Absolutely positioned, non-replaced elements"
1790     // <http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width>
1791     // (block-style-comments in this function and in calcAbsoluteHorizontalValues()
1792     // correspond to text from the spec)
1793 
1794 
1795     // We don't use containingBlock(), since we may be positioned by an enclosing
1796     // relative positioned inline.
1797     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
1798 
1799     const int containerWidth = containingBlockWidthForPositioned(containerBlock);
1800 
1801     // To match WinIE, in quirks mode use the parent's 'direction' property
1802     // instead of the the container block's.
1803     TextDirection containerDirection = (style()->htmlHacks()) ? parent()->style()->direction() : containerBlock->style()->direction();
1804 
1805     const int bordersPlusPadding = borderLeft() + borderRight() + paddingLeft() + paddingRight();
1806     const Length marginLeft = style()->marginLeft();
1807     const Length marginRight = style()->marginRight();
1808     Length left = style()->left();
1809     Length right = style()->right();
1810 
1811     /*---------------------------------------------------------------------------*\
1812      * For the purposes of this section and the next, the term "static position"
1813      * (of an element) refers, roughly, to the position an element would have had
1814      * in the normal flow. More precisely:
1815      *
1816      * * The static position for 'left' is the distance from the left edge of the
1817      *   containing block to the left margin edge of a hypothetical box that would
1818      *   have been the first box of the element if its 'position' property had
1819      *   been 'static' and 'float' had been 'none'. The value is negative if the
1820      *   hypothetical box is to the left of the containing block.
1821      * * The static position for 'right' is the distance from the right edge of the
1822      *   containing block to the right margin edge of the same hypothetical box as
1823      *   above. The value is positive if the hypothetical box is to the left of the
1824      *   containing block's edge.
1825      *
1826      * But rather than actually calculating the dimensions of that hypothetical box,
1827      * user agents are free to make a guess at its probable position.
1828      *
1829      * For the purposes of calculating the static position, the containing block of
1830      * fixed positioned elements is the initial containing block instead of the
1831      * viewport, and all scrollable boxes should be assumed to be scrolled to their
1832      * origin.
1833     \*---------------------------------------------------------------------------*/
1834 
1835     // see FIXME 2
1836     // Calculate the static distance if needed.
1837     if (left.isAuto() && right.isAuto()) {
1838         if (containerDirection == LTR) {
1839             // 'staticX' should already have been set through layout of the parent.
1840             int staticPosition = layer()->staticX() - containerBlock->borderLeft();
1841             for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) {
1842                 if (po->isBox())
1843                     staticPosition += toRenderBox(po)->x();
1844             }
1845             left.setValue(Fixed, staticPosition);
1846         } else {
1847             RenderObject* po = parent();
1848             // 'staticX' should already have been set through layout of the parent.
1849             int staticPosition = layer()->staticX() + containerWidth + containerBlock->borderRight();
1850             if (po->isBox())
1851                 staticPosition -= toRenderBox(po)->width();
1852             for (; po && po != containerBlock; po = po->parent()) {
1853                 if (po->isBox())
1854                     staticPosition -= toRenderBox(po)->x();
1855             }
1856             right.setValue(Fixed, staticPosition);
1857         }
1858     }
1859 
1860     // Calculate constraint equation values for 'width' case.
1861     int widthResult;
1862     int xResult;
1863     calcAbsoluteHorizontalValues(style()->width(), containerBlock, containerDirection,
1864                                  containerWidth, bordersPlusPadding,
1865                                  left, right, marginLeft, marginRight,
1866                                  widthResult, m_marginLeft, m_marginRight, xResult);
1867     setWidth(widthResult);
1868     setX(xResult);
1869 
1870     // Calculate constraint equation values for 'max-width' case.
1871     if (!style()->maxWidth().isUndefined()) {
1872         int maxWidth;
1873         int maxMarginLeft;
1874         int maxMarginRight;
1875         int maxXPos;
1876 
1877         calcAbsoluteHorizontalValues(style()->maxWidth(), containerBlock, containerDirection,
1878                                      containerWidth, bordersPlusPadding,
1879                                      left, right, marginLeft, marginRight,
1880                                      maxWidth, maxMarginLeft, maxMarginRight, maxXPos);
1881 
1882         if (width() > maxWidth) {
1883             setWidth(maxWidth);
1884             m_marginLeft = maxMarginLeft;
1885             m_marginRight = maxMarginRight;
1886             m_frameRect.setX(maxXPos);
1887         }
1888     }
1889 
1890     // Calculate constraint equation values for 'min-width' case.
1891     if (!style()->minWidth().isZero()) {
1892         int minWidth;
1893         int minMarginLeft;
1894         int minMarginRight;
1895         int minXPos;
1896 
1897         calcAbsoluteHorizontalValues(style()->minWidth(), containerBlock, containerDirection,
1898                                      containerWidth, bordersPlusPadding,
1899                                      left, right, marginLeft, marginRight,
1900                                      minWidth, minMarginLeft, minMarginRight, minXPos);
1901 
1902         if (width() < minWidth) {
1903             setWidth(minWidth);
1904             m_marginLeft = minMarginLeft;
1905             m_marginRight = minMarginRight;
1906             m_frameRect.setX(minXPos);
1907         }
1908     }
1909 
1910     if (stretchesToMinIntrinsicWidth() && width() < minPrefWidth() - bordersPlusPadding) {
1911         calcAbsoluteHorizontalValues(Length(minPrefWidth() - bordersPlusPadding, Fixed), containerBlock, containerDirection,
1912                                      containerWidth, bordersPlusPadding,
1913                                      left, right, marginLeft, marginRight,
1914                                      widthResult, m_marginLeft, m_marginRight, xResult);
1915         setWidth(widthResult);
1916         setX(xResult);
1917     }
1918 
1919     // Put width() into correct form.
1920     setWidth(width() + bordersPlusPadding);
1921 }
1922 
calcAbsoluteHorizontalValues(Length width,const RenderBoxModelObject * containerBlock,TextDirection containerDirection,const int containerWidth,const int bordersPlusPadding,const Length left,const Length right,const Length marginLeft,const Length marginRight,int & widthValue,int & marginLeftValue,int & marginRightValue,int & xPos)1923 void RenderBox::calcAbsoluteHorizontalValues(Length width, const RenderBoxModelObject* containerBlock, TextDirection containerDirection,
1924                                              const int containerWidth, const int bordersPlusPadding,
1925                                              const Length left, const Length right, const Length marginLeft, const Length marginRight,
1926                                              int& widthValue, int& marginLeftValue, int& marginRightValue, int& xPos)
1927 {
1928     // 'left' and 'right' cannot both be 'auto' because one would of been
1929     // converted to the static postion already
1930     ASSERT(!(left.isAuto() && right.isAuto()));
1931 
1932     int leftValue = 0;
1933 
1934     bool widthIsAuto = width.isIntrinsicOrAuto();
1935     bool leftIsAuto = left.isAuto();
1936     bool rightIsAuto = right.isAuto();
1937 
1938     if (!leftIsAuto && !widthIsAuto && !rightIsAuto) {
1939         /*-----------------------------------------------------------------------*\
1940          * If none of the three is 'auto': If both 'margin-left' and 'margin-
1941          * right' are 'auto', solve the equation under the extra constraint that
1942          * the two margins get equal values, unless this would make them negative,
1943          * in which case when direction of the containing block is 'ltr' ('rtl'),
1944          * set 'margin-left' ('margin-right') to zero and solve for 'margin-right'
1945          * ('margin-left'). If one of 'margin-left' or 'margin-right' is 'auto',
1946          * solve the equation for that value. If the values are over-constrained,
1947          * ignore the value for 'left' (in case the 'direction' property of the
1948          * containing block is 'rtl') or 'right' (in case 'direction' is 'ltr')
1949          * and solve for that value.
1950         \*-----------------------------------------------------------------------*/
1951         // NOTE:  It is not necessary to solve for 'right' in the over constrained
1952         // case because the value is not used for any further calculations.
1953 
1954         leftValue = left.calcValue(containerWidth);
1955         widthValue = calcContentBoxWidth(width.calcValue(containerWidth));
1956 
1957         const int availableSpace = containerWidth - (leftValue + widthValue + right.calcValue(containerWidth) + bordersPlusPadding);
1958 
1959         // Margins are now the only unknown
1960         if (marginLeft.isAuto() && marginRight.isAuto()) {
1961             // Both margins auto, solve for equality
1962             if (availableSpace >= 0) {
1963                 marginLeftValue = availableSpace / 2; // split the diference
1964                 marginRightValue = availableSpace - marginLeftValue;  // account for odd valued differences
1965             } else {
1966                 // see FIXME 1
1967                 if (containerDirection == LTR) {
1968                     marginLeftValue = 0;
1969                     marginRightValue = availableSpace; // will be negative
1970                 } else {
1971                     marginLeftValue = availableSpace; // will be negative
1972                     marginRightValue = 0;
1973                 }
1974             }
1975         } else if (marginLeft.isAuto()) {
1976             // Solve for left margin
1977             marginRightValue = marginRight.calcValue(containerWidth);
1978             marginLeftValue = availableSpace - marginRightValue;
1979         } else if (marginRight.isAuto()) {
1980             // Solve for right margin
1981             marginLeftValue = marginLeft.calcValue(containerWidth);
1982             marginRightValue = availableSpace - marginLeftValue;
1983         } else {
1984             // Over-constrained, solve for left if direction is RTL
1985             marginLeftValue = marginLeft.calcValue(containerWidth);
1986             marginRightValue = marginRight.calcValue(containerWidth);
1987 
1988             // see FIXME 1 -- used to be "this->style()->direction()"
1989             if (containerDirection == RTL)
1990                 leftValue = (availableSpace + leftValue) - marginLeftValue - marginRightValue;
1991         }
1992     } else {
1993         /*--------------------------------------------------------------------*\
1994          * Otherwise, set 'auto' values for 'margin-left' and 'margin-right'
1995          * to 0, and pick the one of the following six rules that applies.
1996          *
1997          * 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the
1998          *    width is shrink-to-fit. Then solve for 'left'
1999          *
2000          *              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
2001          * ------------------------------------------------------------------
2002          * 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if
2003          *    the 'direction' property of the containing block is 'ltr' set
2004          *    'left' to the static position, otherwise set 'right' to the
2005          *    static position. Then solve for 'left' (if 'direction is 'rtl')
2006          *    or 'right' (if 'direction' is 'ltr').
2007          * ------------------------------------------------------------------
2008          *
2009          * 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the
2010          *    width is shrink-to-fit . Then solve for 'right'
2011          * 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve
2012          *    for 'left'
2013          * 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve
2014          *    for 'width'
2015          * 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve
2016          *    for 'right'
2017          *
2018          * Calculation of the shrink-to-fit width is similar to calculating the
2019          * width of a table cell using the automatic table layout algorithm.
2020          * Roughly: calculate the preferred width by formatting the content
2021          * without breaking lines other than where explicit line breaks occur,
2022          * and also calculate the preferred minimum width, e.g., by trying all
2023          * possible line breaks. CSS 2.1 does not define the exact algorithm.
2024          * Thirdly, calculate the available width: this is found by solving
2025          * for 'width' after setting 'left' (in case 1) or 'right' (in case 3)
2026          * to 0.
2027          *
2028          * Then the shrink-to-fit width is:
2029          * min(max(preferred minimum width, available width), preferred width).
2030         \*--------------------------------------------------------------------*/
2031         // NOTE: For rules 3 and 6 it is not necessary to solve for 'right'
2032         // because the value is not used for any further calculations.
2033 
2034         // Calculate margins, 'auto' margins are ignored.
2035         marginLeftValue = marginLeft.calcMinValue(containerWidth);
2036         marginRightValue = marginRight.calcMinValue(containerWidth);
2037 
2038         const int availableSpace = containerWidth - (marginLeftValue + marginRightValue + bordersPlusPadding);
2039 
2040         // FIXME: Is there a faster way to find the correct case?
2041         // Use rule/case that applies.
2042         if (leftIsAuto && widthIsAuto && !rightIsAuto) {
2043             // RULE 1: (use shrink-to-fit for width, and solve of left)
2044             int rightValue = right.calcValue(containerWidth);
2045 
2046             // FIXME: would it be better to have shrink-to-fit in one step?
2047             int preferredWidth = maxPrefWidth() - bordersPlusPadding;
2048             int preferredMinWidth = minPrefWidth() - bordersPlusPadding;
2049             int availableWidth = availableSpace - rightValue;
2050             widthValue = min(max(preferredMinWidth, availableWidth), preferredWidth);
2051             leftValue = availableSpace - (widthValue + rightValue);
2052         } else if (!leftIsAuto && widthIsAuto && rightIsAuto) {
2053             // RULE 3: (use shrink-to-fit for width, and no need solve of right)
2054             leftValue = left.calcValue(containerWidth);
2055 
2056             // FIXME: would it be better to have shrink-to-fit in one step?
2057             int preferredWidth = maxPrefWidth() - bordersPlusPadding;
2058             int preferredMinWidth = minPrefWidth() - bordersPlusPadding;
2059             int availableWidth = availableSpace - leftValue;
2060             widthValue = min(max(preferredMinWidth, availableWidth), preferredWidth);
2061         } else if (leftIsAuto && !width.isAuto() && !rightIsAuto) {
2062             // RULE 4: (solve for left)
2063             widthValue = calcContentBoxWidth(width.calcValue(containerWidth));
2064             leftValue = availableSpace - (widthValue + right.calcValue(containerWidth));
2065         } else if (!leftIsAuto && widthIsAuto && !rightIsAuto) {
2066             // RULE 5: (solve for width)
2067             leftValue = left.calcValue(containerWidth);
2068             widthValue = availableSpace - (leftValue + right.calcValue(containerWidth));
2069         } else if (!leftIsAuto&& !widthIsAuto && rightIsAuto) {
2070             // RULE 6: (no need solve for right)
2071             leftValue = left.calcValue(containerWidth);
2072             widthValue = calcContentBoxWidth(width.calcValue(containerWidth));
2073         }
2074     }
2075 
2076     // Use computed values to calculate the horizontal position.
2077 
2078     // FIXME: This hack is needed to calculate the xPos for a 'rtl' relatively
2079     // positioned, inline because right now, it is using the xPos
2080     // of the first line box when really it should use the last line box.  When
2081     // this is fixed elsewhere, this block should be removed.
2082     if (containerBlock->isRenderInline() && containerBlock->style()->direction() == RTL) {
2083         const RenderInline* flow = toRenderInline(containerBlock);
2084         InlineFlowBox* firstLine = flow->firstLineBox();
2085         InlineFlowBox* lastLine = flow->lastLineBox();
2086         if (firstLine && lastLine && firstLine != lastLine) {
2087             xPos = leftValue + marginLeftValue + lastLine->borderLeft() + (lastLine->x() - firstLine->x());
2088             return;
2089         }
2090     }
2091 
2092     xPos = leftValue + marginLeftValue + containerBlock->borderLeft();
2093 }
2094 
calcAbsoluteVertical()2095 void RenderBox::calcAbsoluteVertical()
2096 {
2097     if (isReplaced()) {
2098         calcAbsoluteVerticalReplaced();
2099         return;
2100     }
2101 
2102     // The following is based off of the W3C Working Draft from April 11, 2006 of
2103     // CSS 2.1: Section 10.6.4 "Absolutely positioned, non-replaced elements"
2104     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-non-replaced-height>
2105     // (block-style-comments in this function and in calcAbsoluteVerticalValues()
2106     // correspond to text from the spec)
2107 
2108 
2109     // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
2110     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
2111 
2112     const int containerHeight = containingBlockHeightForPositioned(containerBlock);
2113 
2114     const int bordersPlusPadding = borderTop() + borderBottom() + paddingTop() + paddingBottom();
2115     const Length marginTop = style()->marginTop();
2116     const Length marginBottom = style()->marginBottom();
2117     Length top = style()->top();
2118     Length bottom = style()->bottom();
2119 
2120     /*---------------------------------------------------------------------------*\
2121      * For the purposes of this section and the next, the term "static position"
2122      * (of an element) refers, roughly, to the position an element would have had
2123      * in the normal flow. More precisely, the static position for 'top' is the
2124      * distance from the top edge of the containing block to the top margin edge
2125      * of a hypothetical box that would have been the first box of the element if
2126      * its 'position' property had been 'static' and 'float' had been 'none'. The
2127      * value is negative if the hypothetical box is above the containing block.
2128      *
2129      * But rather than actually calculating the dimensions of that hypothetical
2130      * box, user agents are free to make a guess at its probable position.
2131      *
2132      * For the purposes of calculating the static position, the containing block
2133      * of fixed positioned elements is the initial containing block instead of
2134      * the viewport.
2135     \*---------------------------------------------------------------------------*/
2136 
2137     // see FIXME 2
2138     // Calculate the static distance if needed.
2139     if (top.isAuto() && bottom.isAuto()) {
2140         // staticY should already have been set through layout of the parent()
2141         int staticTop = layer()->staticY() - containerBlock->borderTop();
2142         for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) {
2143             if (po->isBox() && !po->isTableRow())
2144                 staticTop += toRenderBox(po)->y();
2145         }
2146         top.setValue(Fixed, staticTop);
2147     }
2148 
2149 
2150     int h; // Needed to compute overflow.
2151     int y;
2152 
2153     // Calculate constraint equation values for 'height' case.
2154     calcAbsoluteVerticalValues(style()->height(), containerBlock, containerHeight, bordersPlusPadding,
2155                                top, bottom, marginTop, marginBottom,
2156                                h, m_marginTop, m_marginBottom, y);
2157     setY(y);
2158 
2159     // Avoid doing any work in the common case (where the values of min-height and max-height are their defaults).
2160     // see FIXME 3
2161 
2162     // Calculate constraint equation values for 'max-height' case.
2163     if (!style()->maxHeight().isUndefined()) {
2164         int maxHeight;
2165         int maxMarginTop;
2166         int maxMarginBottom;
2167         int maxYPos;
2168 
2169         calcAbsoluteVerticalValues(style()->maxHeight(), containerBlock, containerHeight, bordersPlusPadding,
2170                                    top, bottom, marginTop, marginBottom,
2171                                    maxHeight, maxMarginTop, maxMarginBottom, maxYPos);
2172 
2173         if (h > maxHeight) {
2174             h = maxHeight;
2175             m_marginTop = maxMarginTop;
2176             m_marginBottom = maxMarginBottom;
2177             m_frameRect.setY(maxYPos);
2178         }
2179     }
2180 
2181     // Calculate constraint equation values for 'min-height' case.
2182     if (!style()->minHeight().isZero()) {
2183         int minHeight;
2184         int minMarginTop;
2185         int minMarginBottom;
2186         int minYPos;
2187 
2188         calcAbsoluteVerticalValues(style()->minHeight(), containerBlock, containerHeight, bordersPlusPadding,
2189                                    top, bottom, marginTop, marginBottom,
2190                                    minHeight, minMarginTop, minMarginBottom, minYPos);
2191 
2192         if (h < minHeight) {
2193             h = minHeight;
2194             m_marginTop = minMarginTop;
2195             m_marginBottom = minMarginBottom;
2196             m_frameRect.setY(minYPos);
2197         }
2198     }
2199 
2200     // Set final height value.
2201     setHeight(h + bordersPlusPadding);
2202 }
2203 
calcAbsoluteVerticalValues(Length h,const RenderBoxModelObject * containerBlock,const int containerHeight,const int bordersPlusPadding,const Length top,const Length bottom,const Length marginTop,const Length marginBottom,int & heightValue,int & marginTopValue,int & marginBottomValue,int & yPos)2204 void RenderBox::calcAbsoluteVerticalValues(Length h, const RenderBoxModelObject* containerBlock,
2205                                            const int containerHeight, const int bordersPlusPadding,
2206                                            const Length top, const Length bottom, const Length marginTop, const Length marginBottom,
2207                                            int& heightValue, int& marginTopValue, int& marginBottomValue, int& yPos)
2208 {
2209     // 'top' and 'bottom' cannot both be 'auto' because 'top would of been
2210     // converted to the static position in calcAbsoluteVertical()
2211     ASSERT(!(top.isAuto() && bottom.isAuto()));
2212 
2213     int contentHeight = height() - bordersPlusPadding;
2214 
2215     int topValue = 0;
2216 
2217     bool heightIsAuto = h.isAuto();
2218     bool topIsAuto = top.isAuto();
2219     bool bottomIsAuto = bottom.isAuto();
2220 
2221     // Height is never unsolved for tables.
2222     if (isTable()) {
2223         h.setValue(Fixed, contentHeight);
2224         heightIsAuto = false;
2225     }
2226 
2227     if (!topIsAuto && !heightIsAuto && !bottomIsAuto) {
2228         /*-----------------------------------------------------------------------*\
2229          * If none of the three are 'auto': If both 'margin-top' and 'margin-
2230          * bottom' are 'auto', solve the equation under the extra constraint that
2231          * the two margins get equal values. If one of 'margin-top' or 'margin-
2232          * bottom' is 'auto', solve the equation for that value. If the values
2233          * are over-constrained, ignore the value for 'bottom' and solve for that
2234          * value.
2235         \*-----------------------------------------------------------------------*/
2236         // NOTE:  It is not necessary to solve for 'bottom' in the over constrained
2237         // case because the value is not used for any further calculations.
2238 
2239         heightValue = calcContentBoxHeight(h.calcValue(containerHeight));
2240         topValue = top.calcValue(containerHeight);
2241 
2242         const int availableSpace = containerHeight - (topValue + heightValue + bottom.calcValue(containerHeight) + bordersPlusPadding);
2243 
2244         // Margins are now the only unknown
2245         if (marginTop.isAuto() && marginBottom.isAuto()) {
2246             // Both margins auto, solve for equality
2247             // NOTE: This may result in negative values.
2248             marginTopValue = availableSpace / 2; // split the diference
2249             marginBottomValue = availableSpace - marginTopValue; // account for odd valued differences
2250         } else if (marginTop.isAuto()) {
2251             // Solve for top margin
2252             marginBottomValue = marginBottom.calcValue(containerHeight);
2253             marginTopValue = availableSpace - marginBottomValue;
2254         } else if (marginBottom.isAuto()) {
2255             // Solve for bottom margin
2256             marginTopValue = marginTop.calcValue(containerHeight);
2257             marginBottomValue = availableSpace - marginTopValue;
2258         } else {
2259             // Over-constrained, (no need solve for bottom)
2260             marginTopValue = marginTop.calcValue(containerHeight);
2261             marginBottomValue = marginBottom.calcValue(containerHeight);
2262         }
2263     } else {
2264         /*--------------------------------------------------------------------*\
2265          * Otherwise, set 'auto' values for 'margin-top' and 'margin-bottom'
2266          * to 0, and pick the one of the following six rules that applies.
2267          *
2268          * 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then
2269          *    the height is based on the content, and solve for 'top'.
2270          *
2271          *              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
2272          * ------------------------------------------------------------------
2273          * 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then
2274          *    set 'top' to the static position, and solve for 'bottom'.
2275          * ------------------------------------------------------------------
2276          *
2277          * 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then
2278          *    the height is based on the content, and solve for 'bottom'.
2279          * 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', and
2280          *    solve for 'top'.
2281          * 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', and
2282          *    solve for 'height'.
2283          * 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', and
2284          *    solve for 'bottom'.
2285         \*--------------------------------------------------------------------*/
2286         // NOTE: For rules 3 and 6 it is not necessary to solve for 'bottom'
2287         // because the value is not used for any further calculations.
2288 
2289         // Calculate margins, 'auto' margins are ignored.
2290         marginTopValue = marginTop.calcMinValue(containerHeight);
2291         marginBottomValue = marginBottom.calcMinValue(containerHeight);
2292 
2293         const int availableSpace = containerHeight - (marginTopValue + marginBottomValue + bordersPlusPadding);
2294 
2295         // Use rule/case that applies.
2296         if (topIsAuto && heightIsAuto && !bottomIsAuto) {
2297             // RULE 1: (height is content based, solve of top)
2298             heightValue = contentHeight;
2299             topValue = availableSpace - (heightValue + bottom.calcValue(containerHeight));
2300         } else if (!topIsAuto && heightIsAuto && bottomIsAuto) {
2301             // RULE 3: (height is content based, no need solve of bottom)
2302             topValue = top.calcValue(containerHeight);
2303             heightValue = contentHeight;
2304         } else if (topIsAuto && !heightIsAuto && !bottomIsAuto) {
2305             // RULE 4: (solve of top)
2306             heightValue = calcContentBoxHeight(h.calcValue(containerHeight));
2307             topValue = availableSpace - (heightValue + bottom.calcValue(containerHeight));
2308         } else if (!topIsAuto && heightIsAuto && !bottomIsAuto) {
2309             // RULE 5: (solve of height)
2310             topValue = top.calcValue(containerHeight);
2311             heightValue = max(0, availableSpace - (topValue + bottom.calcValue(containerHeight)));
2312         } else if (!topIsAuto && !heightIsAuto && bottomIsAuto) {
2313             // RULE 6: (no need solve of bottom)
2314             heightValue = calcContentBoxHeight(h.calcValue(containerHeight));
2315             topValue = top.calcValue(containerHeight);
2316         }
2317     }
2318 
2319     // Use computed values to calculate the vertical position.
2320     yPos = topValue + marginTopValue + containerBlock->borderTop();
2321 }
2322 
calcAbsoluteHorizontalReplaced()2323 void RenderBox::calcAbsoluteHorizontalReplaced()
2324 {
2325     // The following is based off of the W3C Working Draft from April 11, 2006 of
2326     // CSS 2.1: Section 10.3.8 "Absolutly positioned, replaced elements"
2327     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-width>
2328     // (block-style-comments in this function correspond to text from the spec and
2329     // the numbers correspond to numbers in spec)
2330 
2331     // We don't use containingBlock(), since we may be positioned by an enclosing
2332     // relative positioned inline.
2333     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
2334 
2335     const int containerWidth = containingBlockWidthForPositioned(containerBlock);
2336 
2337     // To match WinIE, in quirks mode use the parent's 'direction' property
2338     // instead of the the container block's.
2339     TextDirection containerDirection = (style()->htmlHacks()) ? parent()->style()->direction() : containerBlock->style()->direction();
2340 
2341     // Variables to solve.
2342     Length left = style()->left();
2343     Length right = style()->right();
2344     Length marginLeft = style()->marginLeft();
2345     Length marginRight = style()->marginRight();
2346 
2347 
2348     /*-----------------------------------------------------------------------*\
2349      * 1. The used value of 'width' is determined as for inline replaced
2350      *    elements.
2351     \*-----------------------------------------------------------------------*/
2352     // NOTE: This value of width is FINAL in that the min/max width calculations
2353     // are dealt with in calcReplacedWidth().  This means that the steps to produce
2354     // correct max/min in the non-replaced version, are not necessary.
2355     setWidth(calcReplacedWidth() + borderLeft() + borderRight() + paddingLeft() + paddingRight());
2356     const int availableSpace = containerWidth - width();
2357 
2358     /*-----------------------------------------------------------------------*\
2359      * 2. If both 'left' and 'right' have the value 'auto', then if 'direction'
2360      *    of the containing block is 'ltr', set 'left' to the static position;
2361      *    else if 'direction' is 'rtl', set 'right' to the static position.
2362     \*-----------------------------------------------------------------------*/
2363     // see FIXME 2
2364     if (left.isAuto() && right.isAuto()) {
2365         // see FIXME 1
2366         if (containerDirection == LTR) {
2367             // 'staticX' should already have been set through layout of the parent.
2368             int staticPosition = layer()->staticX() - containerBlock->borderLeft();
2369             for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) {
2370                 if (po->isBox())
2371                     staticPosition += toRenderBox(po)->x();
2372             }
2373             left.setValue(Fixed, staticPosition);
2374         } else {
2375             RenderObject* po = parent();
2376             // 'staticX' should already have been set through layout of the parent.
2377             int staticPosition = layer()->staticX() + containerWidth + containerBlock->borderRight();
2378             for ( ; po && po != containerBlock; po = po->parent()) {
2379                 if (po->isBox())
2380                     staticPosition += toRenderBox(po)->x();
2381             }
2382             right.setValue(Fixed, staticPosition);
2383         }
2384     }
2385 
2386     /*-----------------------------------------------------------------------*\
2387      * 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left'
2388      *    or 'margin-right' with '0'.
2389     \*-----------------------------------------------------------------------*/
2390     if (left.isAuto() || right.isAuto()) {
2391         if (marginLeft.isAuto())
2392             marginLeft.setValue(Fixed, 0);
2393         if (marginRight.isAuto())
2394             marginRight.setValue(Fixed, 0);
2395     }
2396 
2397     /*-----------------------------------------------------------------------*\
2398      * 4. If at this point both 'margin-left' and 'margin-right' are still
2399      *    'auto', solve the equation under the extra constraint that the two
2400      *    margins must get equal values, unless this would make them negative,
2401      *    in which case when the direction of the containing block is 'ltr'
2402      *    ('rtl'), set 'margin-left' ('margin-right') to zero and solve for
2403      *    'margin-right' ('margin-left').
2404     \*-----------------------------------------------------------------------*/
2405     int leftValue = 0;
2406     int rightValue = 0;
2407 
2408     if (marginLeft.isAuto() && marginRight.isAuto()) {
2409         // 'left' and 'right' cannot be 'auto' due to step 3
2410         ASSERT(!(left.isAuto() && right.isAuto()));
2411 
2412         leftValue = left.calcValue(containerWidth);
2413         rightValue = right.calcValue(containerWidth);
2414 
2415         int difference = availableSpace - (leftValue + rightValue);
2416         if (difference > 0) {
2417             m_marginLeft = difference / 2; // split the diference
2418             m_marginRight = difference - m_marginLeft; // account for odd valued differences
2419         } else {
2420             // see FIXME 1
2421             if (containerDirection == LTR) {
2422                 m_marginLeft = 0;
2423                 m_marginRight = difference;  // will be negative
2424             } else {
2425                 m_marginLeft = difference;  // will be negative
2426                 m_marginRight = 0;
2427             }
2428         }
2429 
2430     /*-----------------------------------------------------------------------*\
2431      * 5. If at this point there is an 'auto' left, solve the equation for
2432      *    that value.
2433     \*-----------------------------------------------------------------------*/
2434     } else if (left.isAuto()) {
2435         m_marginLeft = marginLeft.calcValue(containerWidth);
2436         m_marginRight = marginRight.calcValue(containerWidth);
2437         rightValue = right.calcValue(containerWidth);
2438 
2439         // Solve for 'left'
2440         leftValue = availableSpace - (rightValue + m_marginLeft + m_marginRight);
2441     } else if (right.isAuto()) {
2442         m_marginLeft = marginLeft.calcValue(containerWidth);
2443         m_marginRight = marginRight.calcValue(containerWidth);
2444         leftValue = left.calcValue(containerWidth);
2445 
2446         // Solve for 'right'
2447         rightValue = availableSpace - (leftValue + m_marginLeft + m_marginRight);
2448     } else if (marginLeft.isAuto()) {
2449         m_marginRight = marginRight.calcValue(containerWidth);
2450         leftValue = left.calcValue(containerWidth);
2451         rightValue = right.calcValue(containerWidth);
2452 
2453         // Solve for 'margin-left'
2454         m_marginLeft = availableSpace - (leftValue + rightValue + m_marginRight);
2455     } else if (marginRight.isAuto()) {
2456         m_marginLeft = marginLeft.calcValue(containerWidth);
2457         leftValue = left.calcValue(containerWidth);
2458         rightValue = right.calcValue(containerWidth);
2459 
2460         // Solve for 'margin-right'
2461         m_marginRight = availableSpace - (leftValue + rightValue + m_marginLeft);
2462     } else {
2463         // Nothing is 'auto', just calculate the values.
2464         m_marginLeft = marginLeft.calcValue(containerWidth);
2465         m_marginRight = marginRight.calcValue(containerWidth);
2466         rightValue = right.calcValue(containerWidth);
2467         leftValue = left.calcValue(containerWidth);
2468     }
2469 
2470     /*-----------------------------------------------------------------------*\
2471      * 6. If at this point the values are over-constrained, ignore the value
2472      *    for either 'left' (in case the 'direction' property of the
2473      *    containing block is 'rtl') or 'right' (in case 'direction' is
2474      *    'ltr') and solve for that value.
2475     \*-----------------------------------------------------------------------*/
2476     // NOTE:  It is not necessary to solve for 'right' when the direction is
2477     // LTR because the value is not used.
2478     int totalWidth = width() + leftValue + rightValue +  m_marginLeft + m_marginRight;
2479     if (totalWidth > containerWidth && (containerDirection == RTL))
2480         leftValue = containerWidth - (totalWidth - leftValue);
2481 
2482     // Use computed values to calculate the horizontal position.
2483 
2484     // FIXME: This hack is needed to calculate the xPos for a 'rtl' relatively
2485     // positioned, inline containing block because right now, it is using the xPos
2486     // of the first line box when really it should use the last line box.  When
2487     // this is fixed elsewhere, this block should be removed.
2488     if (containerBlock->isInline() && containerBlock->style()->direction() == RTL) {
2489         const RenderInline* flow = toRenderInline(containerBlock);
2490         InlineFlowBox* firstLine = flow->firstLineBox();
2491         InlineFlowBox* lastLine = flow->lastLineBox();
2492         if (firstLine && lastLine && firstLine != lastLine) {
2493             m_frameRect.setX(leftValue + m_marginLeft + lastLine->borderLeft() + (lastLine->x() - firstLine->x()));
2494             return;
2495         }
2496     }
2497 
2498     m_frameRect.setX(leftValue + m_marginLeft + containerBlock->borderLeft());
2499 }
2500 
calcAbsoluteVerticalReplaced()2501 void RenderBox::calcAbsoluteVerticalReplaced()
2502 {
2503     // The following is based off of the W3C Working Draft from April 11, 2006 of
2504     // CSS 2.1: Section 10.6.5 "Absolutly positioned, replaced elements"
2505     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-height>
2506     // (block-style-comments in this function correspond to text from the spec and
2507     // the numbers correspond to numbers in spec)
2508 
2509     // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
2510     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
2511 
2512     const int containerHeight = containingBlockHeightForPositioned(containerBlock);
2513 
2514     // Variables to solve.
2515     Length top = style()->top();
2516     Length bottom = style()->bottom();
2517     Length marginTop = style()->marginTop();
2518     Length marginBottom = style()->marginBottom();
2519 
2520 
2521     /*-----------------------------------------------------------------------*\
2522      * 1. The used value of 'height' is determined as for inline replaced
2523      *    elements.
2524     \*-----------------------------------------------------------------------*/
2525     // NOTE: This value of height is FINAL in that the min/max height calculations
2526     // are dealt with in calcReplacedHeight().  This means that the steps to produce
2527     // correct max/min in the non-replaced version, are not necessary.
2528     setHeight(calcReplacedHeight() + borderTop() + borderBottom() + paddingTop() + paddingBottom());
2529     const int availableSpace = containerHeight - height();
2530 
2531     /*-----------------------------------------------------------------------*\
2532      * 2. If both 'top' and 'bottom' have the value 'auto', replace 'top'
2533      *    with the element's static position.
2534     \*-----------------------------------------------------------------------*/
2535     // see FIXME 2
2536     if (top.isAuto() && bottom.isAuto()) {
2537         // staticY should already have been set through layout of the parent().
2538         int staticTop = layer()->staticY() - containerBlock->borderTop();
2539         for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) {
2540             if (po->isBox() && !po->isTableRow())
2541                 staticTop += toRenderBox(po)->y();
2542         }
2543         top.setValue(Fixed, staticTop);
2544     }
2545 
2546     /*-----------------------------------------------------------------------*\
2547      * 3. If 'bottom' is 'auto', replace any 'auto' on 'margin-top' or
2548      *    'margin-bottom' with '0'.
2549     \*-----------------------------------------------------------------------*/
2550     // FIXME: The spec. says that this step should only be taken when bottom is
2551     // auto, but if only top is auto, this makes step 4 impossible.
2552     if (top.isAuto() || bottom.isAuto()) {
2553         if (marginTop.isAuto())
2554             marginTop.setValue(Fixed, 0);
2555         if (marginBottom.isAuto())
2556             marginBottom.setValue(Fixed, 0);
2557     }
2558 
2559     /*-----------------------------------------------------------------------*\
2560      * 4. If at this point both 'margin-top' and 'margin-bottom' are still
2561      *    'auto', solve the equation under the extra constraint that the two
2562      *    margins must get equal values.
2563     \*-----------------------------------------------------------------------*/
2564     int topValue = 0;
2565     int bottomValue = 0;
2566 
2567     if (marginTop.isAuto() && marginBottom.isAuto()) {
2568         // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combinded.
2569         ASSERT(!(top.isAuto() || bottom.isAuto()));
2570 
2571         topValue = top.calcValue(containerHeight);
2572         bottomValue = bottom.calcValue(containerHeight);
2573 
2574         int difference = availableSpace - (topValue + bottomValue);
2575         // NOTE: This may result in negative values.
2576         m_marginTop =  difference / 2; // split the difference
2577         m_marginBottom = difference - m_marginTop; // account for odd valued differences
2578 
2579     /*-----------------------------------------------------------------------*\
2580      * 5. If at this point there is only one 'auto' left, solve the equation
2581      *    for that value.
2582     \*-----------------------------------------------------------------------*/
2583     } else if (top.isAuto()) {
2584         m_marginTop = marginTop.calcValue(containerHeight);
2585         m_marginBottom = marginBottom.calcValue(containerHeight);
2586         bottomValue = bottom.calcValue(containerHeight);
2587 
2588         // Solve for 'top'
2589         topValue = availableSpace - (bottomValue + m_marginTop + m_marginBottom);
2590     } else if (bottom.isAuto()) {
2591         m_marginTop = marginTop.calcValue(containerHeight);
2592         m_marginBottom = marginBottom.calcValue(containerHeight);
2593         topValue = top.calcValue(containerHeight);
2594 
2595         // Solve for 'bottom'
2596         // NOTE: It is not necessary to solve for 'bottom' because we don't ever
2597         // use the value.
2598     } else if (marginTop.isAuto()) {
2599         m_marginBottom = marginBottom.calcValue(containerHeight);
2600         topValue = top.calcValue(containerHeight);
2601         bottomValue = bottom.calcValue(containerHeight);
2602 
2603         // Solve for 'margin-top'
2604         m_marginTop = availableSpace - (topValue + bottomValue + m_marginBottom);
2605     } else if (marginBottom.isAuto()) {
2606         m_marginTop = marginTop.calcValue(containerHeight);
2607         topValue = top.calcValue(containerHeight);
2608         bottomValue = bottom.calcValue(containerHeight);
2609 
2610         // Solve for 'margin-bottom'
2611         m_marginBottom = availableSpace - (topValue + bottomValue + m_marginTop);
2612     } else {
2613         // Nothing is 'auto', just calculate the values.
2614         m_marginTop = marginTop.calcValue(containerHeight);
2615         m_marginBottom = marginBottom.calcValue(containerHeight);
2616         topValue = top.calcValue(containerHeight);
2617         // NOTE: It is not necessary to solve for 'bottom' because we don't ever
2618         // use the value.
2619      }
2620 
2621     /*-----------------------------------------------------------------------*\
2622      * 6. If at this point the values are over-constrained, ignore the value
2623      *    for 'bottom' and solve for that value.
2624     \*-----------------------------------------------------------------------*/
2625     // NOTE: It is not necessary to do this step because we don't end up using
2626     // the value of 'bottom' regardless of whether the values are over-constrained
2627     // or not.
2628 
2629     // Use computed values to calculate the vertical position.
2630     m_frameRect.setY(topValue + m_marginTop + containerBlock->borderTop());
2631 }
2632 
localCaretRect(InlineBox * box,int caretOffset,int * extraWidthToEndOfLine)2633 IntRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, int* extraWidthToEndOfLine)
2634 {
2635     // VisiblePositions at offsets inside containers either a) refer to the positions before/after
2636     // those containers (tables and select elements) or b) refer to the position inside an empty block.
2637     // They never refer to children.
2638     // FIXME: Paint the carets inside empty blocks differently than the carets before/after elements.
2639 
2640     // FIXME: What about border and padding?
2641     IntRect rect(x(), y(), caretWidth, height());
2642     TextDirection direction = box ? box->direction() : style()->direction();
2643 
2644     if ((!caretOffset) ^ (direction == LTR))
2645         rect.move(IntSize(width() - caretWidth, 0));
2646 
2647     if (box) {
2648         RootInlineBox* rootBox = box->root();
2649         int top = rootBox->topOverflow();
2650         rect.setY(top);
2651         rect.setHeight(rootBox->bottomOverflow() - top);
2652     }
2653 
2654     // If height of box is smaller than font height, use the latter one,
2655     // otherwise the caret might become invisible.
2656     //
2657     // Also, if the box is not a replaced element, always use the font height.
2658     // This prevents the "big caret" bug described in:
2659     // <rdar://problem/3777804> Deleting all content in a document can result in giant tall-as-window insertion point
2660     //
2661     // FIXME: ignoring :first-line, missing good reason to take care of
2662     int fontHeight = style()->font().height();
2663     if (fontHeight > rect.height() || (!isReplaced() && !isTable()))
2664         rect.setHeight(fontHeight);
2665 
2666     if (extraWidthToEndOfLine)
2667         *extraWidthToEndOfLine = x() + width() - rect.right();
2668 
2669     // Move to local coords
2670     rect.move(-x(), -y());
2671     return rect;
2672 }
2673 
lowestPosition(bool,bool includeSelf) const2674 int RenderBox::lowestPosition(bool /*includeOverflowInterior*/, bool includeSelf) const
2675 {
2676     if (!includeSelf || !width())
2677         return 0;
2678     int bottom = height();
2679     if (isRelPositioned())
2680         bottom += relativePositionOffsetY();
2681     return bottom;
2682 }
2683 
rightmostPosition(bool,bool includeSelf) const2684 int RenderBox::rightmostPosition(bool /*includeOverflowInterior*/, bool includeSelf) const
2685 {
2686     if (!includeSelf || !height())
2687         return 0;
2688     int right = width();
2689     if (isRelPositioned())
2690         right += relativePositionOffsetX();
2691     return right;
2692 }
2693 
leftmostPosition(bool,bool includeSelf) const2694 int RenderBox::leftmostPosition(bool /*includeOverflowInterior*/, bool includeSelf) const
2695 {
2696     if (!includeSelf || !height())
2697         return width();
2698     int left = 0;
2699     if (isRelPositioned())
2700         left += relativePositionOffsetX();
2701     return left;
2702 }
2703 
isAfterContent(RenderObject * child) const2704 bool RenderBox::isAfterContent(RenderObject* child) const
2705 {
2706     return (child && child->style()->styleType() == AFTER && (!child->isText() || child->isBR()));
2707 }
2708 
positionForPoint(const IntPoint & point)2709 VisiblePosition RenderBox::positionForPoint(const IntPoint& point)
2710 {
2711     // no children...return this render object's element, if there is one, and offset 0
2712     if (!firstChild())
2713         return createVisiblePosition(firstDeepEditingPositionForNode(node()));
2714 
2715     int xPos = point.x();
2716     int yPos = point.y();
2717 
2718     if (isTable() && node()) {
2719         int right = contentWidth() + borderRight() + paddingRight() + borderLeft() + paddingLeft();
2720         int bottom = contentHeight() + borderTop() + paddingTop() + borderBottom() + paddingBottom();
2721 
2722         if (xPos < 0 || xPos > right || yPos < 0 || yPos > bottom) {
2723             if (xPos <= right / 2)
2724                 return createVisiblePosition(firstDeepEditingPositionForNode(node()));
2725             return createVisiblePosition(lastDeepEditingPositionForNode(node()));
2726         }
2727     }
2728 
2729     // Pass off to the closest child.
2730     int minDist = INT_MAX;
2731     RenderBox* closestRenderer = 0;
2732     int newX = xPos;
2733     int newY = yPos;
2734     if (isTableRow()) {
2735         newX += x();
2736         newY += y();
2737     }
2738     for (RenderObject* renderObject = firstChild(); renderObject; renderObject = renderObject->nextSibling()) {
2739         if ((!renderObject->firstChild() && !renderObject->isInline() && !renderObject->isBlockFlow() )
2740             || renderObject->style()->visibility() != VISIBLE)
2741             continue;
2742 
2743         if (!renderObject->isBox())
2744             continue;
2745 
2746         RenderBox* renderer = toRenderBox(renderObject);
2747 
2748         int top = renderer->borderTop() + renderer->paddingTop() + (isTableRow() ? 0 : renderer->y());
2749         int bottom = top + renderer->contentHeight();
2750         int left = renderer->borderLeft() + renderer->paddingLeft() + (isTableRow() ? 0 : renderer->x());
2751         int right = left + renderer->contentWidth();
2752 
2753         if (xPos <= right && xPos >= left && yPos <= top && yPos >= bottom) {
2754             if (renderer->isTableRow())
2755                 return renderer->positionForCoordinates(xPos + newX - renderer->x(), yPos + newY - renderer->y());
2756             return renderer->positionForCoordinates(xPos - renderer->x(), yPos - renderer->y());
2757         }
2758 
2759         // Find the distance from (x, y) to the box.  Split the space around the box into 8 pieces
2760         // and use a different compare depending on which piece (x, y) is in.
2761         IntPoint cmp;
2762         if (xPos > right) {
2763             if (yPos < top)
2764                 cmp = IntPoint(right, top);
2765             else if (yPos > bottom)
2766                 cmp = IntPoint(right, bottom);
2767             else
2768                 cmp = IntPoint(right, yPos);
2769         } else if (xPos < left) {
2770             if (yPos < top)
2771                 cmp = IntPoint(left, top);
2772             else if (yPos > bottom)
2773                 cmp = IntPoint(left, bottom);
2774             else
2775                 cmp = IntPoint(left, yPos);
2776         } else {
2777             if (yPos < top)
2778                 cmp = IntPoint(xPos, top);
2779             else
2780                 cmp = IntPoint(xPos, bottom);
2781         }
2782 
2783         int x1minusx2 = cmp.x() - xPos;
2784         int y1minusy2 = cmp.y() - yPos;
2785 
2786         int dist = x1minusx2 * x1minusx2 + y1minusy2 * y1minusy2;
2787         if (dist < minDist) {
2788             closestRenderer = renderer;
2789             minDist = dist;
2790         }
2791     }
2792 
2793     if (closestRenderer)
2794         return closestRenderer->positionForCoordinates(newX - closestRenderer->x(), newY - closestRenderer->y());
2795 
2796     return createVisiblePosition(firstDeepEditingPositionForNode(node()));
2797 }
2798 
shrinkToAvoidFloats() const2799 bool RenderBox::shrinkToAvoidFloats() const
2800 {
2801     // FIXME: Technically we should be able to shrink replaced elements on a line, but this is difficult to accomplish, since this
2802     // involves doing a relayout during findNextLineBreak and somehow overriding the containingBlockWidth method to return the
2803     // current remaining width on a line.
2804     if ((isInline() && !isHTMLMarquee()) || !avoidsFloats())
2805         return false;
2806 
2807     // All auto-width objects that avoid floats should always use lineWidth.
2808     return style()->width().isAuto();
2809 }
2810 
avoidsFloats() const2811 bool RenderBox::avoidsFloats() const
2812 {
2813     return isReplaced() || hasOverflowClip() || isHR();
2814 }
2815 
2816 #if ENABLE(SVG)
2817 
localTransform() const2818 TransformationMatrix RenderBox::localTransform() const
2819 {
2820     return TransformationMatrix(1, 0, 0, 1, x(), y());
2821 }
2822 
2823 #endif
2824 
2825 } // namespace WebCore
2826