• 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, 2010 Apple Inc. All rights reserved.
7  * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  *
24  */
25 
26 #include "config.h"
27 #include "core/rendering/RenderBox.h"
28 
29 #include <math.h>
30 #include <algorithm>
31 #include "HTMLNames.h"
32 #include "core/dom/Document.h"
33 #include "core/editing/htmlediting.h"
34 #include "core/html/HTMLElement.h"
35 #include "core/html/HTMLFrameElementBase.h"
36 #include "core/html/HTMLFrameOwnerElement.h"
37 #include "core/html/HTMLHtmlElement.h"
38 #include "core/html/HTMLTextAreaElement.h"
39 #include "core/frame/Frame.h"
40 #include "core/frame/FrameView.h"
41 #include "core/page/AutoscrollController.h"
42 #include "core/page/EventHandler.h"
43 #include "core/page/Page.h"
44 #include "core/rendering/HitTestResult.h"
45 #include "core/rendering/LayoutRectRecorder.h"
46 #include "core/rendering/PaintInfo.h"
47 #include "core/rendering/RenderBoxRegionInfo.h"
48 #include "core/rendering/RenderFlexibleBox.h"
49 #include "core/rendering/RenderFlowThread.h"
50 #include "core/rendering/RenderGeometryMap.h"
51 #include "core/rendering/RenderGrid.h"
52 #include "core/rendering/RenderInline.h"
53 #include "core/rendering/RenderLayer.h"
54 #include "core/rendering/RenderLayerCompositor.h"
55 #include "core/rendering/RenderListMarker.h"
56 #include "core/rendering/RenderRegion.h"
57 #include "core/rendering/RenderTableCell.h"
58 #include "core/rendering/RenderTheme.h"
59 #include "core/rendering/RenderView.h"
60 #include "platform/geometry/FloatQuad.h"
61 #include "platform/geometry/TransformState.h"
62 #include "platform/graphics/GraphicsContextStateSaver.h"
63 
64 using namespace std;
65 
66 namespace WebCore {
67 
68 using namespace HTMLNames;
69 
70 // Used by flexible boxes when flexing this element and by table cells.
71 typedef WTF::HashMap<const RenderBox*, LayoutUnit> OverrideSizeMap;
72 static OverrideSizeMap* gOverrideHeightMap = 0;
73 static OverrideSizeMap* gOverrideWidthMap = 0;
74 
75 // Used by grid elements to properly size their grid items.
76 static OverrideSizeMap* gOverrideContainingBlockLogicalHeightMap = 0;
77 static OverrideSizeMap* gOverrideContainingBlockLogicalWidthMap = 0;
78 
79 
80 // Size of border belt for autoscroll. When mouse pointer in border belt,
81 // autoscroll is started.
82 static const int autoscrollBeltSize = 20;
83 static const unsigned backgroundObscurationTestMaxDepth = 4;
84 
skipBodyBackground(const RenderBox * bodyElementRenderer)85 static bool skipBodyBackground(const RenderBox* bodyElementRenderer)
86 {
87     ASSERT(bodyElementRenderer->isBody());
88     // The <body> only paints its background if the root element has defined a background independent of the body,
89     // or if the <body>'s parent is not the document element's renderer (e.g. inside SVG foreignObject).
90     RenderObject* documentElementRenderer = bodyElementRenderer->document().documentElement()->renderer();
91     return documentElementRenderer
92         && !documentElementRenderer->hasBackground()
93         && (documentElementRenderer == bodyElementRenderer->parent());
94 }
95 
RenderBox(ContainerNode * node)96 RenderBox::RenderBox(ContainerNode* node)
97     : RenderBoxModelObject(node)
98     , m_minPreferredLogicalWidth(-1)
99     , m_maxPreferredLogicalWidth(-1)
100     , m_intrinsicContentLogicalHeight(-1)
101     , m_inlineBoxWrapper(0)
102 {
103     setIsBox();
104 }
105 
~RenderBox()106 RenderBox::~RenderBox()
107 {
108 }
109 
borderBoxRectInRegion(RenderRegion * region,RenderBoxRegionInfoFlags cacheFlag) const110 LayoutRect RenderBox::borderBoxRectInRegion(RenderRegion* region, RenderBoxRegionInfoFlags cacheFlag) const
111 {
112     if (!region)
113         return borderBoxRect();
114 
115     // Compute the logical width and placement in this region.
116     RenderBoxRegionInfo* boxInfo = renderBoxRegionInfo(region, cacheFlag);
117     if (!boxInfo)
118         return borderBoxRect();
119 
120     // We have cached insets.
121     LayoutUnit logicalWidth = boxInfo->logicalWidth();
122     LayoutUnit logicalLeft = boxInfo->logicalLeft();
123 
124     // Now apply the parent inset since it is cumulative whenever anything in the containing block chain shifts.
125     // FIXME: Doesn't work right with perpendicular writing modes.
126     const RenderBlock* currentBox = containingBlock();
127     RenderBoxRegionInfo* currentBoxInfo = currentBox->renderBoxRegionInfo(region);
128     while (currentBoxInfo && currentBoxInfo->isShifted()) {
129         if (currentBox->style()->direction() == LTR)
130             logicalLeft += currentBoxInfo->logicalLeft();
131         else
132             logicalLeft -= (currentBox->logicalWidth() - currentBoxInfo->logicalWidth()) - currentBoxInfo->logicalLeft();
133         currentBox = currentBox->containingBlock();
134         region = currentBox->clampToStartAndEndRegions(region);
135         currentBoxInfo = currentBox->renderBoxRegionInfo(region);
136     }
137 
138     if (cacheFlag == DoNotCacheRenderBoxRegionInfo)
139         delete boxInfo;
140 
141     if (isHorizontalWritingMode())
142         return LayoutRect(logicalLeft, 0, logicalWidth, height());
143     return LayoutRect(0, logicalLeft, width(), logicalWidth);
144 }
145 
clearRenderBoxRegionInfo()146 void RenderBox::clearRenderBoxRegionInfo()
147 {
148     if (isRenderFlowThread())
149         return;
150 
151     RenderFlowThread* flowThread = flowThreadContainingBlock();
152     if (flowThread)
153         flowThread->removeRenderBoxRegionInfo(this);
154 }
155 
willBeDestroyed()156 void RenderBox::willBeDestroyed()
157 {
158     clearOverrideSize();
159     clearContainingBlockOverrideSize();
160 
161     RenderBlock::removePercentHeightDescendantIfNeeded(this);
162 
163     ShapeOutsideInfo::removeInfo(this);
164 
165     RenderBoxModelObject::willBeDestroyed();
166 }
167 
removeFloatingOrPositionedChildFromBlockLists()168 void RenderBox::removeFloatingOrPositionedChildFromBlockLists()
169 {
170     ASSERT(isFloatingOrOutOfFlowPositioned());
171 
172     if (documentBeingDestroyed())
173         return;
174 
175     if (isFloating()) {
176         RenderBlockFlow* parentBlockFlow = 0;
177         for (RenderObject* curr = parent(); curr && !curr->isRenderView(); curr = curr->parent()) {
178             if (curr->isRenderBlockFlow()) {
179                 RenderBlockFlow* currBlockFlow = toRenderBlockFlow(curr);
180                 if (!parentBlockFlow || currBlockFlow->containsFloat(this))
181                     parentBlockFlow = currBlockFlow;
182             }
183         }
184 
185         if (parentBlockFlow) {
186             parentBlockFlow->markSiblingsWithFloatsForLayout(this);
187             parentBlockFlow->markAllDescendantsWithFloatsForLayout(this, false);
188         }
189     }
190 
191     if (isOutOfFlowPositioned())
192         RenderBlock::removePositionedObject(this);
193 }
194 
styleWillChange(StyleDifference diff,const RenderStyle * newStyle)195 void RenderBox::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
196 {
197     RenderStyle* oldStyle = style();
198     if (oldStyle) {
199         // The background of the root element or the body element could propagate up to
200         // the canvas.  Just dirty the entire canvas when our style changes substantially.
201         if (diff >= StyleDifferenceRepaint && node() &&
202             (isHTMLHtmlElement(node()) || node()->hasTagName(bodyTag))) {
203             view()->repaint();
204 
205             if (oldStyle->hasEntirelyFixedBackground() != newStyle->hasEntirelyFixedBackground())
206                 view()->compositor()->rootFixedBackgroundsChanged();
207         }
208 
209         // When a layout hint happens and an object's position style changes, we have to do a layout
210         // to dirty the render tree using the old position value now.
211         if (diff == StyleDifferenceLayout && parent() && oldStyle->position() != newStyle->position()) {
212             markContainingBlocksForLayout();
213             if (oldStyle->position() == StaticPosition)
214                 repaint();
215             else if (newStyle->hasOutOfFlowPosition())
216                 parent()->setChildNeedsLayout();
217             if (isFloating() && !isOutOfFlowPositioned() && newStyle->hasOutOfFlowPosition())
218                 removeFloatingOrPositionedChildFromBlockLists();
219         }
220     } else if (newStyle && isBody())
221         view()->repaint();
222 
223     RenderBoxModelObject::styleWillChange(diff, newStyle);
224 }
225 
styleDidChange(StyleDifference diff,const RenderStyle * oldStyle)226 void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
227 {
228     // Horizontal writing mode definition is updated in RenderBoxModelObject::updateFromStyle,
229     // (as part of the RenderBoxModelObject::styleDidChange call below). So, we can safely cache the horizontal
230     // writing mode value before style change here.
231     bool oldHorizontalWritingMode = isHorizontalWritingMode();
232 
233     RenderBoxModelObject::styleDidChange(diff, oldStyle);
234 
235     RenderStyle* newStyle = style();
236     if (needsLayout() && oldStyle) {
237         RenderBlock::removePercentHeightDescendantIfNeeded(this);
238 
239         // Normally we can do optimized positioning layout for absolute/fixed positioned objects. There is one special case, however, which is
240         // when the positioned object's margin-before is changed. In this case the parent has to get a layout in order to run margin collapsing
241         // to determine the new static position.
242         if (isOutOfFlowPositioned() && newStyle->hasStaticBlockPosition(isHorizontalWritingMode()) && oldStyle->marginBefore() != newStyle->marginBefore()
243             && parent() && !parent()->normalChildNeedsLayout())
244             parent()->setChildNeedsLayout();
245     }
246 
247     if (RenderBlock::hasPercentHeightContainerMap() && firstChild()
248         && oldHorizontalWritingMode != isHorizontalWritingMode())
249         RenderBlock::clearPercentHeightDescendantsFrom(this);
250 
251     // If our zoom factor changes and we have a defined scrollLeft/Top, we need to adjust that value into the
252     // new zoomed coordinate space.
253     if (hasOverflowClip() && oldStyle && newStyle && oldStyle->effectiveZoom() != newStyle->effectiveZoom() && layer()) {
254         if (int left = layer()->scrollableArea()->scrollXOffset()) {
255             left = (left / oldStyle->effectiveZoom()) * newStyle->effectiveZoom();
256             layer()->scrollableArea()->scrollToXOffset(left);
257         }
258         if (int top = layer()->scrollableArea()->scrollYOffset()) {
259             top = (top / oldStyle->effectiveZoom()) * newStyle->effectiveZoom();
260             layer()->scrollableArea()->scrollToYOffset(top);
261         }
262     }
263 
264     // Our opaqueness might have changed without triggering layout.
265     if (diff == StyleDifferenceRepaint || diff == StyleDifferenceRepaintIfTextOrColorChange || diff == StyleDifferenceRepaintLayer) {
266         RenderObject* parentToInvalidate = parent();
267         for (unsigned i = 0; i < backgroundObscurationTestMaxDepth && parentToInvalidate; ++i) {
268             parentToInvalidate->invalidateBackgroundObscurationStatus();
269             parentToInvalidate = parentToInvalidate->parent();
270         }
271     }
272 
273     if (isRoot() || isBody())
274         document().view()->recalculateScrollbarOverlayStyle();
275 
276     updateShapeOutsideInfoAfterStyleChange(*style(), oldStyle);
277     updateGridPositionAfterStyleChange(oldStyle);
278 }
279 
updateShapeOutsideInfoAfterStyleChange(const RenderStyle & style,const RenderStyle * oldStyle)280 void RenderBox::updateShapeOutsideInfoAfterStyleChange(const RenderStyle& style, const RenderStyle* oldStyle)
281 {
282     const ShapeValue* shapeOutside = style.shapeOutside();
283     const ShapeValue* oldShapeOutside = oldStyle ? oldStyle->shapeOutside() : RenderStyle::initialShapeOutside();
284 
285     Length shapeMargin = style.shapeMargin();
286     Length oldShapeMargin = oldStyle ? oldStyle->shapeMargin() : RenderStyle::initialShapeMargin();
287 
288     float shapeImageThreshold = style.shapeImageThreshold();
289     float oldShapeImageThreshold = oldStyle ? oldStyle->shapeImageThreshold() : RenderStyle::initialShapeImageThreshold();
290 
291     // FIXME: A future optimization would do a deep comparison for equality. (bug 100811)
292     if (shapeOutside == oldShapeOutside && shapeMargin == oldShapeMargin && shapeImageThreshold == oldShapeImageThreshold)
293         return;
294 
295     if (!shapeOutside)
296         ShapeOutsideInfo::removeInfo(this);
297     else
298         ShapeOutsideInfo::ensureInfo(this)->dirtyShapeSize();
299 
300     if (shapeOutside || shapeOutside != oldShapeOutside)
301         markShapeOutsideDependentsForLayout();
302 }
303 
updateGridPositionAfterStyleChange(const RenderStyle * oldStyle)304 void RenderBox::updateGridPositionAfterStyleChange(const RenderStyle* oldStyle)
305 {
306     if (!oldStyle || !parent() || !parent()->isRenderGrid())
307         return;
308 
309     if (oldStyle->gridColumnStart() == style()->gridColumnStart()
310         && oldStyle->gridColumnEnd() == style()->gridColumnEnd()
311         && oldStyle->gridRowStart() == style()->gridRowStart()
312         && oldStyle->gridRowEnd() == style()->gridRowEnd()
313         && oldStyle->order() == style()->order()
314         && oldStyle->hasOutOfFlowPosition() == style()->hasOutOfFlowPosition())
315         return;
316 
317     // It should be possible to not dirty the grid in some cases (like moving an explicitly placed grid item).
318     // For now, it's more simple to just always recompute the grid.
319     toRenderGrid(parent())->dirtyGrid();
320 }
321 
updateFromStyle()322 void RenderBox::updateFromStyle()
323 {
324     RenderBoxModelObject::updateFromStyle();
325 
326     RenderStyle* styleToUse = style();
327     bool isRootObject = isRoot();
328     bool isViewObject = isRenderView();
329 
330     // The root and the RenderView always paint their backgrounds/borders.
331     if (isRootObject || isViewObject)
332         setHasBoxDecorations(true);
333 
334     setFloating(!isOutOfFlowPositioned() && styleToUse->isFloating());
335 
336     bool boxHasOverflowClip = false;
337     // We also handle <body> and <html>, whose overflow applies to the viewport.
338     // It's sufficient to just check one direction, since it's illegal to have visible on only one overflow value.
339     if (styleToUse->overflowX() != OVISIBLE && !isRootObject && isRenderBlock()) {
340         // Overflow on the body can propagate to the viewport under the following conditions.
341         // (1) The root element is <html>.
342         // (2) We are the primary <body> (can be checked by looking at document.body).
343         // (3) The root element has visible overflow.
344         if (isBody() && isHTMLHtmlElement(document().documentElement())
345             && document().body() == node()
346             && document().documentElement()->renderer()->style()->overflowX() == OVISIBLE) {
347             boxHasOverflowClip = false;
348         } else {
349             boxHasOverflowClip = true;
350             if (!hasOverflowClip()) {
351                 // If we are getting an overflow clip, preemptively erase any overflowing content.
352                 // FIXME: This should probably consult RenderOverflow.
353                 repaint();
354             }
355         }
356     }
357     setHasOverflowClip(boxHasOverflowClip);
358 
359     setHasTransform(styleToUse->hasTransformRelatedProperty());
360     setHasReflection(styleToUse->boxReflect());
361 }
362 
layout()363 void RenderBox::layout()
364 {
365     ASSERT(needsLayout());
366 
367     LayoutRectRecorder recorder(*this);
368 
369     RenderObject* child = firstChild();
370     if (!child) {
371         clearNeedsLayout();
372         return;
373     }
374 
375     LayoutStateMaintainer statePusher(view(), this, locationOffset(), style()->isFlippedBlocksWritingMode());
376     while (child) {
377         child->layoutIfNeeded();
378         ASSERT(!child->needsLayout());
379         child = child->nextSibling();
380     }
381     statePusher.pop();
382     invalidateBackgroundObscurationStatus();
383     clearNeedsLayout();
384 }
385 
386 // More IE extensions.  clientWidth and clientHeight represent the interior of an object
387 // excluding border and scrollbar.
clientWidth() const388 LayoutUnit RenderBox::clientWidth() const
389 {
390     return width() - borderLeft() - borderRight() - verticalScrollbarWidth();
391 }
392 
clientHeight() const393 LayoutUnit RenderBox::clientHeight() const
394 {
395     return height() - borderTop() - borderBottom() - horizontalScrollbarHeight();
396 }
397 
pixelSnappedClientWidth() const398 int RenderBox::pixelSnappedClientWidth() const
399 {
400     return snapSizeToPixel(clientWidth(), x() + clientLeft());
401 }
402 
pixelSnappedClientHeight() const403 int RenderBox::pixelSnappedClientHeight() const
404 {
405     return snapSizeToPixel(clientHeight(), y() + clientTop());
406 }
407 
pixelSnappedOffsetWidth() const408 int RenderBox::pixelSnappedOffsetWidth() const
409 {
410     return snapSizeToPixel(offsetWidth(), x() + clientLeft());
411 }
412 
pixelSnappedOffsetHeight() const413 int RenderBox::pixelSnappedOffsetHeight() const
414 {
415     return snapSizeToPixel(offsetHeight(), y() + clientTop());
416 }
417 
canDetermineWidthWithoutLayout() const418 bool RenderBox::canDetermineWidthWithoutLayout() const
419 {
420     // FIXME: This optimization is incorrect as written.
421     // We need to be able to opt-in to this behavior only when
422     // it's guarentted correct.
423     // Until then disabling this optimization to be safe.
424     return false;
425 
426     // FIXME: There are likely many subclasses of RenderBlockFlow which
427     // cannot determine their layout just from style!
428     // Perhaps we should create a "PlainRenderBlockFlow"
429     // and move this optimization there?
430     if (!isRenderBlockFlow()
431         // Flexbox items can be expanded beyond their width.
432         || isFlexItemIncludingDeprecated()
433         // Table Layout controls cell size and can expand beyond width.
434         || isTableCell())
435         return false;
436 
437     RenderStyle* style = this->style();
438     return style->width().isFixed()
439         && style->minWidth().isFixed()
440         && (style->maxWidth().isUndefined() || style->maxWidth().isFixed())
441         && style->paddingLeft().isFixed()
442         && style->paddingRight().isFixed()
443         && style->boxSizing() == CONTENT_BOX;
444 }
445 
fixedOffsetWidth() const446 LayoutUnit RenderBox::fixedOffsetWidth() const
447 {
448     ASSERT(canDetermineWidthWithoutLayout());
449 
450     RenderStyle* style = this->style();
451 
452     LayoutUnit width = std::max(LayoutUnit(style->minWidth().value()), LayoutUnit(style->width().value()));
453     if (style->maxWidth().isFixed())
454         width = std::min(LayoutUnit(style->maxWidth().value()), width);
455 
456     LayoutUnit borderLeft = style->borderLeft().nonZero() ? style->borderLeft().width() : 0;
457     LayoutUnit borderRight = style->borderRight().nonZero() ? style->borderRight().width() : 0;
458 
459     return width + borderLeft + borderRight + style->paddingLeft().value() + style->paddingRight().value();
460 }
461 
scrollWidth() const462 int RenderBox::scrollWidth() const
463 {
464     if (hasOverflowClip())
465         return layer()->scrollableArea()->scrollWidth();
466     // For objects with visible overflow, this matches IE.
467     // FIXME: Need to work right with writing modes.
468     if (style()->isLeftToRightDirection())
469         return snapSizeToPixel(max(clientWidth(), layoutOverflowRect().maxX() - borderLeft()), x() + clientLeft());
470     return clientWidth() - min<LayoutUnit>(0, layoutOverflowRect().x() - borderLeft());
471 }
472 
scrollHeight() const473 int RenderBox::scrollHeight() const
474 {
475     if (hasOverflowClip())
476         return layer()->scrollableArea()->scrollHeight();
477     // For objects with visible overflow, this matches IE.
478     // FIXME: Need to work right with writing modes.
479     return snapSizeToPixel(max(clientHeight(), layoutOverflowRect().maxY() - borderTop()), y() + clientTop());
480 }
481 
scrollLeft() const482 int RenderBox::scrollLeft() const
483 {
484     return hasOverflowClip() ? layer()->scrollableArea()->scrollXOffset() : 0;
485 }
486 
scrollTop() const487 int RenderBox::scrollTop() const
488 {
489     return hasOverflowClip() ? layer()->scrollableArea()->scrollYOffset() : 0;
490 }
491 
setScrollLeft(int newLeft)492 void RenderBox::setScrollLeft(int newLeft)
493 {
494     if (hasOverflowClip())
495         layer()->scrollableArea()->scrollToXOffset(newLeft, ScrollOffsetClamped);
496 }
497 
setScrollTop(int newTop)498 void RenderBox::setScrollTop(int newTop)
499 {
500     if (hasOverflowClip())
501         layer()->scrollableArea()->scrollToYOffset(newTop, ScrollOffsetClamped);
502 }
503 
scrollToOffset(const IntSize & offset)504 void RenderBox::scrollToOffset(const IntSize& offset)
505 {
506     ASSERT(hasOverflowClip());
507     layer()->scrollableArea()->scrollToOffset(offset, ScrollOffsetClamped);
508 }
509 
frameElementAndViewPermitScroll(HTMLFrameElementBase * frameElementBase,FrameView * frameView)510 static inline bool frameElementAndViewPermitScroll(HTMLFrameElementBase* frameElementBase, FrameView* frameView)
511 {
512     // If scrollbars aren't explicitly forbidden, permit scrolling.
513     if (frameElementBase && frameElementBase->scrollingMode() != ScrollbarAlwaysOff)
514         return true;
515 
516     // If scrollbars are forbidden, user initiated scrolls should obviously be ignored.
517     if (frameView->wasScrolledByUser())
518         return false;
519 
520     // Forbid autoscrolls when scrollbars are off, but permits other programmatic scrolls,
521     // like navigation to an anchor.
522     Page* page = frameView->frame().page();
523     if (!page)
524         return false;
525     return !page->autoscrollController().autoscrollInProgress();
526 }
527 
scrollRectToVisible(const LayoutRect & rect,const ScrollAlignment & alignX,const ScrollAlignment & alignY)528 void RenderBox::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
529 {
530     RenderBox* parentBox = 0;
531     LayoutRect newRect = rect;
532 
533     bool restrictedByLineClamp = false;
534     if (parent()) {
535         parentBox = parent()->enclosingBox();
536         restrictedByLineClamp = !parent()->style()->lineClamp().isNone();
537     }
538 
539     if (hasOverflowClip() && !restrictedByLineClamp) {
540         // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property.
541         // This will prevent us from revealing text hidden by the slider in Safari RSS.
542         newRect = layer()->scrollableArea()->exposeRect(rect, alignX, alignY);
543     } else if (!parentBox && canBeProgramaticallyScrolled()) {
544         if (FrameView* frameView = this->frameView()) {
545             Element* ownerElement = document().ownerElement();
546 
547             if (ownerElement && ownerElement->renderer()) {
548                 HTMLFrameElementBase* frameElementBase = 0;
549 
550                 if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))
551                     frameElementBase = toHTMLFrameElementBase(ownerElement);
552 
553                 if (frameElementAndViewPermitScroll(frameElementBase, frameView)) {
554                     LayoutRect viewRect = frameView->visibleContentRect();
555                     LayoutRect exposeRect = ScrollAlignment::getRectToExpose(viewRect, rect, alignX, alignY);
556 
557                     int xOffset = roundToInt(exposeRect.x());
558                     int yOffset = roundToInt(exposeRect.y());
559                     // Adjust offsets if they're outside of the allowable range.
560                     xOffset = max(0, min(frameView->contentsWidth(), xOffset));
561                     yOffset = max(0, min(frameView->contentsHeight(), yOffset));
562 
563                     frameView->setScrollPosition(IntPoint(xOffset, yOffset));
564                     if (frameView->safeToPropagateScrollToParent()) {
565                         parentBox = ownerElement->renderer()->enclosingBox();
566                         // FIXME: This doesn't correctly convert the rect to
567                         // absolute coordinates in the parent.
568                         newRect.setX(rect.x() - frameView->scrollX() + frameView->x());
569                         newRect.setY(rect.y() - frameView->scrollY() + frameView->y());
570                     } else {
571                         parentBox = 0;
572                     }
573                 }
574             } else {
575                 LayoutRect viewRect = frameView->visibleContentRect();
576                 LayoutRect r = ScrollAlignment::getRectToExpose(viewRect, rect, alignX, alignY);
577                 frameView->setScrollPosition(roundedIntPoint(r.location()));
578             }
579         }
580     }
581 
582     if (frame()->page()->autoscrollController().autoscrollInProgress())
583         parentBox = enclosingScrollableBox();
584 
585     if (parentBox)
586         parentBox->scrollRectToVisible(newRect, alignX, alignY);
587 }
588 
absoluteRects(Vector<IntRect> & rects,const LayoutPoint & accumulatedOffset) const589 void RenderBox::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
590 {
591     rects.append(pixelSnappedIntRect(accumulatedOffset, size()));
592 }
593 
absoluteQuads(Vector<FloatQuad> & quads,bool * wasFixed) const594 void RenderBox::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
595 {
596     quads.append(localToAbsoluteQuad(FloatRect(0, 0, width(), height()), 0 /* mode */, wasFixed));
597 }
598 
updateLayerTransform()599 void RenderBox::updateLayerTransform()
600 {
601     // Transform-origin depends on box size, so we need to update the layer transform after layout.
602     if (hasLayer())
603         layer()->updateTransform();
604 }
605 
constrainLogicalWidthInRegionByMinMax(LayoutUnit logicalWidth,LayoutUnit availableWidth,RenderBlock * cb,RenderRegion * region) const606 LayoutUnit RenderBox::constrainLogicalWidthInRegionByMinMax(LayoutUnit logicalWidth, LayoutUnit availableWidth, RenderBlock* cb, RenderRegion* region) const
607 {
608     RenderStyle* styleToUse = style();
609     if (!styleToUse->logicalMaxWidth().isUndefined())
610         logicalWidth = min(logicalWidth, computeLogicalWidthInRegionUsing(MaxSize, styleToUse->logicalMaxWidth(), availableWidth, cb, region));
611     return max(logicalWidth, computeLogicalWidthInRegionUsing(MinSize, styleToUse->logicalMinWidth(), availableWidth, cb, region));
612 }
613 
constrainLogicalHeightByMinMax(LayoutUnit logicalHeight,LayoutUnit intrinsicContentHeight) const614 LayoutUnit RenderBox::constrainLogicalHeightByMinMax(LayoutUnit logicalHeight, LayoutUnit intrinsicContentHeight) const
615 {
616     RenderStyle* styleToUse = style();
617     if (!styleToUse->logicalMaxHeight().isUndefined()) {
618         LayoutUnit maxH = computeLogicalHeightUsing(styleToUse->logicalMaxHeight(), intrinsicContentHeight);
619         if (maxH != -1)
620             logicalHeight = min(logicalHeight, maxH);
621     }
622     return max(logicalHeight, computeLogicalHeightUsing(styleToUse->logicalMinHeight(), intrinsicContentHeight));
623 }
624 
constrainContentBoxLogicalHeightByMinMax(LayoutUnit logicalHeight,LayoutUnit intrinsicContentHeight) const625 LayoutUnit RenderBox::constrainContentBoxLogicalHeightByMinMax(LayoutUnit logicalHeight, LayoutUnit intrinsicContentHeight) const
626 {
627     RenderStyle* styleToUse = style();
628     if (!styleToUse->logicalMaxHeight().isUndefined()) {
629         LayoutUnit maxH = computeContentLogicalHeight(styleToUse->logicalMaxHeight(), intrinsicContentHeight);
630         if (maxH != -1)
631             logicalHeight = min(logicalHeight, maxH);
632     }
633     return max(logicalHeight, computeContentLogicalHeight(styleToUse->logicalMinHeight(), intrinsicContentHeight));
634 }
635 
absoluteContentBox() const636 IntRect RenderBox::absoluteContentBox() const
637 {
638     // This is wrong with transforms and flipped writing modes.
639     IntRect rect = pixelSnappedIntRect(contentBoxRect());
640     FloatPoint absPos = localToAbsolute();
641     rect.move(absPos.x(), absPos.y());
642     return rect;
643 }
644 
absoluteContentQuad() const645 FloatQuad RenderBox::absoluteContentQuad() const
646 {
647     LayoutRect rect = contentBoxRect();
648     return localToAbsoluteQuad(FloatRect(rect));
649 }
650 
outlineBoundsForRepaint(const RenderLayerModelObject * repaintContainer,const RenderGeometryMap * geometryMap) const651 LayoutRect RenderBox::outlineBoundsForRepaint(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap) const
652 {
653     LayoutRect box = borderBoundingBox();
654     adjustRectForOutlineAndShadow(box);
655 
656     if (repaintContainer != this) {
657         FloatQuad containerRelativeQuad;
658         if (geometryMap)
659             containerRelativeQuad = geometryMap->mapToContainer(box, repaintContainer);
660         else
661             containerRelativeQuad = localToContainerQuad(FloatRect(box), repaintContainer);
662 
663         box = containerRelativeQuad.enclosingBoundingBox();
664     }
665 
666     // FIXME: layoutDelta needs to be applied in parts before/after transforms and
667     // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
668     box.move(view()->layoutDelta());
669 
670     return box;
671 }
672 
addFocusRingRects(Vector<IntRect> & rects,const LayoutPoint & additionalOffset,const RenderLayerModelObject *)673 void RenderBox::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
674 {
675     if (!size().isEmpty())
676         rects.append(pixelSnappedIntRect(additionalOffset, size()));
677 }
678 
canResize() const679 bool RenderBox::canResize() const
680 {
681     // We need a special case for <iframe> because they never have
682     // hasOverflowClip(). However, they do "implicitly" clip their contents, so
683     // we want to allow resizing them also.
684     return (hasOverflowClip() || isRenderIFrame()) && style()->resize() != RESIZE_NONE;
685 }
686 
addLayerHitTestRects(LayerHitTestRects & layerRects,const RenderLayer * currentLayer,const LayoutPoint & layerOffset,const LayoutRect & containerRect) const687 void RenderBox::addLayerHitTestRects(LayerHitTestRects& layerRects, const RenderLayer* currentLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const
688 {
689     LayoutPoint adjustedLayerOffset = layerOffset + locationOffset();
690     RenderBoxModelObject::addLayerHitTestRects(layerRects, currentLayer, adjustedLayerOffset, containerRect);
691 }
692 
computeSelfHitTestRects(Vector<LayoutRect> & rects,const LayoutPoint & layerOffset) const693 void RenderBox::computeSelfHitTestRects(Vector<LayoutRect>& rects, const LayoutPoint& layerOffset) const
694 {
695     if (!size().isEmpty())
696         rects.append(LayoutRect(layerOffset, size()));
697 }
698 
reflectionBox() const699 LayoutRect RenderBox::reflectionBox() const
700 {
701     LayoutRect result;
702     if (!style()->boxReflect())
703         return result;
704     LayoutRect box = borderBoxRect();
705     result = box;
706     switch (style()->boxReflect()->direction()) {
707         case ReflectionBelow:
708             result.move(0, box.height() + reflectionOffset());
709             break;
710         case ReflectionAbove:
711             result.move(0, -box.height() - reflectionOffset());
712             break;
713         case ReflectionLeft:
714             result.move(-box.width() - reflectionOffset(), 0);
715             break;
716         case ReflectionRight:
717             result.move(box.width() + reflectionOffset(), 0);
718             break;
719     }
720     return result;
721 }
722 
reflectionOffset() const723 int RenderBox::reflectionOffset() const
724 {
725     if (!style()->boxReflect())
726         return 0;
727     RenderView* renderView = view();
728     if (style()->boxReflect()->direction() == ReflectionLeft || style()->boxReflect()->direction() == ReflectionRight)
729         return valueForLength(style()->boxReflect()->offset(), borderBoxRect().width(), renderView);
730     return valueForLength(style()->boxReflect()->offset(), borderBoxRect().height(), renderView);
731 }
732 
reflectedRect(const LayoutRect & r) const733 LayoutRect RenderBox::reflectedRect(const LayoutRect& r) const
734 {
735     if (!style()->boxReflect())
736         return LayoutRect();
737 
738     LayoutRect box = borderBoxRect();
739     LayoutRect result = r;
740     switch (style()->boxReflect()->direction()) {
741         case ReflectionBelow:
742             result.setY(box.maxY() + reflectionOffset() + (box.maxY() - r.maxY()));
743             break;
744         case ReflectionAbove:
745             result.setY(box.y() - reflectionOffset() - box.height() + (box.maxY() - r.maxY()));
746             break;
747         case ReflectionLeft:
748             result.setX(box.x() - reflectionOffset() - box.width() + (box.maxX() - r.maxX()));
749             break;
750         case ReflectionRight:
751             result.setX(box.maxX() + reflectionOffset() + (box.maxX() - r.maxX()));
752             break;
753     }
754     return result;
755 }
756 
verticalScrollbarWidth() const757 int RenderBox::verticalScrollbarWidth() const
758 {
759     if (!hasOverflowClip() || style()->overflowY() == OOVERLAY)
760         return 0;
761 
762     return layer()->scrollableArea()->verticalScrollbarWidth();
763 }
764 
horizontalScrollbarHeight() const765 int RenderBox::horizontalScrollbarHeight() const
766 {
767     if (!hasOverflowClip() || style()->overflowX() == OOVERLAY)
768         return 0;
769 
770     return layer()->scrollableArea()->horizontalScrollbarHeight();
771 }
772 
instrinsicScrollbarLogicalWidth() const773 int RenderBox::instrinsicScrollbarLogicalWidth() const
774 {
775     if (!hasOverflowClip())
776         return 0;
777 
778     if (isHorizontalWritingMode() && style()->overflowY() == OSCROLL) {
779         ASSERT(layer()->scrollableArea() && layer()->scrollableArea()->hasVerticalScrollbar());
780         return verticalScrollbarWidth();
781     }
782 
783     if (!isHorizontalWritingMode() && style()->overflowX() == OSCROLL) {
784         ASSERT(layer()->scrollableArea() && layer()->scrollableArea()->hasHorizontalScrollbar());
785         return horizontalScrollbarHeight();
786     }
787 
788     return 0;
789 }
790 
scroll(ScrollDirection direction,ScrollGranularity granularity,float multiplier)791 bool RenderBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
792 {
793     // Logical scroll is a higher level concept, all directions by here must be physical
794     ASSERT(!isLogical(direction));
795 
796     if (!layer() || !layer()->scrollableArea())
797         return false;
798 
799     return layer()->scrollableArea()->scroll(direction, granularity, multiplier);
800 }
801 
canBeScrolledAndHasScrollableArea() const802 bool RenderBox::canBeScrolledAndHasScrollableArea() const
803 {
804     return canBeProgramaticallyScrolled() && (scrollHeight() != clientHeight() || scrollWidth() != clientWidth());
805 }
806 
canBeProgramaticallyScrolled() const807 bool RenderBox::canBeProgramaticallyScrolled() const
808 {
809     Node* node = this->node();
810     if (node && node->isDocumentNode())
811         return true;
812 
813     if (!hasOverflowClip())
814         return false;
815 
816     bool hasScrollableOverflow = hasScrollableOverflowX() || hasScrollableOverflowY();
817     if (scrollsOverflow() && hasScrollableOverflow)
818         return true;
819 
820     return node && node->rendererIsEditable();
821 }
822 
usesCompositedScrolling() const823 bool RenderBox::usesCompositedScrolling() const
824 {
825     return hasOverflowClip() && hasLayer() && layer()->scrollableArea()->usesCompositedScrolling();
826 }
827 
autoscroll(const IntPoint & position)828 void RenderBox::autoscroll(const IntPoint& position)
829 {
830     Frame* frame = this->frame();
831     if (!frame)
832         return;
833 
834     FrameView* frameView = frame->view();
835     if (!frameView)
836         return;
837 
838     IntPoint currentDocumentPosition = frameView->windowToContents(position);
839     scrollRectToVisible(LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
840 }
841 
autoscrollInProgress() const842 bool RenderBox::autoscrollInProgress() const
843 {
844     return frame() && frame()->page() && frame()->page()->autoscrollController().autoscrollInProgress(this);
845 }
846 
847 // There are two kinds of renderer that can autoscroll.
canAutoscroll() const848 bool RenderBox::canAutoscroll() const
849 {
850     if (node() && node()->isDocumentNode())
851         return view()->frameView()->isScrollable();
852 
853     // Check for a box that can be scrolled in its own right.
854     return canBeScrolledAndHasScrollableArea();
855 }
856 
857 // If specified point is in border belt, returned offset denotes direction of
858 // scrolling.
calculateAutoscrollDirection(const IntPoint & windowPoint) const859 IntSize RenderBox::calculateAutoscrollDirection(const IntPoint& windowPoint) const
860 {
861     if (!frame())
862         return IntSize();
863 
864     FrameView* frameView = frame()->view();
865     if (!frameView)
866         return IntSize();
867 
868     IntRect box(absoluteBoundingBoxRect());
869     box.move(view()->frameView()->scrollOffset());
870     IntRect windowBox = view()->frameView()->contentsToWindow(box);
871 
872     IntPoint windowAutoscrollPoint = windowPoint;
873 
874     if (windowAutoscrollPoint.x() < windowBox.x() + autoscrollBeltSize)
875         windowAutoscrollPoint.move(-autoscrollBeltSize, 0);
876     else if (windowAutoscrollPoint.x() > windowBox.maxX() - autoscrollBeltSize)
877         windowAutoscrollPoint.move(autoscrollBeltSize, 0);
878 
879     if (windowAutoscrollPoint.y() < windowBox.y() + autoscrollBeltSize)
880         windowAutoscrollPoint.move(0, -autoscrollBeltSize);
881     else if (windowAutoscrollPoint.y() > windowBox.maxY() - autoscrollBeltSize)
882         windowAutoscrollPoint.move(0, autoscrollBeltSize);
883 
884     return windowAutoscrollPoint - windowPoint;
885 }
886 
findAutoscrollable(RenderObject * renderer)887 RenderBox* RenderBox::findAutoscrollable(RenderObject* renderer)
888 {
889     while (renderer && !(renderer->isBox() && toRenderBox(renderer)->canAutoscroll())) {
890         if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document().ownerElement())
891             renderer = renderer->document().ownerElement()->renderer();
892         else
893             renderer = renderer->parent();
894     }
895 
896     return renderer && renderer->isBox() ? toRenderBox(renderer) : 0;
897 }
898 
adjustedScrollDelta(int beginningDelta)899 static inline int adjustedScrollDelta(int beginningDelta)
900 {
901     // This implemention matches Firefox's.
902     // http://mxr.mozilla.org/firefox/source/toolkit/content/widgets/browser.xml#856.
903     const int speedReducer = 12;
904 
905     int adjustedDelta = beginningDelta / speedReducer;
906     if (adjustedDelta > 1)
907         adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(adjustedDelta))) - 1;
908     else if (adjustedDelta < -1)
909         adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(-adjustedDelta))) + 1;
910 
911     return adjustedDelta;
912 }
913 
adjustedScrollDelta(const IntSize & delta)914 static inline IntSize adjustedScrollDelta(const IntSize& delta)
915 {
916     return IntSize(adjustedScrollDelta(delta.width()), adjustedScrollDelta(delta.height()));
917 }
918 
panScroll(const IntPoint & sourcePoint)919 void RenderBox::panScroll(const IntPoint& sourcePoint)
920 {
921     Frame* frame = this->frame();
922     if (!frame)
923         return;
924 
925     IntPoint lastKnownMousePosition = frame->eventHandler().lastKnownMousePosition();
926 
927     // We need to check if the last known mouse position is out of the window. When the mouse is out of the window, the position is incoherent
928     static IntPoint previousMousePosition;
929     if (lastKnownMousePosition.x() < 0 || lastKnownMousePosition.y() < 0)
930         lastKnownMousePosition = previousMousePosition;
931     else
932         previousMousePosition = lastKnownMousePosition;
933 
934     IntSize delta = lastKnownMousePosition - sourcePoint;
935 
936     if (abs(delta.width()) <= ScrollView::noPanScrollRadius) // at the center we let the space for the icon
937         delta.setWidth(0);
938     if (abs(delta.height()) <= ScrollView::noPanScrollRadius)
939         delta.setHeight(0);
940 
941     scrollByRecursively(adjustedScrollDelta(delta), ScrollOffsetClamped);
942 }
943 
scrollByRecursively(const IntSize & delta,ScrollOffsetClamping clamp)944 void RenderBox::scrollByRecursively(const IntSize& delta, ScrollOffsetClamping clamp)
945 {
946     if (delta.isZero())
947         return;
948 
949     bool restrictedByLineClamp = false;
950     if (parent())
951         restrictedByLineClamp = !parent()->style()->lineClamp().isNone();
952 
953     if (hasOverflowClip() && !restrictedByLineClamp) {
954         IntSize newScrollOffset = layer()->scrollableArea()->adjustedScrollOffset() + delta;
955         layer()->scrollableArea()->scrollToOffset(newScrollOffset, clamp);
956 
957         // If this layer can't do the scroll we ask the next layer up that can scroll to try
958         IntSize remainingScrollOffset = newScrollOffset - layer()->scrollableArea()->adjustedScrollOffset();
959         if (!remainingScrollOffset.isZero() && parent()) {
960             if (RenderBox* scrollableBox = enclosingScrollableBox())
961                 scrollableBox->scrollByRecursively(remainingScrollOffset, clamp);
962 
963             Frame* frame = this->frame();
964             if (frame && frame->page())
965                 frame->page()->autoscrollController().updateAutoscrollRenderer();
966         }
967     } else if (view()->frameView()) {
968         // If we are here, we were called on a renderer that can be programmatically scrolled, but doesn't
969         // have an overflow clip. Which means that it is a document node that can be scrolled.
970         view()->frameView()->scrollBy(delta);
971 
972         // FIXME: If we didn't scroll the whole way, do we want to try looking at the frames ownerElement?
973         // https://bugs.webkit.org/show_bug.cgi?id=28237
974     }
975 }
976 
needsPreferredWidthsRecalculation() const977 bool RenderBox::needsPreferredWidthsRecalculation() const
978 {
979     return style()->paddingStart().isPercent() || style()->paddingEnd().isPercent();
980 }
981 
scrolledContentOffset() const982 IntSize RenderBox::scrolledContentOffset() const
983 {
984     ASSERT(hasOverflowClip());
985     ASSERT(hasLayer());
986     return layer()->scrollableArea()->scrollOffset();
987 }
988 
cachedSizeForOverflowClip() const989 LayoutSize RenderBox::cachedSizeForOverflowClip() const
990 {
991     ASSERT(hasOverflowClip());
992     ASSERT(hasLayer());
993     return layer()->size();
994 }
995 
applyCachedClipAndScrollOffsetForRepaint(LayoutRect & paintRect) const996 void RenderBox::applyCachedClipAndScrollOffsetForRepaint(LayoutRect& paintRect) const
997 {
998     paintRect.move(-scrolledContentOffset()); // For overflow:auto/scroll/hidden.
999 
1000     // Do not clip scroll layer contents to reduce the number of repaints while scrolling.
1001     if (usesCompositedScrolling())
1002         return;
1003 
1004     // height() is inaccurate if we're in the middle of a layout of this RenderBox, so use the
1005     // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint
1006     // anyway if its size does change.
1007     LayoutRect clipRect(LayoutPoint(), cachedSizeForOverflowClip());
1008     paintRect = intersection(paintRect, clipRect);
1009 }
1010 
computeIntrinsicLogicalWidths(LayoutUnit & minLogicalWidth,LayoutUnit & maxLogicalWidth) const1011 void RenderBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
1012 {
1013     minLogicalWidth = minPreferredLogicalWidth() - borderAndPaddingLogicalWidth();
1014     maxLogicalWidth = maxPreferredLogicalWidth() - borderAndPaddingLogicalWidth();
1015 }
1016 
minPreferredLogicalWidth() const1017 LayoutUnit RenderBox::minPreferredLogicalWidth() const
1018 {
1019     if (preferredLogicalWidthsDirty()) {
1020 #ifndef NDEBUG
1021         SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<RenderBox*>(this));
1022 #endif
1023         const_cast<RenderBox*>(this)->computePreferredLogicalWidths();
1024     }
1025 
1026     return m_minPreferredLogicalWidth;
1027 }
1028 
maxPreferredLogicalWidth() const1029 LayoutUnit RenderBox::maxPreferredLogicalWidth() const
1030 {
1031     if (preferredLogicalWidthsDirty()) {
1032 #ifndef NDEBUG
1033         SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<RenderBox*>(this));
1034 #endif
1035         const_cast<RenderBox*>(this)->computePreferredLogicalWidths();
1036     }
1037 
1038     return m_maxPreferredLogicalWidth;
1039 }
1040 
hasOverrideHeight() const1041 bool RenderBox::hasOverrideHeight() const
1042 {
1043     return gOverrideHeightMap && gOverrideHeightMap->contains(this);
1044 }
1045 
hasOverrideWidth() const1046 bool RenderBox::hasOverrideWidth() const
1047 {
1048     return gOverrideWidthMap && gOverrideWidthMap->contains(this);
1049 }
1050 
setOverrideLogicalContentHeight(LayoutUnit height)1051 void RenderBox::setOverrideLogicalContentHeight(LayoutUnit height)
1052 {
1053     if (!gOverrideHeightMap)
1054         gOverrideHeightMap = new OverrideSizeMap();
1055     gOverrideHeightMap->set(this, height);
1056 }
1057 
setOverrideLogicalContentWidth(LayoutUnit width)1058 void RenderBox::setOverrideLogicalContentWidth(LayoutUnit width)
1059 {
1060     if (!gOverrideWidthMap)
1061         gOverrideWidthMap = new OverrideSizeMap();
1062     gOverrideWidthMap->set(this, width);
1063 }
1064 
clearOverrideLogicalContentHeight()1065 void RenderBox::clearOverrideLogicalContentHeight()
1066 {
1067     if (gOverrideHeightMap)
1068         gOverrideHeightMap->remove(this);
1069 }
1070 
clearOverrideLogicalContentWidth()1071 void RenderBox::clearOverrideLogicalContentWidth()
1072 {
1073     if (gOverrideWidthMap)
1074         gOverrideWidthMap->remove(this);
1075 }
1076 
clearOverrideSize()1077 void RenderBox::clearOverrideSize()
1078 {
1079     clearOverrideLogicalContentHeight();
1080     clearOverrideLogicalContentWidth();
1081 }
1082 
overrideLogicalContentWidth() const1083 LayoutUnit RenderBox::overrideLogicalContentWidth() const
1084 {
1085     ASSERT(hasOverrideWidth());
1086     return gOverrideWidthMap->get(this);
1087 }
1088 
overrideLogicalContentHeight() const1089 LayoutUnit RenderBox::overrideLogicalContentHeight() const
1090 {
1091     ASSERT(hasOverrideHeight());
1092     return gOverrideHeightMap->get(this);
1093 }
1094 
overrideContainingBlockContentLogicalWidth() const1095 LayoutUnit RenderBox::overrideContainingBlockContentLogicalWidth() const
1096 {
1097     ASSERT(hasOverrideContainingBlockLogicalWidth());
1098     return gOverrideContainingBlockLogicalWidthMap->get(this);
1099 }
1100 
overrideContainingBlockContentLogicalHeight() const1101 LayoutUnit RenderBox::overrideContainingBlockContentLogicalHeight() const
1102 {
1103     ASSERT(hasOverrideContainingBlockLogicalHeight());
1104     return gOverrideContainingBlockLogicalHeightMap->get(this);
1105 }
1106 
hasOverrideContainingBlockLogicalWidth() const1107 bool RenderBox::hasOverrideContainingBlockLogicalWidth() const
1108 {
1109     return gOverrideContainingBlockLogicalWidthMap && gOverrideContainingBlockLogicalWidthMap->contains(this);
1110 }
1111 
hasOverrideContainingBlockLogicalHeight() const1112 bool RenderBox::hasOverrideContainingBlockLogicalHeight() const
1113 {
1114     return gOverrideContainingBlockLogicalHeightMap && gOverrideContainingBlockLogicalHeightMap->contains(this);
1115 }
1116 
setOverrideContainingBlockContentLogicalWidth(LayoutUnit logicalWidth)1117 void RenderBox::setOverrideContainingBlockContentLogicalWidth(LayoutUnit logicalWidth)
1118 {
1119     if (!gOverrideContainingBlockLogicalWidthMap)
1120         gOverrideContainingBlockLogicalWidthMap = new OverrideSizeMap;
1121     gOverrideContainingBlockLogicalWidthMap->set(this, logicalWidth);
1122 }
1123 
setOverrideContainingBlockContentLogicalHeight(LayoutUnit logicalHeight)1124 void RenderBox::setOverrideContainingBlockContentLogicalHeight(LayoutUnit logicalHeight)
1125 {
1126     if (!gOverrideContainingBlockLogicalHeightMap)
1127         gOverrideContainingBlockLogicalHeightMap = new OverrideSizeMap;
1128     gOverrideContainingBlockLogicalHeightMap->set(this, logicalHeight);
1129 }
1130 
clearContainingBlockOverrideSize()1131 void RenderBox::clearContainingBlockOverrideSize()
1132 {
1133     if (gOverrideContainingBlockLogicalWidthMap)
1134         gOverrideContainingBlockLogicalWidthMap->remove(this);
1135     clearOverrideContainingBlockContentLogicalHeight();
1136 }
1137 
clearOverrideContainingBlockContentLogicalHeight()1138 void RenderBox::clearOverrideContainingBlockContentLogicalHeight()
1139 {
1140     if (gOverrideContainingBlockLogicalHeightMap)
1141         gOverrideContainingBlockLogicalHeightMap->remove(this);
1142 }
1143 
adjustBorderBoxLogicalWidthForBoxSizing(LayoutUnit width) const1144 LayoutUnit RenderBox::adjustBorderBoxLogicalWidthForBoxSizing(LayoutUnit width) const
1145 {
1146     LayoutUnit bordersPlusPadding = borderAndPaddingLogicalWidth();
1147     if (style()->boxSizing() == CONTENT_BOX)
1148         return width + bordersPlusPadding;
1149     return max(width, bordersPlusPadding);
1150 }
1151 
adjustBorderBoxLogicalHeightForBoxSizing(LayoutUnit height) const1152 LayoutUnit RenderBox::adjustBorderBoxLogicalHeightForBoxSizing(LayoutUnit height) const
1153 {
1154     LayoutUnit bordersPlusPadding = borderAndPaddingLogicalHeight();
1155     if (style()->boxSizing() == CONTENT_BOX)
1156         return height + bordersPlusPadding;
1157     return max(height, bordersPlusPadding);
1158 }
1159 
adjustContentBoxLogicalWidthForBoxSizing(LayoutUnit width) const1160 LayoutUnit RenderBox::adjustContentBoxLogicalWidthForBoxSizing(LayoutUnit width) const
1161 {
1162     if (style()->boxSizing() == BORDER_BOX)
1163         width -= borderAndPaddingLogicalWidth();
1164     return max<LayoutUnit>(0, width);
1165 }
1166 
adjustContentBoxLogicalHeightForBoxSizing(LayoutUnit height) const1167 LayoutUnit RenderBox::adjustContentBoxLogicalHeightForBoxSizing(LayoutUnit height) const
1168 {
1169     if (style()->boxSizing() == BORDER_BOX)
1170         height -= borderAndPaddingLogicalHeight();
1171     return max<LayoutUnit>(0, height);
1172 }
1173 
1174 // Hit Testing
nodeAtPoint(const HitTestRequest & request,HitTestResult & result,const HitTestLocation & locationInContainer,const LayoutPoint & accumulatedOffset,HitTestAction action)1175 bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
1176 {
1177     LayoutPoint adjustedLocation = accumulatedOffset + location();
1178 
1179     // Check kids first.
1180     for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
1181         if (!child->hasLayer() && child->nodeAtPoint(request, result, locationInContainer, adjustedLocation, action)) {
1182             updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation));
1183             return true;
1184         }
1185     }
1186 
1187     // Check our bounds next. For this purpose always assume that we can only be hit in the
1188     // foreground phase (which is true for replaced elements like images).
1189     LayoutRect boundsRect = borderBoxRectInRegion(locationInContainer.region());
1190     boundsRect.moveBy(adjustedLocation);
1191     if (visibleToHitTestRequest(request) && action == HitTestForeground && locationInContainer.intersects(boundsRect)) {
1192         updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation));
1193         if (!result.addNodeToRectBasedTestResult(node(), request, locationInContainer, boundsRect))
1194             return true;
1195     }
1196 
1197     return false;
1198 }
1199 
1200 // --------------------- painting stuff -------------------------------
1201 
paint(PaintInfo & paintInfo,const LayoutPoint & paintOffset)1202 void RenderBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1203 {
1204     LayoutPoint adjustedPaintOffset = paintOffset + location();
1205     // default implementation. Just pass paint through to the children
1206     PaintInfo childInfo(paintInfo);
1207     childInfo.updatePaintingRootForChildren(this);
1208     for (RenderObject* child = firstChild(); child; child = child->nextSibling())
1209         child->paint(childInfo, adjustedPaintOffset);
1210 }
1211 
paintRootBoxFillLayers(const PaintInfo & paintInfo)1212 void RenderBox::paintRootBoxFillLayers(const PaintInfo& paintInfo)
1213 {
1214     if (paintInfo.skipRootBackground())
1215         return;
1216 
1217     RenderObject* rootBackgroundRenderer = rendererForRootBackground();
1218 
1219     const FillLayer* bgLayer = rootBackgroundRenderer->style()->backgroundLayers();
1220     Color bgColor = rootBackgroundRenderer->resolveColor(CSSPropertyBackgroundColor);
1221 
1222     paintFillLayers(paintInfo, bgColor, bgLayer, view()->backgroundRect(this), BackgroundBleedNone, CompositeSourceOver, rootBackgroundRenderer);
1223 }
1224 
determineBackgroundBleedAvoidance(GraphicsContext * context) const1225 BackgroundBleedAvoidance RenderBox::determineBackgroundBleedAvoidance(GraphicsContext* context) const
1226 {
1227     if (context->paintingDisabled())
1228         return BackgroundBleedNone;
1229 
1230     const RenderStyle* style = this->style();
1231 
1232     if (!style->hasBackground() || !style->hasBorder() || !style->hasBorderRadius() || borderImageIsLoadedAndCanBeRendered())
1233         return BackgroundBleedNone;
1234 
1235     AffineTransform ctm = context->getCTM();
1236     FloatSize contextScaling(static_cast<float>(ctm.xScale()), static_cast<float>(ctm.yScale()));
1237 
1238     // Because RoundedRect uses IntRect internally the inset applied by the
1239     // BackgroundBleedShrinkBackground strategy cannot be less than one integer
1240     // layout coordinate, even with subpixel layout enabled. To take that into
1241     // account, we clamp the contextScaling to 1.0 for the following test so
1242     // that borderObscuresBackgroundEdge can only return true if the border
1243     // widths are greater than 2 in both layout coordinates and screen
1244     // coordinates.
1245     // This precaution will become obsolete if RoundedRect is ever promoted to
1246     // a sub-pixel representation.
1247     if (contextScaling.width() > 1)
1248         contextScaling.setWidth(1);
1249     if (contextScaling.height() > 1)
1250         contextScaling.setHeight(1);
1251 
1252     if (borderObscuresBackgroundEdge(contextScaling))
1253         return BackgroundBleedShrinkBackground;
1254     if (!style->hasAppearance() && borderObscuresBackground() && backgroundHasOpaqueTopLayer())
1255         return BackgroundBleedBackgroundOverBorder;
1256 
1257     return BackgroundBleedUseTransparencyLayer;
1258 }
1259 
paintBoxDecorations(PaintInfo & paintInfo,const LayoutPoint & paintOffset)1260 void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1261 {
1262     if (!paintInfo.shouldPaintWithinRoot(this))
1263         return;
1264 
1265     LayoutRect paintRect = borderBoxRectInRegion(paintInfo.renderRegion);
1266     paintRect.moveBy(paintOffset);
1267     paintBoxDecorationsWithRect(paintInfo, paintOffset, paintRect);
1268 }
1269 
paintBoxDecorationsWithRect(PaintInfo & paintInfo,const LayoutPoint & paintOffset,const LayoutRect & paintRect)1270 void RenderBox::paintBoxDecorationsWithRect(PaintInfo& paintInfo, const LayoutPoint& paintOffset, const LayoutRect& paintRect)
1271 {
1272     BackgroundBleedAvoidance bleedAvoidance = determineBackgroundBleedAvoidance(paintInfo.context);
1273 
1274     // FIXME: Should eventually give the theme control over whether the box shadow should paint, since controls could have
1275     // custom shadows of their own.
1276     if (!boxShadowShouldBeAppliedToBackground(bleedAvoidance))
1277         paintBoxShadow(paintInfo, paintRect, style(), Normal);
1278 
1279     GraphicsContextStateSaver stateSaver(*paintInfo.context, false);
1280     if (bleedAvoidance == BackgroundBleedUseTransparencyLayer) {
1281         // To avoid the background color bleeding out behind the border, we'll render background and border
1282         // into a transparency layer, and then clip that in one go (which requires setting up the clip before
1283         // beginning the layer).
1284         RoundedRect border = style()->getRoundedBorderFor(paintRect, view());
1285         stateSaver.save();
1286         paintInfo.context->clipRoundedRect(border);
1287         paintInfo.context->beginTransparencyLayer(1);
1288     }
1289 
1290     paintBackgroundWithBorderAndBoxShadow(paintInfo, paintRect, bleedAvoidance);
1291 
1292     if (bleedAvoidance == BackgroundBleedUseTransparencyLayer)
1293         paintInfo.context->endLayer();
1294 }
1295 
paintBackgroundWithBorderAndBoxShadow(PaintInfo & paintInfo,const LayoutRect & paintRect,BackgroundBleedAvoidance bleedAvoidance)1296 void RenderBox::paintBackgroundWithBorderAndBoxShadow(PaintInfo& paintInfo, const LayoutRect& paintRect, BackgroundBleedAvoidance bleedAvoidance)
1297 {
1298     // If we have a native theme appearance, paint that before painting our background.
1299     // The theme will tell us whether or not we should also paint the CSS background.
1300     IntRect snappedPaintRect(pixelSnappedIntRect(paintRect));
1301     bool themePainted = style()->hasAppearance() && !RenderTheme::theme().paint(this, paintInfo, snappedPaintRect);
1302     if (!themePainted) {
1303         if (bleedAvoidance == BackgroundBleedBackgroundOverBorder)
1304             paintBorder(paintInfo, paintRect, style(), bleedAvoidance);
1305 
1306         paintBackground(paintInfo, paintRect, bleedAvoidance);
1307 
1308         if (style()->hasAppearance())
1309             RenderTheme::theme().paintDecorations(this, paintInfo, snappedPaintRect);
1310     }
1311     paintBoxShadow(paintInfo, paintRect, style(), Inset);
1312 
1313     // The theme will tell us whether or not we should also paint the CSS border.
1314     if (bleedAvoidance != BackgroundBleedBackgroundOverBorder && (!style()->hasAppearance() || (!themePainted && RenderTheme::theme().paintBorderOnly(this, paintInfo, snappedPaintRect))) && style()->hasBorder() && !(isTable() && toRenderTable(this)->collapseBorders()))
1315         paintBorder(paintInfo, paintRect, style(), bleedAvoidance);
1316 }
1317 
paintBackground(const PaintInfo & paintInfo,const LayoutRect & paintRect,BackgroundBleedAvoidance bleedAvoidance)1318 void RenderBox::paintBackground(const PaintInfo& paintInfo, const LayoutRect& paintRect, BackgroundBleedAvoidance bleedAvoidance)
1319 {
1320     if (isRoot()) {
1321         paintRootBoxFillLayers(paintInfo);
1322         return;
1323     }
1324     if (isBody() && skipBodyBackground(this))
1325         return;
1326     if (backgroundIsKnownToBeObscured())
1327         return;
1328     paintFillLayers(paintInfo, resolveColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), paintRect, bleedAvoidance);
1329 }
1330 
backgroundPaintedExtent() const1331 LayoutRect RenderBox::backgroundPaintedExtent() const
1332 {
1333     ASSERT(hasBackground());
1334     LayoutRect backgroundRect = pixelSnappedIntRect(borderBoxRect());
1335 
1336     Color backgroundColor = resolveColor(CSSPropertyBackgroundColor);
1337     if (backgroundColor.isValid() && backgroundColor.alpha())
1338         return backgroundRect;
1339     if (!style()->backgroundLayers()->image() || style()->backgroundLayers()->next())
1340         return backgroundRect;
1341     BackgroundImageGeometry geometry;
1342     const_cast<RenderBox*>(this)->calculateBackgroundImageGeometry(style()->backgroundLayers(), backgroundRect, geometry);
1343     return geometry.destRect();
1344 }
1345 
backgroundIsKnownToBeOpaqueInRect(const LayoutRect & localRect) const1346 bool RenderBox::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const
1347 {
1348     if (isBody() && skipBodyBackground(this))
1349         return false;
1350 
1351     Color backgroundColor = resolveColor(CSSPropertyBackgroundColor);
1352     if (!backgroundColor.isValid() || backgroundColor.hasAlpha())
1353         return false;
1354 
1355     // If the element has appearance, it might be painted by theme.
1356     // We cannot be sure if theme paints the background opaque.
1357     // In this case it is safe to not assume opaqueness.
1358     // FIXME: May be ask theme if it paints opaque.
1359     if (style()->hasAppearance())
1360         return false;
1361     // FIXME: Check the opaqueness of background images.
1362 
1363     // FIXME: Use rounded rect if border radius is present.
1364     if (style()->hasBorderRadius())
1365         return false;
1366     // FIXME: The background color clip is defined by the last layer.
1367     if (style()->backgroundLayers()->next())
1368         return false;
1369     LayoutRect backgroundRect;
1370     switch (style()->backgroundClip()) {
1371     case BorderFillBox:
1372         backgroundRect = borderBoxRect();
1373         break;
1374     case PaddingFillBox:
1375         backgroundRect = paddingBoxRect();
1376         break;
1377     case ContentFillBox:
1378         backgroundRect = contentBoxRect();
1379         break;
1380     default:
1381         break;
1382     }
1383     return backgroundRect.contains(localRect);
1384 }
1385 
isCandidateForOpaquenessTest(RenderBox * childBox)1386 static bool isCandidateForOpaquenessTest(RenderBox* childBox)
1387 {
1388     RenderStyle* childStyle = childBox->style();
1389     if (childStyle->position() != StaticPosition && childBox->containingBlock() != childBox->parent())
1390         return false;
1391     if (childStyle->visibility() != VISIBLE || childStyle->shapeOutside())
1392         return false;
1393     if (!childBox->width() || !childBox->height())
1394         return false;
1395     if (RenderLayer* childLayer = childBox->layer()) {
1396         // FIXME: perhaps this could be less conservative?
1397         if (childLayer->compositingState() != NotComposited)
1398             return false;
1399         // FIXME: Deal with z-index.
1400         if (!childStyle->hasAutoZIndex())
1401             return false;
1402         if (childLayer->hasTransform() || childLayer->isTransparent() || childLayer->hasFilter())
1403             return false;
1404         if (childBox->hasOverflowClip() && childStyle->hasBorderRadius())
1405             return false;
1406     }
1407     return true;
1408 }
1409 
foregroundIsKnownToBeOpaqueInRect(const LayoutRect & localRect,unsigned maxDepthToTest) const1410 bool RenderBox::foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, unsigned maxDepthToTest) const
1411 {
1412     if (!maxDepthToTest)
1413         return false;
1414     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
1415         if (!child->isBox())
1416             continue;
1417         RenderBox* childBox = toRenderBox(child);
1418         if (!isCandidateForOpaquenessTest(childBox))
1419             continue;
1420         LayoutPoint childLocation = childBox->location();
1421         if (childBox->isRelPositioned())
1422             childLocation.move(childBox->relativePositionOffset());
1423         LayoutRect childLocalRect = localRect;
1424         childLocalRect.moveBy(-childLocation);
1425         if (childLocalRect.y() < 0 || childLocalRect.x() < 0) {
1426             // If there is unobscured area above/left of a static positioned box then the rect is probably not covered.
1427             if (childBox->style()->position() == StaticPosition)
1428                 return false;
1429             continue;
1430         }
1431         if (childLocalRect.maxY() > childBox->height() || childLocalRect.maxX() > childBox->width())
1432             continue;
1433         if (childBox->backgroundIsKnownToBeOpaqueInRect(childLocalRect))
1434             return true;
1435         if (childBox->foregroundIsKnownToBeOpaqueInRect(childLocalRect, maxDepthToTest - 1))
1436             return true;
1437     }
1438     return false;
1439 }
1440 
computeBackgroundIsKnownToBeObscured()1441 bool RenderBox::computeBackgroundIsKnownToBeObscured()
1442 {
1443     // Test to see if the children trivially obscure the background.
1444     // FIXME: This test can be much more comprehensive.
1445     if (!hasBackground())
1446         return false;
1447     // Table and root background painting is special.
1448     if (isTable() || isRoot())
1449         return false;
1450     // FIXME: box-shadow is painted while background painting.
1451     if (style()->boxShadow())
1452         return false;
1453     LayoutRect backgroundRect = backgroundPaintedExtent();
1454     return foregroundIsKnownToBeOpaqueInRect(backgroundRect, backgroundObscurationTestMaxDepth);
1455 }
1456 
backgroundHasOpaqueTopLayer() const1457 bool RenderBox::backgroundHasOpaqueTopLayer() const
1458 {
1459     const FillLayer* fillLayer = style()->backgroundLayers();
1460     if (!fillLayer || fillLayer->clip() != BorderFillBox)
1461         return false;
1462 
1463     // Clipped with local scrolling
1464     if (hasOverflowClip() && fillLayer->attachment() == LocalBackgroundAttachment)
1465         return false;
1466 
1467     if (fillLayer->hasOpaqueImage(this) && fillLayer->hasRepeatXY() && fillLayer->image()->canRender(this, style()->effectiveZoom()))
1468         return true;
1469 
1470     // If there is only one layer and no image, check whether the background color is opaque
1471     if (!fillLayer->next() && !fillLayer->hasImage()) {
1472         Color bgColor = resolveColor(CSSPropertyBackgroundColor);
1473         if (bgColor.isValid() && bgColor.alpha() == 255)
1474             return true;
1475     }
1476 
1477     return false;
1478 }
1479 
paintMask(PaintInfo & paintInfo,const LayoutPoint & paintOffset)1480 void RenderBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1481 {
1482     if (!paintInfo.shouldPaintWithinRoot(this) || style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask || paintInfo.context->paintingDisabled())
1483         return;
1484 
1485     LayoutRect paintRect = LayoutRect(paintOffset, size());
1486     paintMaskImages(paintInfo, paintRect);
1487 }
1488 
paintClippingMask(PaintInfo & paintInfo,const LayoutPoint & paintOffset)1489 void RenderBox::paintClippingMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1490 {
1491     if (!paintInfo.shouldPaintWithinRoot(this) || style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseClippingMask || paintInfo.context->paintingDisabled())
1492         return;
1493 
1494     if (!layer() || layer()->compositingState() != PaintsIntoOwnBacking)
1495         return;
1496 
1497     // We should never have this state in this function. A layer with a mask
1498     // should have always created its own backing if it became composited.
1499     ASSERT(layer()->compositingState() != HasOwnBackingButPaintsIntoAncestor);
1500 
1501     LayoutRect paintRect = LayoutRect(paintOffset, size());
1502     paintInfo.context->fillRect(pixelSnappedIntRect(paintRect), Color::black);
1503 }
1504 
paintMaskImages(const PaintInfo & paintInfo,const LayoutRect & paintRect)1505 void RenderBox::paintMaskImages(const PaintInfo& paintInfo, const LayoutRect& paintRect)
1506 {
1507     // Figure out if we need to push a transparency layer to render our mask.
1508     bool pushTransparencyLayer = false;
1509     bool compositedMask = hasLayer() && layer()->hasCompositedMask();
1510     bool flattenCompositingLayers = view()->frameView() && view()->frameView()->paintBehavior() & PaintBehaviorFlattenCompositingLayers;
1511     CompositeOperator compositeOp = CompositeSourceOver;
1512 
1513     bool allMaskImagesLoaded = true;
1514 
1515     if (!compositedMask || flattenCompositingLayers) {
1516         pushTransparencyLayer = true;
1517         StyleImage* maskBoxImage = style()->maskBoxImage().image();
1518         const FillLayer* maskLayers = style()->maskLayers();
1519 
1520         // Don't render a masked element until all the mask images have loaded, to prevent a flash of unmasked content.
1521         if (maskBoxImage)
1522             allMaskImagesLoaded &= maskBoxImage->isLoaded();
1523 
1524         if (maskLayers)
1525             allMaskImagesLoaded &= maskLayers->imagesAreLoaded();
1526 
1527         paintInfo.context->setCompositeOperation(CompositeDestinationIn);
1528         paintInfo.context->beginTransparencyLayer(1);
1529         compositeOp = CompositeSourceOver;
1530     }
1531 
1532     if (allMaskImagesLoaded) {
1533         paintFillLayers(paintInfo, Color(), style()->maskLayers(), paintRect, BackgroundBleedNone, compositeOp);
1534         paintNinePieceImage(paintInfo.context, paintRect, style(), style()->maskBoxImage(), compositeOp);
1535     }
1536 
1537     if (pushTransparencyLayer)
1538         paintInfo.context->endLayer();
1539 }
1540 
maskClipRect()1541 LayoutRect RenderBox::maskClipRect()
1542 {
1543     const NinePieceImage& maskBoxImage = style()->maskBoxImage();
1544     if (maskBoxImage.image()) {
1545         LayoutRect borderImageRect = borderBoxRect();
1546 
1547         // Apply outsets to the border box.
1548         borderImageRect.expand(style()->maskBoxImageOutsets());
1549         return borderImageRect;
1550     }
1551 
1552     LayoutRect result;
1553     LayoutRect borderBox = borderBoxRect();
1554     for (const FillLayer* maskLayer = style()->maskLayers(); maskLayer; maskLayer = maskLayer->next()) {
1555         if (maskLayer->image()) {
1556             BackgroundImageGeometry geometry;
1557             calculateBackgroundImageGeometry(maskLayer, borderBox, geometry);
1558             result.unite(geometry.destRect());
1559         }
1560     }
1561     return result;
1562 }
1563 
paintFillLayers(const PaintInfo & paintInfo,const Color & c,const FillLayer * fillLayer,const LayoutRect & rect,BackgroundBleedAvoidance bleedAvoidance,CompositeOperator op,RenderObject * backgroundObject)1564 void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, const LayoutRect& rect,
1565     BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderObject* backgroundObject)
1566 {
1567     Vector<const FillLayer*, 8> layers;
1568     const FillLayer* curLayer = fillLayer;
1569     bool shouldDrawBackgroundInSeparateBuffer = false;
1570     while (curLayer) {
1571         layers.append(curLayer);
1572         // Stop traversal when an opaque layer is encountered.
1573         // FIXME : It would be possible for the following occlusion culling test to be more aggressive
1574         // on layers with no repeat by testing whether the image covers the layout rect.
1575         // Testing that here would imply duplicating a lot of calculations that are currently done in
1576         // RenderBoxModelObject::paintFillLayerExtended. A more efficient solution might be to move
1577         // the layer recursion into paintFillLayerExtended, or to compute the layer geometry here
1578         // and pass it down.
1579 
1580         if (!shouldDrawBackgroundInSeparateBuffer && curLayer->blendMode() != blink::WebBlendModeNormal)
1581             shouldDrawBackgroundInSeparateBuffer = true;
1582 
1583         // The clipOccludesNextLayers condition must be evaluated first to avoid short-circuiting.
1584         if (curLayer->clipOccludesNextLayers(curLayer == fillLayer) && curLayer->hasOpaqueImage(this) && curLayer->image()->canRender(this, style()->effectiveZoom()) && curLayer->hasRepeatXY() && curLayer->blendMode() == blink::WebBlendModeNormal && !boxShadowShouldBeAppliedToBackground(bleedAvoidance))
1585             break;
1586         curLayer = curLayer->next();
1587     }
1588 
1589     GraphicsContext* context = paintInfo.context;
1590     if (!context)
1591         shouldDrawBackgroundInSeparateBuffer = false;
1592     if (shouldDrawBackgroundInSeparateBuffer)
1593         context->beginTransparencyLayer(1);
1594 
1595     Vector<const FillLayer*>::const_reverse_iterator topLayer = layers.rend();
1596     for (Vector<const FillLayer*>::const_reverse_iterator it = layers.rbegin(); it != topLayer; ++it)
1597         paintFillLayer(paintInfo, c, *it, rect, bleedAvoidance, op, backgroundObject);
1598 
1599     if (shouldDrawBackgroundInSeparateBuffer)
1600         context->endLayer();
1601 }
1602 
paintFillLayer(const PaintInfo & paintInfo,const Color & c,const FillLayer * fillLayer,const LayoutRect & rect,BackgroundBleedAvoidance bleedAvoidance,CompositeOperator op,RenderObject * backgroundObject)1603 void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, const LayoutRect& rect,
1604     BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderObject* backgroundObject)
1605 {
1606     paintFillLayerExtended(paintInfo, c, fillLayer, rect, bleedAvoidance, 0, LayoutSize(), op, backgroundObject);
1607 }
1608 
layersUseImage(WrappedImagePtr image,const FillLayer * layers)1609 static bool layersUseImage(WrappedImagePtr image, const FillLayer* layers)
1610 {
1611     for (const FillLayer* curLayer = layers; curLayer; curLayer = curLayer->next()) {
1612         if (curLayer->image() && image == curLayer->image()->data())
1613             return true;
1614     }
1615 
1616     return false;
1617 }
1618 
imageChanged(WrappedImagePtr image,const IntRect *)1619 void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*)
1620 {
1621     if (!parent())
1622         return;
1623 
1624     if ((style()->borderImage().image() && style()->borderImage().image()->data() == image) ||
1625         (style()->maskBoxImage().image() && style()->maskBoxImage().image()->data() == image)) {
1626         repaint();
1627         return;
1628     }
1629 
1630     bool didFullRepaint = repaintLayerRectsForImage(image, style()->backgroundLayers(), true);
1631     if (!didFullRepaint)
1632         repaintLayerRectsForImage(image, style()->maskLayers(), false);
1633 
1634 
1635     if (hasLayer() && layer()->hasCompositedMask() && layersUseImage(image, style()->maskLayers()))
1636         layer()->contentChanged(MaskImageChanged);
1637 }
1638 
repaintLayerRectsForImage(WrappedImagePtr image,const FillLayer * layers,bool drawingBackground)1639 bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer* layers, bool drawingBackground)
1640 {
1641     LayoutRect rendererRect;
1642     RenderBox* layerRenderer = 0;
1643 
1644     for (const FillLayer* curLayer = layers; curLayer; curLayer = curLayer->next()) {
1645         if (curLayer->image() && image == curLayer->image()->data() && curLayer->image()->canRender(this, style()->effectiveZoom())) {
1646             // Now that we know this image is being used, compute the renderer and the rect
1647             // if we haven't already
1648             if (!layerRenderer) {
1649                 bool drawingRootBackground = drawingBackground && (isRoot() || (isBody() && !document().documentElement()->renderer()->hasBackground()));
1650                 if (drawingRootBackground) {
1651                     layerRenderer = view();
1652 
1653                     LayoutUnit rw;
1654                     LayoutUnit rh;
1655 
1656                     if (FrameView* frameView = toRenderView(layerRenderer)->frameView()) {
1657                         rw = frameView->contentsWidth();
1658                         rh = frameView->contentsHeight();
1659                     } else {
1660                         rw = layerRenderer->width();
1661                         rh = layerRenderer->height();
1662                     }
1663                     rendererRect = LayoutRect(-layerRenderer->marginLeft(),
1664                         -layerRenderer->marginTop(),
1665                         max(layerRenderer->width() + layerRenderer->marginWidth() + layerRenderer->borderLeft() + layerRenderer->borderRight(), rw),
1666                         max(layerRenderer->height() + layerRenderer->marginHeight() + layerRenderer->borderTop() + layerRenderer->borderBottom(), rh));
1667                 } else {
1668                     layerRenderer = this;
1669                     rendererRect = borderBoxRect();
1670                 }
1671             }
1672 
1673             BackgroundImageGeometry geometry;
1674             layerRenderer->calculateBackgroundImageGeometry(curLayer, rendererRect, geometry);
1675             layerRenderer->repaintRectangle(geometry.destRect());
1676             if (geometry.destRect() == rendererRect)
1677                 return true;
1678         }
1679     }
1680     return false;
1681 }
1682 
pushContentsClip(PaintInfo & paintInfo,const LayoutPoint & accumulatedOffset,ContentsClipBehavior contentsClipBehavior)1683 bool RenderBox::pushContentsClip(PaintInfo& paintInfo, const LayoutPoint& accumulatedOffset, ContentsClipBehavior contentsClipBehavior)
1684 {
1685     if (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == PaintPhaseSelfOutline || paintInfo.phase == PaintPhaseMask)
1686         return false;
1687 
1688     bool isControlClip = hasControlClip();
1689     bool isOverflowClip = hasOverflowClip() && !layer()->isSelfPaintingLayer();
1690 
1691     if (!isControlClip && !isOverflowClip)
1692         return false;
1693 
1694     LayoutRect clipRect = isControlClip ? controlClipRect(accumulatedOffset) : overflowClipRect(accumulatedOffset, paintInfo.renderRegion);
1695     RoundedRect clipRoundedRect(0, 0, 0, 0);
1696     bool hasBorderRadius = style()->hasBorderRadius();
1697     if (hasBorderRadius)
1698         clipRoundedRect = style()->getRoundedInnerBorderFor(LayoutRect(accumulatedOffset, size()));
1699 
1700     if (contentsClipBehavior == SkipContentsClipIfPossible) {
1701         LayoutRect contentsVisualOverflow = contentsVisualOverflowRect();
1702         if (contentsVisualOverflow.isEmpty())
1703             return false;
1704 
1705         // FIXME: Get rid of this slop from here and elsewhere.
1706         // Instead, properly include the outline in visual overflow.
1707         if (RenderView* view = this->view())
1708             contentsVisualOverflow.inflate(view->maximalOutlineSize());
1709 
1710         LayoutRect conservativeClipRect = clipRect;
1711         if (hasBorderRadius)
1712             conservativeClipRect.intersect(clipRoundedRect.radiusCenterRect());
1713         conservativeClipRect.moveBy(-accumulatedOffset);
1714         if (hasLayer())
1715             conservativeClipRect.move(scrolledContentOffset());
1716         if (conservativeClipRect.contains(contentsVisualOverflow))
1717             return false;
1718     }
1719 
1720     if (paintInfo.phase == PaintPhaseOutline)
1721         paintInfo.phase = PaintPhaseChildOutlines;
1722     else if (paintInfo.phase == PaintPhaseChildBlockBackground) {
1723         paintInfo.phase = PaintPhaseBlockBackground;
1724         paintObject(paintInfo, accumulatedOffset);
1725         paintInfo.phase = PaintPhaseChildBlockBackgrounds;
1726     }
1727     paintInfo.context->save();
1728     if (hasBorderRadius)
1729         paintInfo.context->clipRoundedRect(clipRoundedRect);
1730     paintInfo.context->clip(pixelSnappedIntRect(clipRect));
1731     return true;
1732 }
1733 
popContentsClip(PaintInfo & paintInfo,PaintPhase originalPhase,const LayoutPoint & accumulatedOffset)1734 void RenderBox::popContentsClip(PaintInfo& paintInfo, PaintPhase originalPhase, const LayoutPoint& accumulatedOffset)
1735 {
1736     ASSERT(hasControlClip() || (hasOverflowClip() && !layer()->isSelfPaintingLayer()));
1737 
1738     paintInfo.context->restore();
1739     if (originalPhase == PaintPhaseOutline) {
1740         paintInfo.phase = PaintPhaseSelfOutline;
1741         paintObject(paintInfo, accumulatedOffset);
1742         paintInfo.phase = originalPhase;
1743     } else if (originalPhase == PaintPhaseChildBlockBackground)
1744         paintInfo.phase = originalPhase;
1745 }
1746 
overflowClipRect(const LayoutPoint & location,RenderRegion * region,OverlayScrollbarSizeRelevancy relevancy)1747 LayoutRect RenderBox::overflowClipRect(const LayoutPoint& location, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy)
1748 {
1749     // FIXME: When overflow-clip (CSS3) is implemented, we'll obtain the property
1750     // here.
1751     LayoutRect clipRect = borderBoxRectInRegion(region);
1752     clipRect.setLocation(location + clipRect.location() + LayoutSize(borderLeft(), borderTop()));
1753     clipRect.setSize(clipRect.size() - LayoutSize(borderLeft() + borderRight(), borderTop() + borderBottom()));
1754 
1755     if (!hasOverflowClip())
1756         return clipRect;
1757 
1758     // Subtract out scrollbars if we have them.
1759     if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
1760         clipRect.move(layer()->scrollableArea()->verticalScrollbarWidth(relevancy), 0);
1761     clipRect.contract(layer()->scrollableArea()->verticalScrollbarWidth(relevancy), layer()->scrollableArea()->horizontalScrollbarHeight(relevancy));
1762 
1763     return clipRect;
1764 }
1765 
clipRect(const LayoutPoint & location,RenderRegion * region)1766 LayoutRect RenderBox::clipRect(const LayoutPoint& location, RenderRegion* region)
1767 {
1768     LayoutRect borderBoxRect = borderBoxRectInRegion(region);
1769     LayoutRect clipRect = LayoutRect(borderBoxRect.location() + location, borderBoxRect.size());
1770     RenderView* renderView = view();
1771 
1772     if (!style()->clipLeft().isAuto()) {
1773         LayoutUnit c = valueForLength(style()->clipLeft(), borderBoxRect.width(), renderView);
1774         clipRect.move(c, 0);
1775         clipRect.contract(c, 0);
1776     }
1777 
1778     // We don't use the region-specific border box's width and height since clip offsets are (stupidly) specified
1779     // from the left and top edges. Therefore it's better to avoid constraining to smaller widths and heights.
1780 
1781     if (!style()->clipRight().isAuto())
1782         clipRect.contract(width() - valueForLength(style()->clipRight(), width(), renderView), 0);
1783 
1784     if (!style()->clipTop().isAuto()) {
1785         LayoutUnit c = valueForLength(style()->clipTop(), borderBoxRect.height(), renderView);
1786         clipRect.move(0, c);
1787         clipRect.contract(0, c);
1788     }
1789 
1790     if (!style()->clipBottom().isAuto())
1791         clipRect.contract(0, height() - valueForLength(style()->clipBottom(), height(), renderView));
1792 
1793     return clipRect;
1794 }
1795 
shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStart,LayoutUnit childMarginEnd,const RenderBlockFlow * cb,RenderRegion * region) const1796 LayoutUnit RenderBox::shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStart, LayoutUnit childMarginEnd, const RenderBlockFlow* cb, RenderRegion* region) const
1797 {
1798     RenderRegion* containingBlockRegion = 0;
1799     LayoutUnit logicalTopPosition = logicalTop();
1800     if (region) {
1801         LayoutUnit offsetFromLogicalTopOfRegion = region ? region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage() : LayoutUnit();
1802         logicalTopPosition = max(logicalTopPosition, logicalTopPosition + offsetFromLogicalTopOfRegion);
1803         containingBlockRegion = cb->clampToStartAndEndRegions(region);
1804     }
1805 
1806     LayoutUnit result = cb->availableLogicalWidthForLineInRegion(logicalTopPosition, false, containingBlockRegion) - childMarginStart - childMarginEnd;
1807 
1808     // We need to see if margins on either the start side or the end side can contain the floats in question. If they can,
1809     // then just using the line width is inaccurate. In the case where a float completely fits, we don't need to use the line
1810     // offset at all, but can instead push all the way to the content edge of the containing block. In the case where the float
1811     // doesn't fit, we can use the line offset, but we need to grow it by the margin to reflect the fact that the margin was
1812     // "consumed" by the float. Negative margins aren't consumed by the float, and so we ignore them.
1813     if (childMarginStart > 0) {
1814         LayoutUnit startContentSide = cb->startOffsetForContent(containingBlockRegion);
1815         LayoutUnit startContentSideWithMargin = startContentSide + childMarginStart;
1816         LayoutUnit startOffset = cb->startOffsetForLineInRegion(logicalTopPosition, false, containingBlockRegion);
1817         if (startOffset > startContentSideWithMargin)
1818             result += childMarginStart;
1819         else
1820             result += startOffset - startContentSide;
1821     }
1822 
1823     if (childMarginEnd > 0) {
1824         LayoutUnit endContentSide = cb->endOffsetForContent(containingBlockRegion);
1825         LayoutUnit endContentSideWithMargin = endContentSide + childMarginEnd;
1826         LayoutUnit endOffset = cb->endOffsetForLineInRegion(logicalTopPosition, false, containingBlockRegion);
1827         if (endOffset > endContentSideWithMargin)
1828             result += childMarginEnd;
1829         else
1830             result += endOffset - endContentSide;
1831     }
1832 
1833     return result;
1834 }
1835 
containingBlockLogicalWidthForContent() const1836 LayoutUnit RenderBox::containingBlockLogicalWidthForContent() const
1837 {
1838     if (hasOverrideContainingBlockLogicalWidth())
1839         return overrideContainingBlockContentLogicalWidth();
1840 
1841     RenderBlock* cb = containingBlock();
1842     return cb->availableLogicalWidth();
1843 }
1844 
containingBlockLogicalHeightForContent(AvailableLogicalHeightType heightType) const1845 LayoutUnit RenderBox::containingBlockLogicalHeightForContent(AvailableLogicalHeightType heightType) const
1846 {
1847     if (hasOverrideContainingBlockLogicalHeight())
1848         return overrideContainingBlockContentLogicalHeight();
1849 
1850     RenderBlock* cb = containingBlock();
1851     return cb->availableLogicalHeight(heightType);
1852 }
1853 
containingBlockLogicalWidthForContentInRegion(RenderRegion * region) const1854 LayoutUnit RenderBox::containingBlockLogicalWidthForContentInRegion(RenderRegion* region) const
1855 {
1856     if (!region)
1857         return containingBlockLogicalWidthForContent();
1858 
1859     RenderBlock* cb = containingBlock();
1860     RenderRegion* containingBlockRegion = cb->clampToStartAndEndRegions(region);
1861     // FIXME: It's unclear if a region's content should use the containing block's override logical width.
1862     // If it should, the following line should call containingBlockLogicalWidthForContent.
1863     LayoutUnit result = cb->availableLogicalWidth();
1864     RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(containingBlockRegion);
1865     if (!boxInfo)
1866         return result;
1867     return max<LayoutUnit>(0, result - (cb->logicalWidth() - boxInfo->logicalWidth()));
1868 }
1869 
containingBlockAvailableLineWidthInRegion(RenderRegion * region) const1870 LayoutUnit RenderBox::containingBlockAvailableLineWidthInRegion(RenderRegion* region) const
1871 {
1872     RenderBlock* cb = containingBlock();
1873     RenderRegion* containingBlockRegion = 0;
1874     LayoutUnit logicalTopPosition = logicalTop();
1875     if (region) {
1876         LayoutUnit offsetFromLogicalTopOfRegion = region ? region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage() : LayoutUnit();
1877         logicalTopPosition = max(logicalTopPosition, logicalTopPosition + offsetFromLogicalTopOfRegion);
1878         containingBlockRegion = cb->clampToStartAndEndRegions(region);
1879     }
1880     return cb->availableLogicalWidthForLineInRegion(logicalTopPosition, false, containingBlockRegion, availableLogicalHeight(IncludeMarginBorderPadding));
1881 }
1882 
perpendicularContainingBlockLogicalHeight() const1883 LayoutUnit RenderBox::perpendicularContainingBlockLogicalHeight() const
1884 {
1885     if (hasOverrideContainingBlockLogicalHeight())
1886         return overrideContainingBlockContentLogicalHeight();
1887 
1888     RenderBlock* cb = containingBlock();
1889     if (cb->hasOverrideHeight())
1890         return cb->overrideLogicalContentHeight();
1891 
1892     RenderStyle* containingBlockStyle = cb->style();
1893     Length logicalHeightLength = containingBlockStyle->logicalHeight();
1894 
1895     // FIXME: For now just support fixed heights.  Eventually should support percentage heights as well.
1896     if (!logicalHeightLength.isFixed()) {
1897         LayoutUnit fillFallbackExtent = containingBlockStyle->isHorizontalWritingMode() ? view()->frameView()->visibleHeight() : view()->frameView()->visibleWidth();
1898         LayoutUnit fillAvailableExtent = containingBlock()->availableLogicalHeight(ExcludeMarginBorderPadding);
1899         return min(fillAvailableExtent, fillFallbackExtent);
1900     }
1901 
1902     // Use the content box logical height as specified by the style.
1903     return cb->adjustContentBoxLogicalHeightForBoxSizing(logicalHeightLength.value());
1904 }
1905 
mapLocalToContainer(const RenderLayerModelObject * repaintContainer,TransformState & transformState,MapCoordinatesFlags mode,bool * wasFixed) const1906 void RenderBox::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const
1907 {
1908     if (repaintContainer == this)
1909         return;
1910 
1911     if (RenderView* v = view()) {
1912         if (v->layoutStateEnabled() && !repaintContainer) {
1913             LayoutState* layoutState = v->layoutState();
1914             LayoutSize offset = layoutState->m_paintOffset + locationOffset();
1915             if (style()->hasInFlowPosition() && layer())
1916                 offset += layer()->offsetForInFlowPosition();
1917             transformState.move(offset);
1918             return;
1919         }
1920     }
1921 
1922     bool containerSkipped;
1923     RenderObject* o = container(repaintContainer, &containerSkipped);
1924     if (!o)
1925         return;
1926 
1927     bool isFixedPos = style()->position() == FixedPosition;
1928     bool hasTransform = hasLayer() && layer()->transform();
1929     // If this box has a transform, it acts as a fixed position container for fixed descendants,
1930     // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
1931     if (hasTransform && !isFixedPos)
1932         mode &= ~IsFixed;
1933     else if (isFixedPos)
1934         mode |= IsFixed;
1935 
1936     if (wasFixed)
1937         *wasFixed = mode & IsFixed;
1938 
1939     LayoutSize containerOffset = offsetFromContainer(o, roundedLayoutPoint(transformState.mappedPoint()));
1940 
1941     bool preserve3D = mode & UseTransforms && (o->style()->preserves3D() || style()->preserves3D());
1942     if (mode & UseTransforms && shouldUseTransformFromContainer(o)) {
1943         TransformationMatrix t;
1944         getTransformFromContainer(o, containerOffset, t);
1945         transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1946     } else
1947         transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1948 
1949     if (containerSkipped) {
1950         // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
1951         // to just subtract the delta between the repaintContainer and o.
1952         LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
1953         transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1954         return;
1955     }
1956 
1957     mode &= ~ApplyContainerFlip;
1958 
1959     o->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed);
1960 }
1961 
mapAbsoluteToLocalPoint(MapCoordinatesFlags mode,TransformState & transformState) const1962 void RenderBox::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState& transformState) const
1963 {
1964     // We don't expect to be called during layout.
1965     ASSERT(!view() || !view()->layoutStateEnabled());
1966 
1967     bool isFixedPos = style()->position() == FixedPosition;
1968     bool hasTransform = hasLayer() && layer()->transform();
1969     if (hasTransform && !isFixedPos) {
1970         // If this box has a transform, it acts as a fixed position container for fixed descendants,
1971         // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
1972         mode &= ~IsFixed;
1973     } else if (isFixedPos)
1974         mode |= IsFixed;
1975 
1976     RenderBoxModelObject::mapAbsoluteToLocalPoint(mode, transformState);
1977 }
1978 
offsetFromContainer(RenderObject * o,const LayoutPoint & point,bool * offsetDependsOnPoint) const1979 LayoutSize RenderBox::offsetFromContainer(RenderObject* o, const LayoutPoint& point, bool* offsetDependsOnPoint) const
1980 {
1981     // A region "has" boxes inside it without being their container.
1982     // FIXME: change container() / containingBlock() to count for boxes being positioned relative to the region, not the
1983     // FlowThread. This requires a separate patch as a simple test with such a change in container() causes 129 out of
1984     // 337 regions tests to fail.
1985     ASSERT(o == container() || o->isRenderRegion());
1986 
1987     LayoutSize offset;
1988     if (isInFlowPositioned())
1989         offset += offsetForInFlowPosition();
1990 
1991     if (!isInline() || isReplaced()) {
1992         if (!style()->hasOutOfFlowPosition() && o->hasColumns()) {
1993             RenderBlock* block = toRenderBlock(o);
1994             LayoutRect columnRect(frameRect());
1995             block->adjustStartEdgeForWritingModeIncludingColumns(columnRect);
1996             offset += toSize(columnRect.location());
1997             LayoutPoint columnPoint = block->flipForWritingModeIncludingColumns(point + offset);
1998             offset = toLayoutSize(block->flipForWritingModeIncludingColumns(toLayoutPoint(offset)));
1999             o->adjustForColumns(offset, columnPoint);
2000             offset = block->flipForWritingMode(offset);
2001 
2002             if (offsetDependsOnPoint)
2003                 *offsetDependsOnPoint = true;
2004         } else
2005             offset += topLeftLocationOffset();
2006     }
2007 
2008     if (o->hasOverflowClip())
2009         offset -= toRenderBox(o)->scrolledContentOffset();
2010 
2011     if (style()->position() == AbsolutePosition && o->isInFlowPositioned() && o->isRenderInline())
2012         offset += toRenderInline(o)->offsetForInFlowPositionedInline(this);
2013 
2014     if (offsetDependsOnPoint)
2015         *offsetDependsOnPoint |= o->isRenderFlowThread();
2016 
2017     return offset;
2018 }
2019 
createInlineBox()2020 InlineBox* RenderBox::createInlineBox()
2021 {
2022     return new InlineBox(this);
2023 }
2024 
dirtyLineBoxes(bool fullLayout)2025 void RenderBox::dirtyLineBoxes(bool fullLayout)
2026 {
2027     if (m_inlineBoxWrapper) {
2028         if (fullLayout) {
2029             m_inlineBoxWrapper->destroy();
2030             m_inlineBoxWrapper = 0;
2031         } else
2032             m_inlineBoxWrapper->dirtyLineBoxes();
2033     }
2034 }
2035 
positionLineBox(InlineBox * box)2036 void RenderBox::positionLineBox(InlineBox* box)
2037 {
2038     if (isOutOfFlowPositioned()) {
2039         // Cache the x position only if we were an INLINE type originally.
2040         bool wasInline = style()->isOriginalDisplayInlineType();
2041         if (wasInline) {
2042             // The value is cached in the xPos of the box.  We only need this value if
2043             // our object was inline originally, since otherwise it would have ended up underneath
2044             // the inlines.
2045             RootInlineBox* root = box->root();
2046             root->block()->setStaticInlinePositionForChild(this, root->lineTopWithLeading(), LayoutUnit::fromFloatRound(box->logicalLeft()));
2047             if (style()->hasStaticInlinePosition(box->isHorizontal()))
2048                 setChildNeedsLayout(MarkOnlyThis); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
2049         } else {
2050             // Our object was a block originally, so we make our normal flow position be
2051             // just below the line box (as though all the inlines that came before us got
2052             // wrapped in an anonymous block, which is what would have happened had we been
2053             // in flow).  This value was cached in the y() of the box.
2054             layer()->setStaticBlockPosition(box->logicalTop());
2055             if (style()->hasStaticBlockPosition(box->isHorizontal()))
2056                 setChildNeedsLayout(MarkOnlyThis); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
2057         }
2058 
2059         // Nuke the box.
2060         box->remove();
2061         box->destroy();
2062     } else if (isReplaced()) {
2063         setLocation(roundedLayoutPoint(box->topLeft()));
2064         setInlineBoxWrapper(box);
2065     }
2066 }
2067 
deleteLineBoxWrapper()2068 void RenderBox::deleteLineBoxWrapper()
2069 {
2070     if (m_inlineBoxWrapper) {
2071         if (!documentBeingDestroyed())
2072             m_inlineBoxWrapper->remove();
2073         m_inlineBoxWrapper->destroy();
2074         m_inlineBoxWrapper = 0;
2075     }
2076 }
2077 
clippedOverflowRectForRepaint(const RenderLayerModelObject * repaintContainer) const2078 LayoutRect RenderBox::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const
2079 {
2080     if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent())
2081         return LayoutRect();
2082 
2083     LayoutRect r = visualOverflowRect();
2084 
2085     RenderView* v = view();
2086     if (v) {
2087         // FIXME: layoutDelta needs to be applied in parts before/after transforms and
2088         // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
2089         r.move(v->layoutDelta());
2090     }
2091 
2092     if (style()) {
2093         // We have to use maximalOutlineSize() because a child might have an outline
2094         // that projects outside of our overflowRect.
2095         if (v) {
2096             ASSERT(style()->outlineSize() <= v->maximalOutlineSize());
2097             r.inflate(v->maximalOutlineSize());
2098         }
2099     }
2100 
2101     computeRectForRepaint(repaintContainer, r);
2102     return r;
2103 }
2104 
computeRectForRepaint(const RenderLayerModelObject * repaintContainer,LayoutRect & rect,bool fixed) const2105 void RenderBox::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const
2106 {
2107     // The rect we compute at each step is shifted by our x/y offset in the parent container's coordinate space.
2108     // Only when we cross a writing mode boundary will we have to possibly flipForWritingMode (to convert into a more appropriate
2109     // offset corner for the enclosing container).  This allows for a fully RL or BT document to repaint
2110     // properly even during layout, since the rect remains flipped all the way until the end.
2111     //
2112     // RenderView::computeRectForRepaint then converts the rect to physical coordinates.  We also convert to
2113     // physical when we hit a repaintContainer boundary.  Therefore the final rect returned is always in the
2114     // physical coordinate space of the repaintContainer.
2115     RenderStyle* styleToUse = style();
2116     if (RenderView* v = view()) {
2117         // LayoutState is only valid for root-relative, non-fixed position repainting
2118         if (v->layoutStateEnabled() && !repaintContainer && styleToUse->position() != FixedPosition) {
2119             LayoutState* layoutState = v->layoutState();
2120 
2121             if (layer() && layer()->transform())
2122                 rect = layer()->transform()->mapRect(pixelSnappedIntRect(rect));
2123 
2124             // We can't trust the bits on RenderObject, because this might be called while re-resolving style.
2125             if (styleToUse->hasInFlowPosition() && layer())
2126                 rect.move(layer()->offsetForInFlowPosition());
2127 
2128             rect.moveBy(location());
2129             rect.move(layoutState->m_paintOffset);
2130             if (layoutState->m_clipped)
2131                 rect.intersect(layoutState->m_clipRect);
2132             return;
2133         }
2134     }
2135 
2136     if (hasReflection())
2137         rect.unite(reflectedRect(rect));
2138 
2139     if (repaintContainer == this) {
2140         if (repaintContainer->style()->isFlippedBlocksWritingMode())
2141             flipForWritingMode(rect);
2142         return;
2143     }
2144 
2145     bool containerSkipped;
2146     RenderObject* o = container(repaintContainer, &containerSkipped);
2147     if (!o)
2148         return;
2149 
2150     if (isWritingModeRoot() && !isOutOfFlowPositioned())
2151         flipForWritingMode(rect);
2152 
2153     LayoutPoint topLeft = rect.location();
2154     topLeft.move(locationOffset());
2155 
2156     EPosition position = styleToUse->position();
2157 
2158     // We are now in our parent container's coordinate space.  Apply our transform to obtain a bounding box
2159     // in the parent's coordinate space that encloses us.
2160     if (hasLayer() && layer()->transform()) {
2161         fixed = position == FixedPosition;
2162         rect = layer()->transform()->mapRect(pixelSnappedIntRect(rect));
2163         topLeft = rect.location();
2164         topLeft.move(locationOffset());
2165     } else if (position == FixedPosition)
2166         fixed = true;
2167 
2168     if (position == AbsolutePosition && o->isInFlowPositioned() && o->isRenderInline()) {
2169         topLeft += toRenderInline(o)->offsetForInFlowPositionedInline(this);
2170     } else if (styleToUse->hasInFlowPosition() && layer()) {
2171         // Apply the relative position offset when invalidating a rectangle.  The layer
2172         // is translated, but the render box isn't, so we need to do this to get the
2173         // right dirty rect.  Since this is called from RenderObject::setStyle, the relative position
2174         // flag on the RenderObject has been cleared, so use the one on the style().
2175         topLeft += layer()->offsetForInFlowPosition();
2176     }
2177 
2178     if (position != AbsolutePosition && position != FixedPosition && o->hasColumns() && o->isRenderBlockFlow()) {
2179         LayoutRect repaintRect(topLeft, rect.size());
2180         toRenderBlock(o)->adjustRectForColumns(repaintRect);
2181         topLeft = repaintRect.location();
2182         rect = repaintRect;
2183     }
2184 
2185     // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
2186     // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
2187     rect.setLocation(topLeft);
2188     if (o->hasOverflowClip()) {
2189         RenderBox* containerBox = toRenderBox(o);
2190         containerBox->applyCachedClipAndScrollOffsetForRepaint(rect);
2191         if (rect.isEmpty())
2192             return;
2193     }
2194 
2195     if (containerSkipped) {
2196         // If the repaintContainer is below o, then we need to map the rect into repaintContainer's coordinates.
2197         LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
2198         rect.move(-containerOffset);
2199         return;
2200     }
2201 
2202     o->computeRectForRepaint(repaintContainer, rect, fixed);
2203 }
2204 
repaintDuringLayoutIfMoved(const LayoutRect & oldRect)2205 void RenderBox::repaintDuringLayoutIfMoved(const LayoutRect& oldRect)
2206 {
2207     if (oldRect.location() != m_frameRect.location()) {
2208         LayoutRect newRect = m_frameRect;
2209         // The child moved.  Invalidate the object's old and new positions.  We have to do this
2210         // since the object may not have gotten a layout.
2211         m_frameRect = oldRect;
2212         repaint();
2213         repaintOverhangingFloats(true);
2214         m_frameRect = newRect;
2215         repaint();
2216         repaintOverhangingFloats(true);
2217     }
2218 }
2219 
repaintOverhangingFloats(bool)2220 void RenderBox::repaintOverhangingFloats(bool)
2221 {
2222 }
2223 
updateLogicalWidth()2224 void RenderBox::updateLogicalWidth()
2225 {
2226     LogicalExtentComputedValues computedValues;
2227     computeLogicalWidthInRegion(computedValues);
2228 
2229     setLogicalWidth(computedValues.m_extent);
2230     setLogicalLeft(computedValues.m_position);
2231     setMarginStart(computedValues.m_margins.m_start);
2232     setMarginEnd(computedValues.m_margins.m_end);
2233 }
2234 
getMaxWidthListMarker(const RenderBox * renderer)2235 static float getMaxWidthListMarker(const RenderBox* renderer)
2236 {
2237 #ifndef NDEBUG
2238     ASSERT(renderer);
2239     Node* parentNode = renderer->generatingNode();
2240     ASSERT(parentNode);
2241     ASSERT(parentNode->hasTagName(olTag) || parentNode->hasTagName(ulTag));
2242     ASSERT(renderer->style()->textAutosizingMultiplier() != 1);
2243 #endif
2244     float maxWidth = 0;
2245     for (RenderObject* child = renderer->firstChild(); child; child = child->nextSibling()) {
2246         if (!child->isListItem())
2247             continue;
2248 
2249         RenderBox* listItem = toRenderBox(child);
2250         for (RenderObject* itemChild = listItem->firstChild(); itemChild; itemChild = itemChild->nextSibling()) {
2251             if (!itemChild->isListMarker())
2252                 continue;
2253             RenderBox* itemMarker = toRenderBox(itemChild);
2254             // FIXME: canDetermineWidthWithoutLayout expects us to use fixedOffsetWidth, which this code
2255             // does not do! This check is likely wrong.
2256             if (!itemMarker->canDetermineWidthWithoutLayout() && itemMarker->needsLayout()) {
2257                 // Make sure to compute the autosized width.
2258                 itemMarker->layout();
2259             }
2260             maxWidth = max<float>(maxWidth, toRenderListMarker(itemMarker)->logicalWidth().toFloat());
2261             break;
2262         }
2263     }
2264     return maxWidth;
2265 }
2266 
computeLogicalWidthInRegion(LogicalExtentComputedValues & computedValues,RenderRegion * region) const2267 void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& computedValues, RenderRegion* region) const
2268 {
2269     computedValues.m_extent = logicalWidth();
2270     computedValues.m_position = logicalLeft();
2271     computedValues.m_margins.m_start = marginStart();
2272     computedValues.m_margins.m_end = marginEnd();
2273 
2274     if (isOutOfFlowPositioned()) {
2275         // FIXME: This calculation is not patched for block-flow yet.
2276         // https://bugs.webkit.org/show_bug.cgi?id=46500
2277         computePositionedLogicalWidth(computedValues, region);
2278         return;
2279     }
2280 
2281     // If layout is limited to a subtree, the subtree root's logical width does not change.
2282     if (node() && view()->frameView() && view()->frameView()->layoutRoot(true) == this)
2283         return;
2284 
2285     // The parent box is flexing us, so it has increased or decreased our
2286     // width.  Use the width from the style context.
2287     // FIXME: Account for block-flow in flexible boxes.
2288     // https://bugs.webkit.org/show_bug.cgi?id=46418
2289     if (hasOverrideWidth() && (style()->borderFit() == BorderFitLines || parent()->isFlexibleBoxIncludingDeprecated())) {
2290         computedValues.m_extent = overrideLogicalContentWidth() + borderAndPaddingLogicalWidth();
2291         return;
2292     }
2293 
2294     // FIXME: Account for block-flow in flexible boxes.
2295     // https://bugs.webkit.org/show_bug.cgi?id=46418
2296     bool inVerticalBox = parent()->isDeprecatedFlexibleBox() && (parent()->style()->boxOrient() == VERTICAL);
2297     bool stretching = (parent()->style()->boxAlign() == BSTRETCH);
2298     bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inVerticalBox || !stretching);
2299 
2300     RenderStyle* styleToUse = style();
2301     Length logicalWidthLength = treatAsReplaced ? Length(computeReplacedLogicalWidth(), Fixed) : styleToUse->logicalWidth();
2302 
2303     RenderBlock* cb = containingBlock();
2304     LayoutUnit containerLogicalWidth = max<LayoutUnit>(0, containingBlockLogicalWidthForContentInRegion(region));
2305     bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode();
2306 
2307     if (isInline() && !isInlineBlockOrInlineTable()) {
2308         // just calculate margins
2309         RenderView* renderView = view();
2310         computedValues.m_margins.m_start = minimumValueForLength(styleToUse->marginStart(), containerLogicalWidth, renderView);
2311         computedValues.m_margins.m_end = minimumValueForLength(styleToUse->marginEnd(), containerLogicalWidth, renderView);
2312         if (treatAsReplaced)
2313             computedValues.m_extent = max<LayoutUnit>(floatValueForLength(logicalWidthLength, 0, 0) + borderAndPaddingLogicalWidth(), minPreferredLogicalWidth());
2314         return;
2315     }
2316 
2317     // Width calculations
2318     if (treatAsReplaced)
2319         computedValues.m_extent = logicalWidthLength.value() + borderAndPaddingLogicalWidth();
2320     else {
2321         LayoutUnit containerWidthInInlineDirection = containerLogicalWidth;
2322         if (hasPerpendicularContainingBlock)
2323             containerWidthInInlineDirection = perpendicularContainingBlockLogicalHeight();
2324         LayoutUnit preferredWidth = computeLogicalWidthInRegionUsing(MainOrPreferredSize, styleToUse->logicalWidth(), containerWidthInInlineDirection, cb, region);
2325         computedValues.m_extent = constrainLogicalWidthInRegionByMinMax(preferredWidth, containerWidthInInlineDirection, cb, region);
2326     }
2327 
2328     // Margin calculations.
2329     if (hasPerpendicularContainingBlock || isFloating() || isInline()) {
2330         RenderView* renderView = view();
2331         computedValues.m_margins.m_start = minimumValueForLength(styleToUse->marginStart(), containerLogicalWidth, renderView);
2332         computedValues.m_margins.m_end = minimumValueForLength(styleToUse->marginEnd(), containerLogicalWidth, renderView);
2333     } else {
2334         LayoutUnit containerLogicalWidthForAutoMargins = containerLogicalWidth;
2335         if (avoidsFloats() && cb->containsFloats())
2336             containerLogicalWidthForAutoMargins = containingBlockAvailableLineWidthInRegion(region);
2337         bool hasInvertedDirection = cb->style()->isLeftToRightDirection() != style()->isLeftToRightDirection();
2338         computeInlineDirectionMargins(cb, containerLogicalWidthForAutoMargins, computedValues.m_extent,
2339             hasInvertedDirection ? computedValues.m_margins.m_end : computedValues.m_margins.m_start,
2340             hasInvertedDirection ? computedValues.m_margins.m_start : computedValues.m_margins.m_end);
2341     }
2342 
2343     if (!hasPerpendicularContainingBlock && containerLogicalWidth && containerLogicalWidth != (computedValues.m_extent + computedValues.m_margins.m_start + computedValues.m_margins.m_end)
2344         && !isFloating() && !isInline() && !cb->isFlexibleBoxIncludingDeprecated() && !cb->isRenderGrid()) {
2345         LayoutUnit newMargin = containerLogicalWidth - computedValues.m_extent - cb->marginStartForChild(this);
2346         bool hasInvertedDirection = cb->style()->isLeftToRightDirection() != style()->isLeftToRightDirection();
2347         if (hasInvertedDirection)
2348             computedValues.m_margins.m_start = newMargin;
2349         else
2350             computedValues.m_margins.m_end = newMargin;
2351     }
2352 
2353     if (styleToUse->textAutosizingMultiplier() != 1 && styleToUse->marginStart().type() == Fixed) {
2354         Node* parentNode = generatingNode();
2355         if (parentNode && (parentNode->hasTagName(olTag) || parentNode->hasTagName(ulTag))) {
2356             // Make sure the markers in a list are properly positioned (i.e. not chopped off) when autosized.
2357             const float adjustedMargin = (1 - 1.0 / styleToUse->textAutosizingMultiplier()) * getMaxWidthListMarker(this);
2358             bool hasInvertedDirection = cb->style()->isLeftToRightDirection() != style()->isLeftToRightDirection();
2359             if (hasInvertedDirection)
2360                 computedValues.m_margins.m_end += adjustedMargin;
2361             else
2362                 computedValues.m_margins.m_start += adjustedMargin;
2363         }
2364     }
2365 }
2366 
fillAvailableMeasure(LayoutUnit availableLogicalWidth) const2367 LayoutUnit RenderBox::fillAvailableMeasure(LayoutUnit availableLogicalWidth) const
2368 {
2369     LayoutUnit marginStart = 0;
2370     LayoutUnit marginEnd = 0;
2371     return fillAvailableMeasure(availableLogicalWidth, marginStart, marginEnd);
2372 }
2373 
fillAvailableMeasure(LayoutUnit availableLogicalWidth,LayoutUnit & marginStart,LayoutUnit & marginEnd) const2374 LayoutUnit RenderBox::fillAvailableMeasure(LayoutUnit availableLogicalWidth, LayoutUnit& marginStart, LayoutUnit& marginEnd) const
2375 {
2376     RenderView* renderView = view();
2377     marginStart = minimumValueForLength(style()->marginStart(), availableLogicalWidth, renderView);
2378     marginEnd = minimumValueForLength(style()->marginEnd(), availableLogicalWidth, renderView);
2379     return availableLogicalWidth - marginStart - marginEnd;
2380 }
2381 
computeIntrinsicLogicalWidthUsing(Length logicalWidthLength,LayoutUnit availableLogicalWidth,LayoutUnit borderAndPadding) const2382 LayoutUnit RenderBox::computeIntrinsicLogicalWidthUsing(Length logicalWidthLength, LayoutUnit availableLogicalWidth, LayoutUnit borderAndPadding) const
2383 {
2384     if (logicalWidthLength.type() == FillAvailable)
2385         return fillAvailableMeasure(availableLogicalWidth);
2386 
2387     LayoutUnit minLogicalWidth = 0;
2388     LayoutUnit maxLogicalWidth = 0;
2389     computeIntrinsicLogicalWidths(minLogicalWidth, maxLogicalWidth);
2390 
2391     if (logicalWidthLength.type() == MinContent)
2392         return minLogicalWidth + borderAndPadding;
2393 
2394     if (logicalWidthLength.type() == MaxContent)
2395         return maxLogicalWidth + borderAndPadding;
2396 
2397     if (logicalWidthLength.type() == FitContent) {
2398         minLogicalWidth += borderAndPadding;
2399         maxLogicalWidth += borderAndPadding;
2400         return max(minLogicalWidth, min(maxLogicalWidth, fillAvailableMeasure(availableLogicalWidth)));
2401     }
2402 
2403     ASSERT_NOT_REACHED();
2404     return 0;
2405 }
2406 
computeLogicalWidthInRegionUsing(SizeType widthType,Length logicalWidth,LayoutUnit availableLogicalWidth,const RenderBlock * cb,RenderRegion * region) const2407 LayoutUnit RenderBox::computeLogicalWidthInRegionUsing(SizeType widthType, Length logicalWidth, LayoutUnit availableLogicalWidth,
2408     const RenderBlock* cb, RenderRegion* region) const
2409 {
2410     if (!logicalWidth.isIntrinsicOrAuto()) {
2411         // FIXME: If the containing block flow is perpendicular to our direction we need to use the available logical height instead.
2412         return adjustBorderBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, availableLogicalWidth, view()));
2413     }
2414 
2415     if (logicalWidth.isIntrinsic())
2416         return computeIntrinsicLogicalWidthUsing(logicalWidth, availableLogicalWidth, borderAndPaddingLogicalWidth());
2417 
2418     LayoutUnit marginStart = 0;
2419     LayoutUnit marginEnd = 0;
2420     LayoutUnit logicalWidthResult = fillAvailableMeasure(availableLogicalWidth, marginStart, marginEnd);
2421 
2422     if (shrinkToAvoidFloats() && cb->containsFloats())
2423         logicalWidthResult = min(logicalWidthResult, shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, toRenderBlockFlow(cb), region));
2424 
2425     if (widthType == MainOrPreferredSize && sizesLogicalWidthToFitContent(widthType))
2426         return max(minPreferredLogicalWidth(), min(maxPreferredLogicalWidth(), logicalWidthResult));
2427     return logicalWidthResult;
2428 }
2429 
columnFlexItemHasStretchAlignment(const RenderObject * flexitem)2430 static bool columnFlexItemHasStretchAlignment(const RenderObject* flexitem)
2431 {
2432     RenderObject* parent = flexitem->parent();
2433     // auto margins mean we don't stretch. Note that this function will only be used for
2434     // widths, so we don't have to check marginBefore/marginAfter.
2435     ASSERT(parent->style()->isColumnFlexDirection());
2436     if (flexitem->style()->marginStart().isAuto() || flexitem->style()->marginEnd().isAuto())
2437         return false;
2438     return flexitem->style()->alignSelf() == AlignStretch || (flexitem->style()->alignSelf() == AlignAuto && parent->style()->alignItems() == AlignStretch);
2439 }
2440 
isStretchingColumnFlexItem(const RenderObject * flexitem)2441 static bool isStretchingColumnFlexItem(const RenderObject* flexitem)
2442 {
2443     RenderObject* parent = flexitem->parent();
2444     if (parent->isDeprecatedFlexibleBox() && parent->style()->boxOrient() == VERTICAL && parent->style()->boxAlign() == BSTRETCH)
2445         return true;
2446 
2447     // We don't stretch multiline flexboxes because they need to apply line spacing (align-content) first.
2448     if (parent->isFlexibleBox() && parent->style()->flexWrap() == FlexNoWrap && parent->style()->isColumnFlexDirection() && columnFlexItemHasStretchAlignment(flexitem))
2449         return true;
2450     return false;
2451 }
2452 
sizesLogicalWidthToFitContent(SizeType widthType) const2453 bool RenderBox::sizesLogicalWidthToFitContent(SizeType widthType) const
2454 {
2455     // Marquees in WinIE are like a mixture of blocks and inline-blocks.  They size as though they're blocks,
2456     // but they allow text to sit on the same line as the marquee.
2457     if (isFloating() || (isInlineBlockOrInlineTable() && !isMarquee()))
2458         return true;
2459 
2460     // This code may look a bit strange.  Basically width:intrinsic should clamp the size when testing both
2461     // min-width and width.  max-width is only clamped if it is also intrinsic.
2462     Length logicalWidth = (widthType == MaxSize) ? style()->logicalMaxWidth() : style()->logicalWidth();
2463     if (logicalWidth.type() == Intrinsic)
2464         return true;
2465 
2466     // Children of a horizontal marquee do not fill the container by default.
2467     // FIXME: Need to deal with MAUTO value properly.  It could be vertical.
2468     // FIXME: Think about block-flow here.  Need to find out how marquee direction relates to
2469     // block-flow (as well as how marquee overflow should relate to block flow).
2470     // https://bugs.webkit.org/show_bug.cgi?id=46472
2471     if (parent()->isMarquee()) {
2472         EMarqueeDirection dir = parent()->style()->marqueeDirection();
2473         if (dir == MAUTO || dir == MFORWARD || dir == MBACKWARD || dir == MLEFT || dir == MRIGHT)
2474             return true;
2475     }
2476 
2477     // Flexible box items should shrink wrap, so we lay them out at their intrinsic widths.
2478     // In the case of columns that have a stretch alignment, we go ahead and layout at the
2479     // stretched size to avoid an extra layout when applying alignment.
2480     if (parent()->isFlexibleBox()) {
2481         // For multiline columns, we need to apply align-content first, so we can't stretch now.
2482         if (!parent()->style()->isColumnFlexDirection() || parent()->style()->flexWrap() != FlexNoWrap)
2483             return true;
2484         if (!columnFlexItemHasStretchAlignment(this))
2485             return true;
2486     }
2487 
2488     // Flexible horizontal boxes lay out children at their intrinsic widths.  Also vertical boxes
2489     // that don't stretch their kids lay out their children at their intrinsic widths.
2490     // FIXME: Think about block-flow here.
2491     // https://bugs.webkit.org/show_bug.cgi?id=46473
2492     if (parent()->isDeprecatedFlexibleBox() && (parent()->style()->boxOrient() == HORIZONTAL || parent()->style()->boxAlign() != BSTRETCH))
2493         return true;
2494 
2495     // Button, input, select, textarea, and legend treat width value of 'auto' as 'intrinsic' unless it's in a
2496     // stretching column flexbox.
2497     // FIXME: Think about block-flow here.
2498     // https://bugs.webkit.org/show_bug.cgi?id=46473
2499     if (logicalWidth.type() == Auto && !isStretchingColumnFlexItem(this) && autoWidthShouldFitContent())
2500         return true;
2501 
2502     if (isHorizontalWritingMode() != containingBlock()->isHorizontalWritingMode())
2503         return true;
2504 
2505     return false;
2506 }
2507 
autoWidthShouldFitContent() const2508 bool RenderBox::autoWidthShouldFitContent() const
2509 {
2510     if (node() && (node()->hasTagName(inputTag) || node()->hasTagName(selectTag) || node()->hasTagName(buttonTag)
2511         || isHTMLTextAreaElement(node()) || node()->hasTagName(legendTag)))
2512         return true;
2513 
2514     return false;
2515 }
2516 
computeInlineDirectionMargins(RenderBlock * containingBlock,LayoutUnit containerWidth,LayoutUnit childWidth,LayoutUnit & marginStart,LayoutUnit & marginEnd) const2517 void RenderBox::computeInlineDirectionMargins(RenderBlock* containingBlock, LayoutUnit containerWidth, LayoutUnit childWidth, LayoutUnit& marginStart, LayoutUnit& marginEnd) const
2518 {
2519     const RenderStyle* containingBlockStyle = containingBlock->style();
2520     Length marginStartLength = style()->marginStartUsing(containingBlockStyle);
2521     Length marginEndLength = style()->marginEndUsing(containingBlockStyle);
2522     RenderView* renderView = view();
2523 
2524     if (isFloating() || isInline()) {
2525         // Inline blocks/tables and floats don't have their margins increased.
2526         marginStart = minimumValueForLength(marginStartLength, containerWidth, renderView);
2527         marginEnd = minimumValueForLength(marginEndLength, containerWidth, renderView);
2528         return;
2529     }
2530 
2531     if (containingBlock->isFlexibleBox()) {
2532         // We need to let flexbox handle the margin adjustment - otherwise, flexbox
2533         // will think we're wider than we actually are and calculate line sizes wrong.
2534         // See also http://dev.w3.org/csswg/css-flexbox/#auto-margins
2535         if (marginStartLength.isAuto())
2536             marginStartLength.setValue(0);
2537         if (marginEndLength.isAuto())
2538             marginEndLength.setValue(0);
2539     }
2540 
2541     // Case One: The object is being centered in the containing block's available logical width.
2542     if ((marginStartLength.isAuto() && marginEndLength.isAuto() && childWidth < containerWidth)
2543         || (!marginStartLength.isAuto() && !marginEndLength.isAuto() && containingBlock->style()->textAlign() == WEBKIT_CENTER)) {
2544         // Other browsers center the margin box for align=center elements so we match them here.
2545         LayoutUnit marginStartWidth = minimumValueForLength(marginStartLength, containerWidth, renderView);
2546         LayoutUnit marginEndWidth = minimumValueForLength(marginEndLength, containerWidth, renderView);
2547         LayoutUnit centeredMarginBoxStart = max<LayoutUnit>(0, (containerWidth - childWidth - marginStartWidth - marginEndWidth) / 2);
2548         marginStart = centeredMarginBoxStart + marginStartWidth;
2549         marginEnd = containerWidth - childWidth - marginStart + marginEndWidth;
2550         return;
2551     }
2552 
2553     // Case Two: The object is being pushed to the start of the containing block's available logical width.
2554     if (marginEndLength.isAuto() && childWidth < containerWidth) {
2555         marginStart = valueForLength(marginStartLength, containerWidth, renderView);
2556         marginEnd = containerWidth - childWidth - marginStart;
2557         return;
2558     }
2559 
2560     // Case Three: The object is being pushed to the end of the containing block's available logical width.
2561     bool pushToEndFromTextAlign = !marginEndLength.isAuto() && ((!containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_LEFT)
2562         || (containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_RIGHT));
2563     if ((marginStartLength.isAuto() && childWidth < containerWidth) || pushToEndFromTextAlign) {
2564         marginEnd = valueForLength(marginEndLength, containerWidth, renderView);
2565         marginStart = containerWidth - childWidth - marginEnd;
2566         return;
2567     }
2568 
2569     // Case Four: Either no auto margins, or our width is >= the container width (css2.1, 10.3.3).  In that case
2570     // auto margins will just turn into 0.
2571     marginStart = minimumValueForLength(marginStartLength, containerWidth, renderView);
2572     marginEnd = minimumValueForLength(marginEndLength, containerWidth, renderView);
2573 }
2574 
renderBoxRegionInfo(RenderRegion * region,RenderBoxRegionInfoFlags cacheFlag) const2575 RenderBoxRegionInfo* RenderBox::renderBoxRegionInfo(RenderRegion* region, RenderBoxRegionInfoFlags cacheFlag) const
2576 {
2577     // Make sure nobody is trying to call this with a null region.
2578     if (!region)
2579         return 0;
2580 
2581     // If we have computed our width in this region already, it will be cached, and we can
2582     // just return it.
2583     RenderBoxRegionInfo* boxInfo = region->renderBoxRegionInfo(this);
2584     if (boxInfo && cacheFlag == CacheRenderBoxRegionInfo)
2585         return boxInfo;
2586 
2587     // No cached value was found, so we have to compute our insets in this region.
2588     // FIXME: For now we limit this computation to normal RenderBlocks. Future patches will expand
2589     // support to cover all boxes.
2590     RenderFlowThread* flowThread = flowThreadContainingBlock();
2591     if (isRenderFlowThread() || !flowThread || !canHaveBoxInfoInRegion() || flowThread->style()->writingMode() != style()->writingMode())
2592         return 0;
2593 
2594     LogicalExtentComputedValues computedValues;
2595     computeLogicalWidthInRegion(computedValues, region);
2596 
2597     // Now determine the insets based off where this object is supposed to be positioned.
2598     RenderBlock* cb = containingBlock();
2599     RenderRegion* clampedContainingBlockRegion = cb->clampToStartAndEndRegions(region);
2600     RenderBoxRegionInfo* containingBlockInfo = cb->renderBoxRegionInfo(clampedContainingBlockRegion);
2601     LayoutUnit containingBlockLogicalWidth = cb->logicalWidth();
2602     LayoutUnit containingBlockLogicalWidthInRegion = containingBlockInfo ? containingBlockInfo->logicalWidth() : containingBlockLogicalWidth;
2603 
2604     LayoutUnit marginStartInRegion = computedValues.m_margins.m_start;
2605     LayoutUnit startMarginDelta = marginStartInRegion - marginStart();
2606     LayoutUnit logicalWidthInRegion = computedValues.m_extent;
2607     LayoutUnit logicalLeftInRegion = computedValues.m_position;
2608     LayoutUnit widthDelta = logicalWidthInRegion - logicalWidth();
2609     LayoutUnit logicalLeftDelta = isOutOfFlowPositioned() ? logicalLeftInRegion - logicalLeft() : startMarginDelta;
2610     LayoutUnit logicalRightInRegion = containingBlockLogicalWidthInRegion - (logicalLeftInRegion + logicalWidthInRegion);
2611     LayoutUnit oldLogicalRight = containingBlockLogicalWidth - (logicalLeft() + logicalWidth());
2612     LayoutUnit logicalRightDelta = isOutOfFlowPositioned() ? logicalRightInRegion - oldLogicalRight : startMarginDelta;
2613 
2614     LayoutUnit logicalLeftOffset = 0;
2615 
2616     if (!isOutOfFlowPositioned() && avoidsFloats() && cb->containsFloats()) {
2617         LayoutUnit startPositionDelta = cb->computeStartPositionDeltaForChildAvoidingFloats(this, marginStartInRegion, region);
2618         if (cb->style()->isLeftToRightDirection())
2619             logicalLeftDelta += startPositionDelta;
2620         else
2621             logicalRightDelta += startPositionDelta;
2622     }
2623 
2624     if (cb->style()->isLeftToRightDirection())
2625         logicalLeftOffset += logicalLeftDelta;
2626     else
2627         logicalLeftOffset -= (widthDelta + logicalRightDelta);
2628 
2629     LayoutUnit logicalRightOffset = logicalWidth() - (logicalLeftOffset + logicalWidthInRegion);
2630     bool isShifted = (containingBlockInfo && containingBlockInfo->isShifted())
2631             || (style()->isLeftToRightDirection() && logicalLeftOffset)
2632             || (!style()->isLeftToRightDirection() && logicalRightOffset);
2633 
2634     // FIXME: Although it's unlikely, these boxes can go outside our bounds, and so we will need to incorporate them into overflow.
2635     if (cacheFlag == CacheRenderBoxRegionInfo)
2636         return region->setRenderBoxRegionInfo(this, logicalLeftOffset, logicalWidthInRegion, isShifted);
2637     return new RenderBoxRegionInfo(logicalLeftOffset, logicalWidthInRegion, isShifted);
2638 }
2639 
shouldFlipBeforeAfterMargins(const RenderStyle * containingBlockStyle,const RenderStyle * childStyle)2640 static bool shouldFlipBeforeAfterMargins(const RenderStyle* containingBlockStyle, const RenderStyle* childStyle)
2641 {
2642     ASSERT(containingBlockStyle->isHorizontalWritingMode() != childStyle->isHorizontalWritingMode());
2643     WritingMode childWritingMode = childStyle->writingMode();
2644     bool shouldFlip = false;
2645     switch (containingBlockStyle->writingMode()) {
2646     case TopToBottomWritingMode:
2647         shouldFlip = (childWritingMode == RightToLeftWritingMode);
2648         break;
2649     case BottomToTopWritingMode:
2650         shouldFlip = (childWritingMode == RightToLeftWritingMode);
2651         break;
2652     case RightToLeftWritingMode:
2653         shouldFlip = (childWritingMode == BottomToTopWritingMode);
2654         break;
2655     case LeftToRightWritingMode:
2656         shouldFlip = (childWritingMode == BottomToTopWritingMode);
2657         break;
2658     }
2659 
2660     if (!containingBlockStyle->isLeftToRightDirection())
2661         shouldFlip = !shouldFlip;
2662 
2663     return shouldFlip;
2664 }
2665 
updateLogicalHeight()2666 void RenderBox::updateLogicalHeight()
2667 {
2668     m_intrinsicContentLogicalHeight = contentLogicalHeight();
2669 
2670     LogicalExtentComputedValues computedValues;
2671     computeLogicalHeight(logicalHeight(), logicalTop(), computedValues);
2672 
2673     setLogicalHeight(computedValues.m_extent);
2674     setLogicalTop(computedValues.m_position);
2675     setMarginBefore(computedValues.m_margins.m_before);
2676     setMarginAfter(computedValues.m_margins.m_after);
2677 }
2678 
computeLogicalHeight(LayoutUnit logicalHeight,LayoutUnit logicalTop,LogicalExtentComputedValues & computedValues) const2679 void RenderBox::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
2680 {
2681     computedValues.m_extent = logicalHeight;
2682     computedValues.m_position = logicalTop;
2683 
2684     // Cell height is managed by the table and inline non-replaced elements do not support a height property.
2685     if (isTableCell() || (isInline() && !isReplaced()))
2686         return;
2687 
2688     Length h;
2689     if (isOutOfFlowPositioned())
2690         computePositionedLogicalHeight(computedValues);
2691     else {
2692         RenderBlock* cb = containingBlock();
2693         bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode();
2694 
2695         if (!hasPerpendicularContainingBlock) {
2696             bool shouldFlipBeforeAfter = cb->style()->writingMode() != style()->writingMode();
2697             computeBlockDirectionMargins(cb,
2698                 shouldFlipBeforeAfter ? computedValues.m_margins.m_after : computedValues.m_margins.m_before,
2699                 shouldFlipBeforeAfter ? computedValues.m_margins.m_before : computedValues.m_margins.m_after);
2700         }
2701 
2702         // For tables, calculate margins only.
2703         if (isTable()) {
2704             if (hasPerpendicularContainingBlock) {
2705                 bool shouldFlipBeforeAfter = shouldFlipBeforeAfterMargins(cb->style(), style());
2706                 computeInlineDirectionMargins(cb, containingBlockLogicalWidthForContent(), computedValues.m_extent,
2707                     shouldFlipBeforeAfter ? computedValues.m_margins.m_after : computedValues.m_margins.m_before,
2708                     shouldFlipBeforeAfter ? computedValues.m_margins.m_before : computedValues.m_margins.m_after);
2709             }
2710             return;
2711         }
2712 
2713         // FIXME: Account for block-flow in flexible boxes.
2714         // https://bugs.webkit.org/show_bug.cgi?id=46418
2715         bool inHorizontalBox = parent()->isDeprecatedFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL;
2716         bool stretching = parent()->style()->boxAlign() == BSTRETCH;
2717         bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inHorizontalBox || !stretching);
2718         bool checkMinMaxHeight = false;
2719 
2720         // The parent box is flexing us, so it has increased or decreased our height.  We have to
2721         // grab our cached flexible height.
2722         // FIXME: Account for block-flow in flexible boxes.
2723         // https://bugs.webkit.org/show_bug.cgi?id=46418
2724         if (hasOverrideHeight() && parent()->isFlexibleBoxIncludingDeprecated())
2725             h = Length(overrideLogicalContentHeight(), Fixed);
2726         else if (treatAsReplaced)
2727             h = Length(computeReplacedLogicalHeight(), Fixed);
2728         else {
2729             h = style()->logicalHeight();
2730             checkMinMaxHeight = true;
2731         }
2732 
2733         // Block children of horizontal flexible boxes fill the height of the box.
2734         // FIXME: Account for block-flow in flexible boxes.
2735         // https://bugs.webkit.org/show_bug.cgi?id=46418
2736         if (h.isAuto() && parent()->isDeprecatedFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
2737                 && parent()->isStretchingChildren()) {
2738             h = Length(parentBox()->contentLogicalHeight() - marginBefore() - marginAfter() - borderAndPaddingLogicalHeight(), Fixed);
2739             checkMinMaxHeight = false;
2740         }
2741 
2742         LayoutUnit heightResult;
2743         if (checkMinMaxHeight) {
2744             heightResult = computeLogicalHeightUsing(style()->logicalHeight(), computedValues.m_extent - borderAndPaddingLogicalHeight());
2745             if (heightResult == -1)
2746                 heightResult = computedValues.m_extent;
2747             heightResult = constrainLogicalHeightByMinMax(heightResult, computedValues.m_extent - borderAndPaddingLogicalHeight());
2748         } else {
2749             // The only times we don't check min/max height are when a fixed length has
2750             // been given as an override.  Just use that.  The value has already been adjusted
2751             // for box-sizing.
2752             ASSERT(h.isFixed());
2753             heightResult = h.value() + borderAndPaddingLogicalHeight();
2754         }
2755 
2756         computedValues.m_extent = heightResult;
2757 
2758         if (hasPerpendicularContainingBlock) {
2759             bool shouldFlipBeforeAfter = shouldFlipBeforeAfterMargins(cb->style(), style());
2760             computeInlineDirectionMargins(cb, containingBlockLogicalWidthForContent(), heightResult,
2761                     shouldFlipBeforeAfter ? computedValues.m_margins.m_after : computedValues.m_margins.m_before,
2762                     shouldFlipBeforeAfter ? computedValues.m_margins.m_before : computedValues.m_margins.m_after);
2763         }
2764     }
2765 
2766     // WinIE quirk: The <html> block always fills the entire canvas in quirks mode.  The <body> always fills the
2767     // <html> block in quirks mode.  Only apply this quirk if the block is normal flow and no height
2768     // is specified. When we're printing, we also need this quirk if the body or root has a percentage
2769     // height since we don't set a height in RenderView when we're printing. So without this quirk, the
2770     // height has nothing to be a percentage of, and it ends up being 0. That is bad.
2771     bool paginatedContentNeedsBaseHeight = document().printing() && h.isPercent()
2772         && (isRoot() || (isBody() && document().documentElement()->renderer()->style()->logicalHeight().isPercent())) && !isInline();
2773     if (stretchesToViewport() || paginatedContentNeedsBaseHeight) {
2774         LayoutUnit margins = collapsedMarginBefore() + collapsedMarginAfter();
2775         LayoutUnit visibleHeight = viewLogicalHeightForPercentages();
2776         if (isRoot())
2777             computedValues.m_extent = max(computedValues.m_extent, visibleHeight - margins);
2778         else {
2779             LayoutUnit marginsBordersPadding = margins + parentBox()->marginBefore() + parentBox()->marginAfter() + parentBox()->borderAndPaddingLogicalHeight();
2780             computedValues.m_extent = max(computedValues.m_extent, visibleHeight - marginsBordersPadding);
2781         }
2782     }
2783 }
2784 
viewLogicalHeightForPercentages() const2785 LayoutUnit RenderBox::viewLogicalHeightForPercentages() const
2786 {
2787     if (document().printing())
2788         return static_cast<LayoutUnit>(view()->pageLogicalHeight());
2789     return view()->viewLogicalHeight();
2790 }
2791 
computeLogicalHeightUsing(const Length & height,LayoutUnit intrinsicContentHeight) const2792 LayoutUnit RenderBox::computeLogicalHeightUsing(const Length& height, LayoutUnit intrinsicContentHeight) const
2793 {
2794     LayoutUnit logicalHeight = computeContentAndScrollbarLogicalHeightUsing(height, intrinsicContentHeight);
2795     if (logicalHeight != -1)
2796         logicalHeight = adjustBorderBoxLogicalHeightForBoxSizing(logicalHeight);
2797     return logicalHeight;
2798 }
2799 
computeContentLogicalHeight(const Length & height,LayoutUnit intrinsicContentHeight) const2800 LayoutUnit RenderBox::computeContentLogicalHeight(const Length& height, LayoutUnit intrinsicContentHeight) const
2801 {
2802     LayoutUnit heightIncludingScrollbar = computeContentAndScrollbarLogicalHeightUsing(height, intrinsicContentHeight);
2803     if (heightIncludingScrollbar == -1)
2804         return -1;
2805     return std::max<LayoutUnit>(0, adjustContentBoxLogicalHeightForBoxSizing(heightIncludingScrollbar) - scrollbarLogicalHeight());
2806 }
2807 
computeIntrinsicLogicalContentHeightUsing(Length logicalHeightLength,LayoutUnit intrinsicContentHeight,LayoutUnit borderAndPadding) const2808 LayoutUnit RenderBox::computeIntrinsicLogicalContentHeightUsing(Length logicalHeightLength, LayoutUnit intrinsicContentHeight, LayoutUnit borderAndPadding) const
2809 {
2810     // FIXME(cbiesinger): The css-sizing spec is considering changing what min-content/max-content should resolve to.
2811     // If that happens, this code will have to change.
2812     if (logicalHeightLength.isMinContent() || logicalHeightLength.isMaxContent() || logicalHeightLength.isFitContent()) {
2813         if (isReplaced())
2814             return intrinsicSize().height();
2815         if (m_intrinsicContentLogicalHeight != -1)
2816             return m_intrinsicContentLogicalHeight;
2817         return intrinsicContentHeight;
2818     }
2819     if (logicalHeightLength.isFillAvailable())
2820         return containingBlock()->availableLogicalHeight(ExcludeMarginBorderPadding) - borderAndPadding;
2821     ASSERT_NOT_REACHED();
2822     return 0;
2823 }
2824 
computeContentAndScrollbarLogicalHeightUsing(const Length & height,LayoutUnit intrinsicContentHeight) const2825 LayoutUnit RenderBox::computeContentAndScrollbarLogicalHeightUsing(const Length& height, LayoutUnit intrinsicContentHeight) const
2826 {
2827     // FIXME(cbiesinger): The css-sizing spec is considering changing what min-content/max-content should resolve to.
2828     // If that happens, this code will have to change.
2829     if (height.isIntrinsic()) {
2830         if (intrinsicContentHeight == -1)
2831             return -1; // Intrinsic height isn't available.
2832         return computeIntrinsicLogicalContentHeightUsing(height, intrinsicContentHeight, borderAndPaddingLogicalHeight());
2833     }
2834     if (height.isFixed())
2835         return height.value();
2836     if (height.isPercent())
2837         return computePercentageLogicalHeight(height);
2838     if (height.isViewportPercentage())
2839         return valueForLength(height, 0, view());
2840     return -1;
2841 }
2842 
skipContainingBlockForPercentHeightCalculation(const RenderBox * containingBlock) const2843 bool RenderBox::skipContainingBlockForPercentHeightCalculation(const RenderBox* containingBlock) const
2844 {
2845     // For quirks mode and anonymous blocks, we skip auto-height containingBlocks when computing percentages.
2846     // For standards mode, we treat the percentage as auto if it has an auto-height containing block.
2847     if (!document().inQuirksMode() && !containingBlock->isAnonymousBlock())
2848         return false;
2849     return !containingBlock->isTableCell() && !containingBlock->isOutOfFlowPositioned() && containingBlock->style()->logicalHeight().isAuto() && isHorizontalWritingMode() == containingBlock->isHorizontalWritingMode();
2850 }
2851 
computePercentageLogicalHeight(const Length & height) const2852 LayoutUnit RenderBox::computePercentageLogicalHeight(const Length& height) const
2853 {
2854     LayoutUnit availableHeight = -1;
2855 
2856     bool skippedAutoHeightContainingBlock = false;
2857     RenderBlock* cb = containingBlock();
2858     const RenderBox* containingBlockChild = this;
2859     LayoutUnit rootMarginBorderPaddingHeight = 0;
2860     while (!cb->isRenderView() && skipContainingBlockForPercentHeightCalculation(cb)) {
2861         if (cb->isBody() || cb->isRoot())
2862             rootMarginBorderPaddingHeight += cb->marginBefore() + cb->marginAfter() + cb->borderAndPaddingLogicalHeight();
2863         skippedAutoHeightContainingBlock = true;
2864         containingBlockChild = cb;
2865         cb = cb->containingBlock();
2866         cb->addPercentHeightDescendant(const_cast<RenderBox*>(this));
2867     }
2868 
2869     RenderStyle* cbstyle = cb->style();
2870 
2871     // A positioned element that specified both top/bottom or that specifies height should be treated as though it has a height
2872     // explicitly specified that can be used for any percentage computations.
2873     bool isOutOfFlowPositionedWithSpecifiedHeight = cb->isOutOfFlowPositioned() && (!cbstyle->logicalHeight().isAuto() || (!cbstyle->logicalTop().isAuto() && !cbstyle->logicalBottom().isAuto()));
2874 
2875     bool includeBorderPadding = isTable();
2876 
2877     if (isHorizontalWritingMode() != cb->isHorizontalWritingMode())
2878         availableHeight = containingBlockChild->containingBlockLogicalWidthForContent();
2879     else if (hasOverrideContainingBlockLogicalHeight())
2880         availableHeight = overrideContainingBlockContentLogicalHeight();
2881     else if (cb->isTableCell()) {
2882         if (!skippedAutoHeightContainingBlock) {
2883             // Table cells violate what the CSS spec says to do with heights. Basically we
2884             // don't care if the cell specified a height or not. We just always make ourselves
2885             // be a percentage of the cell's current content height.
2886             if (!cb->hasOverrideHeight()) {
2887                 // Normally we would let the cell size intrinsically, but scrolling overflow has to be
2888                 // treated differently, since WinIE lets scrolled overflow regions shrink as needed.
2889                 // While we can't get all cases right, we can at least detect when the cell has a specified
2890                 // height or when the table has a specified height. In these cases we want to initially have
2891                 // no size and allow the flexing of the table or the cell to its specified height to cause us
2892                 // to grow to fill the space. This could end up being wrong in some cases, but it is
2893                 // preferable to the alternative (sizing intrinsically and making the row end up too big).
2894                 RenderTableCell* cell = toRenderTableCell(cb);
2895                 if (scrollsOverflowY() && (!cell->style()->logicalHeight().isAuto() || !cell->table()->style()->logicalHeight().isAuto()))
2896                     return 0;
2897                 return -1;
2898             }
2899             availableHeight = cb->overrideLogicalContentHeight();
2900             includeBorderPadding = true;
2901         }
2902     } else if (cbstyle->logicalHeight().isFixed()) {
2903         LayoutUnit contentBoxHeight = cb->adjustContentBoxLogicalHeightForBoxSizing(cbstyle->logicalHeight().value());
2904         availableHeight = max<LayoutUnit>(0, cb->constrainContentBoxLogicalHeightByMinMax(contentBoxHeight - cb->scrollbarLogicalHeight(), -1));
2905     } else if (cbstyle->logicalHeight().isPercent() && !isOutOfFlowPositionedWithSpecifiedHeight) {
2906         // We need to recur and compute the percentage height for our containing block.
2907         LayoutUnit heightWithScrollbar = cb->computePercentageLogicalHeight(cbstyle->logicalHeight());
2908         if (heightWithScrollbar != -1) {
2909             LayoutUnit contentBoxHeightWithScrollbar = cb->adjustContentBoxLogicalHeightForBoxSizing(heightWithScrollbar);
2910             // We need to adjust for min/max height because this method does not
2911             // handle the min/max of the current block, its caller does. So the
2912             // return value from the recursive call will not have been adjusted
2913             // yet.
2914             LayoutUnit contentBoxHeight = cb->constrainContentBoxLogicalHeightByMinMax(contentBoxHeightWithScrollbar - cb->scrollbarLogicalHeight(), -1);
2915             availableHeight = max<LayoutUnit>(0, contentBoxHeight);
2916         }
2917     } else if (cbstyle->logicalHeight().isViewportPercentage()) {
2918         LayoutUnit heightWithScrollbar = valueForLength(cbstyle->logicalHeight(), 0, view());
2919         if (heightWithScrollbar != -1) {
2920             LayoutUnit contentBoxHeightWithScrollbar = cb->adjustContentBoxLogicalHeightForBoxSizing(heightWithScrollbar);
2921             // We need to adjust for min/max height because this method does not
2922             // handle the min/max of the current block, its caller does. So the
2923             // return value from the recursive call will not have been adjusted
2924             // yet.
2925             LayoutUnit contentBoxHeight = cb->constrainContentBoxLogicalHeightByMinMax(contentBoxHeightWithScrollbar - cb->scrollbarLogicalHeight(), -1);
2926             availableHeight = max<LayoutUnit>(0, contentBoxHeight);
2927         }
2928     } else if (isOutOfFlowPositionedWithSpecifiedHeight) {
2929         // Don't allow this to affect the block' height() member variable, since this
2930         // can get called while the block is still laying out its kids.
2931         LogicalExtentComputedValues computedValues;
2932         cb->computeLogicalHeight(cb->logicalHeight(), 0, computedValues);
2933         availableHeight = computedValues.m_extent - cb->borderAndPaddingLogicalHeight() - cb->scrollbarLogicalHeight();
2934     } else if (cb->isRenderView())
2935         availableHeight = viewLogicalHeightForPercentages();
2936 
2937     if (availableHeight == -1)
2938         return availableHeight;
2939 
2940     availableHeight -= rootMarginBorderPaddingHeight;
2941 
2942     LayoutUnit result = valueForLength(height, availableHeight);
2943     if (includeBorderPadding) {
2944         // FIXME: Table cells should default to box-sizing: border-box so we can avoid this hack.
2945         // It is necessary to use the border-box to match WinIE's broken
2946         // box model. This is essential for sizing inside
2947         // table cells using percentage heights.
2948         result -= borderAndPaddingLogicalHeight();
2949         return max<LayoutUnit>(0, result);
2950     }
2951     return result;
2952 }
2953 
computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const2954 LayoutUnit RenderBox::computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const
2955 {
2956     return computeReplacedLogicalWidthRespectingMinMaxWidth(computeReplacedLogicalWidthUsing(style()->logicalWidth()), shouldComputePreferred);
2957 }
2958 
computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUnit logicalWidth,ShouldComputePreferred shouldComputePreferred) const2959 LayoutUnit RenderBox::computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUnit logicalWidth, ShouldComputePreferred shouldComputePreferred) const
2960 {
2961     LayoutUnit minLogicalWidth = (shouldComputePreferred == ComputePreferred && style()->logicalMinWidth().isPercent()) || style()->logicalMinWidth().isUndefined() ? logicalWidth : computeReplacedLogicalWidthUsing(style()->logicalMinWidth());
2962     LayoutUnit maxLogicalWidth = (shouldComputePreferred == ComputePreferred && style()->logicalMaxWidth().isPercent()) || style()->logicalMaxWidth().isUndefined() ? logicalWidth : computeReplacedLogicalWidthUsing(style()->logicalMaxWidth());
2963     return max(minLogicalWidth, min(logicalWidth, maxLogicalWidth));
2964 }
2965 
computeReplacedLogicalWidthUsing(Length logicalWidth) const2966 LayoutUnit RenderBox::computeReplacedLogicalWidthUsing(Length logicalWidth) const
2967 {
2968     switch (logicalWidth.type()) {
2969         case Fixed:
2970             return adjustContentBoxLogicalWidthForBoxSizing(logicalWidth.value());
2971         case MinContent:
2972         case MaxContent: {
2973             // MinContent/MaxContent don't need the availableLogicalWidth argument.
2974             LayoutUnit availableLogicalWidth = 0;
2975             return computeIntrinsicLogicalWidthUsing(logicalWidth, availableLogicalWidth, borderAndPaddingLogicalWidth()) - borderAndPaddingLogicalWidth();
2976         }
2977         case ViewportPercentageWidth:
2978         case ViewportPercentageHeight:
2979         case ViewportPercentageMin:
2980         case ViewportPercentageMax:
2981             return adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, 0, view()));
2982         case FitContent:
2983         case FillAvailable:
2984         case Percent:
2985         case Calculated: {
2986             // FIXME: containingBlockLogicalWidthForContent() is wrong if the replaced element's block-flow is perpendicular to the
2987             // containing block's block-flow.
2988             // https://bugs.webkit.org/show_bug.cgi?id=46496
2989             const LayoutUnit cw = isOutOfFlowPositioned() ? containingBlockLogicalWidthForPositioned(toRenderBoxModelObject(container())) : containingBlockLogicalWidthForContent();
2990             Length containerLogicalWidth = containingBlock()->style()->logicalWidth();
2991             // FIXME: Handle cases when containing block width is calculated or viewport percent.
2992             // https://bugs.webkit.org/show_bug.cgi?id=91071
2993             if (logicalWidth.isIntrinsic())
2994                 return computeIntrinsicLogicalWidthUsing(logicalWidth, cw, borderAndPaddingLogicalWidth()) - borderAndPaddingLogicalWidth();
2995             if (cw > 0 || (!cw && (containerLogicalWidth.isFixed() || containerLogicalWidth.isPercent())))
2996                 return adjustContentBoxLogicalWidthForBoxSizing(minimumValueForLength(logicalWidth, cw));
2997         }
2998         // fall through
2999         case Intrinsic:
3000         case MinIntrinsic:
3001         case Auto:
3002         case ExtendToZoom:
3003         case Undefined:
3004             return intrinsicLogicalWidth();
3005     }
3006 
3007     ASSERT_NOT_REACHED();
3008     return 0;
3009 }
3010 
computeReplacedLogicalHeight() const3011 LayoutUnit RenderBox::computeReplacedLogicalHeight() const
3012 {
3013     return computeReplacedLogicalHeightRespectingMinMaxHeight(computeReplacedLogicalHeightUsing(style()->logicalHeight()));
3014 }
3015 
computeReplacedLogicalHeightRespectingMinMaxHeight(LayoutUnit logicalHeight) const3016 LayoutUnit RenderBox::computeReplacedLogicalHeightRespectingMinMaxHeight(LayoutUnit logicalHeight) const
3017 {
3018     LayoutUnit minLogicalHeight = computeReplacedLogicalHeightUsing(style()->logicalMinHeight());
3019     LayoutUnit maxLogicalHeight = style()->logicalMaxHeight().isUndefined() ? logicalHeight : computeReplacedLogicalHeightUsing(style()->logicalMaxHeight());
3020     return max(minLogicalHeight, min(logicalHeight, maxLogicalHeight));
3021 }
3022 
computeReplacedLogicalHeightUsing(Length logicalHeight) const3023 LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(Length logicalHeight) const
3024 {
3025     switch (logicalHeight.type()) {
3026         case Fixed:
3027             return adjustContentBoxLogicalHeightForBoxSizing(logicalHeight.value());
3028         case Percent:
3029         case Calculated:
3030         {
3031             RenderObject* cb = isOutOfFlowPositioned() ? container() : containingBlock();
3032             while (cb->isAnonymous()) {
3033                 cb = cb->containingBlock();
3034                 toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this));
3035             }
3036 
3037             // FIXME: This calculation is not patched for block-flow yet.
3038             // https://bugs.webkit.org/show_bug.cgi?id=46500
3039             if (cb->isOutOfFlowPositioned() && cb->style()->height().isAuto() && !(cb->style()->top().isAuto() || cb->style()->bottom().isAuto())) {
3040                 ASSERT_WITH_SECURITY_IMPLICATION(cb->isRenderBlock());
3041                 RenderBlock* block = toRenderBlock(cb);
3042                 LogicalExtentComputedValues computedValues;
3043                 block->computeLogicalHeight(block->logicalHeight(), 0, computedValues);
3044                 LayoutUnit newContentHeight = computedValues.m_extent - block->borderAndPaddingLogicalHeight() - block->scrollbarLogicalHeight();
3045                 LayoutUnit newHeight = block->adjustContentBoxLogicalHeightForBoxSizing(newContentHeight);
3046                 return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeight, newHeight));
3047             }
3048 
3049             // FIXME: availableLogicalHeight() is wrong if the replaced element's block-flow is perpendicular to the
3050             // containing block's block-flow.
3051             // https://bugs.webkit.org/show_bug.cgi?id=46496
3052             LayoutUnit availableHeight;
3053             if (isOutOfFlowPositioned())
3054                 availableHeight = containingBlockLogicalHeightForPositioned(toRenderBoxModelObject(cb));
3055             else {
3056                 availableHeight = containingBlockLogicalHeightForContent(IncludeMarginBorderPadding);
3057                 // It is necessary to use the border-box to match WinIE's broken
3058                 // box model.  This is essential for sizing inside
3059                 // table cells using percentage heights.
3060                 // FIXME: This needs to be made block-flow-aware.  If the cell and image are perpendicular block-flows, this isn't right.
3061                 // https://bugs.webkit.org/show_bug.cgi?id=46997
3062                 while (cb && !cb->isRenderView() && (cb->style()->logicalHeight().isAuto() || cb->style()->logicalHeight().isPercent())) {
3063                     if (cb->isTableCell()) {
3064                         // Don't let table cells squeeze percent-height replaced elements
3065                         // <http://bugs.webkit.org/show_bug.cgi?id=15359>
3066                         availableHeight = max(availableHeight, intrinsicLogicalHeight());
3067                         return valueForLength(logicalHeight, availableHeight - borderAndPaddingLogicalHeight());
3068                     }
3069                     toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this));
3070                     cb = cb->containingBlock();
3071                 }
3072             }
3073             return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeight, availableHeight));
3074         }
3075         case ViewportPercentageWidth:
3076         case ViewportPercentageHeight:
3077         case ViewportPercentageMin:
3078         case ViewportPercentageMax:
3079             return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeight, 0, view()));
3080         case MinContent:
3081         case MaxContent:
3082         case FitContent:
3083         case FillAvailable:
3084             return adjustContentBoxLogicalHeightForBoxSizing(computeIntrinsicLogicalContentHeightUsing(logicalHeight, intrinsicLogicalHeight(), borderAndPaddingHeight()));
3085         default:
3086             return intrinsicLogicalHeight();
3087     }
3088 }
3089 
availableLogicalHeight(AvailableLogicalHeightType heightType) const3090 LayoutUnit RenderBox::availableLogicalHeight(AvailableLogicalHeightType heightType) const
3091 {
3092     return constrainLogicalHeightByMinMax(availableLogicalHeightUsing(style()->logicalHeight(), heightType), -1);
3093 }
3094 
availableLogicalHeightUsing(const Length & h,AvailableLogicalHeightType heightType) const3095 LayoutUnit RenderBox::availableLogicalHeightUsing(const Length& h, AvailableLogicalHeightType heightType) const
3096 {
3097     if (isRenderView())
3098         return isHorizontalWritingMode() ? toRenderView(this)->frameView()->visibleHeight() : toRenderView(this)->frameView()->visibleWidth();
3099 
3100     // We need to stop here, since we don't want to increase the height of the table
3101     // artificially.  We're going to rely on this cell getting expanded to some new
3102     // height, and then when we lay out again we'll use the calculation below.
3103     if (isTableCell() && (h.isAuto() || h.isPercent())) {
3104         if (hasOverrideHeight())
3105             return overrideLogicalContentHeight();
3106         return logicalHeight() - borderAndPaddingLogicalHeight();
3107     }
3108 
3109     if (h.isPercent() && isOutOfFlowPositioned() && !isRenderFlowThread()) {
3110         // FIXME: This is wrong if the containingBlock has a perpendicular writing mode.
3111         LayoutUnit availableHeight = containingBlockLogicalHeightForPositioned(containingBlock());
3112         return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(h, availableHeight));
3113     }
3114 
3115     LayoutUnit heightIncludingScrollbar = computeContentAndScrollbarLogicalHeightUsing(h, -1);
3116     if (heightIncludingScrollbar != -1)
3117         return std::max<LayoutUnit>(0, adjustContentBoxLogicalHeightForBoxSizing(heightIncludingScrollbar) - scrollbarLogicalHeight());
3118 
3119     // FIXME: Check logicalTop/logicalBottom here to correctly handle vertical writing-mode.
3120     // https://bugs.webkit.org/show_bug.cgi?id=46500
3121     if (isRenderBlock() && isOutOfFlowPositioned() && style()->height().isAuto() && !(style()->top().isAuto() || style()->bottom().isAuto())) {
3122         RenderBlock* block = const_cast<RenderBlock*>(toRenderBlock(this));
3123         LogicalExtentComputedValues computedValues;
3124         block->computeLogicalHeight(block->logicalHeight(), 0, computedValues);
3125         LayoutUnit newContentHeight = computedValues.m_extent - block->borderAndPaddingLogicalHeight() - block->scrollbarLogicalHeight();
3126         return adjustContentBoxLogicalHeightForBoxSizing(newContentHeight);
3127     }
3128 
3129     // FIXME: This is wrong if the containingBlock has a perpendicular writing mode.
3130     LayoutUnit availableHeight = containingBlockLogicalHeightForContent(heightType);
3131     if (heightType == ExcludeMarginBorderPadding) {
3132         // FIXME: Margin collapsing hasn't happened yet, so this incorrectly removes collapsed margins.
3133         availableHeight -= marginBefore() + marginAfter() + borderAndPaddingLogicalHeight();
3134     }
3135     return availableHeight;
3136 }
3137 
computeBlockDirectionMargins(const RenderBlock * containingBlock,LayoutUnit & marginBefore,LayoutUnit & marginAfter) const3138 void RenderBox::computeBlockDirectionMargins(const RenderBlock* containingBlock, LayoutUnit& marginBefore, LayoutUnit& marginAfter) const
3139 {
3140     if (isTableCell()) {
3141         // FIXME: Not right if we allow cells to have different directionality than the table.  If we do allow this, though,
3142         // we may just do it with an extra anonymous block inside the cell.
3143         marginBefore = 0;
3144         marginAfter = 0;
3145         return;
3146     }
3147 
3148     // Margins are calculated with respect to the logical width of
3149     // the containing block (8.3)
3150     LayoutUnit cw = containingBlockLogicalWidthForContent();
3151     RenderView* renderView = view();
3152     RenderStyle* containingBlockStyle = containingBlock->style();
3153     marginBefore = minimumValueForLength(style()->marginBeforeUsing(containingBlockStyle), cw, renderView);
3154     marginAfter = minimumValueForLength(style()->marginAfterUsing(containingBlockStyle), cw, renderView);
3155 }
3156 
computeAndSetBlockDirectionMargins(const RenderBlock * containingBlock)3157 void RenderBox::computeAndSetBlockDirectionMargins(const RenderBlock* containingBlock)
3158 {
3159     LayoutUnit marginBefore;
3160     LayoutUnit marginAfter;
3161     computeBlockDirectionMargins(containingBlock, marginBefore, marginAfter);
3162     containingBlock->setMarginBeforeForChild(this, marginBefore);
3163     containingBlock->setMarginAfterForChild(this, marginAfter);
3164 }
3165 
containingBlockLogicalWidthForPositioned(const RenderBoxModelObject * containingBlock,RenderRegion * region,bool checkForPerpendicularWritingMode) const3166 LayoutUnit RenderBox::containingBlockLogicalWidthForPositioned(const RenderBoxModelObject* containingBlock, RenderRegion* region, bool checkForPerpendicularWritingMode) const
3167 {
3168     if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode())
3169         return containingBlockLogicalHeightForPositioned(containingBlock, false);
3170 
3171     // Use viewport as container for top-level fixed-position elements.
3172     if (style()->position() == FixedPosition && containingBlock->isRenderView()) {
3173         const RenderView* view = toRenderView(containingBlock);
3174         if (FrameView* frameView = view->frameView()) {
3175             LayoutRect viewportRect = frameView->viewportConstrainedVisibleContentRect();
3176             return containingBlock->isHorizontalWritingMode() ? viewportRect.width() : viewportRect.height();
3177         }
3178     }
3179 
3180     if (containingBlock->isBox()) {
3181         RenderFlowThread* flowThread = flowThreadContainingBlock();
3182         if (!flowThread)
3183             return toRenderBox(containingBlock)->clientLogicalWidth();
3184 
3185         const RenderBlock* cb = toRenderBlock(containingBlock);
3186         RenderBoxRegionInfo* boxInfo = 0;
3187         if (!region) {
3188             if (containingBlock->isRenderFlowThread() && !checkForPerpendicularWritingMode)
3189                 return toRenderFlowThread(containingBlock)->contentLogicalWidthOfFirstRegion();
3190             if (isWritingModeRoot()) {
3191                 LayoutUnit cbPageOffset = cb->offsetFromLogicalTopOfFirstPage();
3192                 RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset);
3193                 if (cbRegion) {
3194                     cbRegion = cb->clampToStartAndEndRegions(cbRegion);
3195                     boxInfo = cb->renderBoxRegionInfo(cbRegion);
3196                 }
3197             }
3198         } else if (region && flowThread->isHorizontalWritingMode() == containingBlock->isHorizontalWritingMode()) {
3199             RenderRegion* containingBlockRegion = cb->clampToStartAndEndRegions(region);
3200             boxInfo = cb->renderBoxRegionInfo(containingBlockRegion);
3201         }
3202         return (boxInfo) ? max<LayoutUnit>(0, cb->clientLogicalWidth() - (cb->logicalWidth() - boxInfo->logicalWidth())) : cb->clientLogicalWidth();
3203     }
3204 
3205     ASSERT(containingBlock->isRenderInline() && containingBlock->isInFlowPositioned());
3206 
3207     const RenderInline* flow = toRenderInline(containingBlock);
3208     InlineFlowBox* first = flow->firstLineBox();
3209     InlineFlowBox* last = flow->lastLineBox();
3210 
3211     // If the containing block is empty, return a width of 0.
3212     if (!first || !last)
3213         return 0;
3214 
3215     LayoutUnit fromLeft;
3216     LayoutUnit fromRight;
3217     if (containingBlock->style()->isLeftToRightDirection()) {
3218         fromLeft = first->logicalLeft() + first->borderLogicalLeft();
3219         fromRight = last->logicalLeft() + last->logicalWidth() - last->borderLogicalRight();
3220     } else {
3221         fromRight = first->logicalLeft() + first->logicalWidth() - first->borderLogicalRight();
3222         fromLeft = last->logicalLeft() + last->borderLogicalLeft();
3223     }
3224 
3225     return max<LayoutUnit>(0, fromRight - fromLeft);
3226 }
3227 
containingBlockLogicalHeightForPositioned(const RenderBoxModelObject * containingBlock,bool checkForPerpendicularWritingMode) const3228 LayoutUnit RenderBox::containingBlockLogicalHeightForPositioned(const RenderBoxModelObject* containingBlock, bool checkForPerpendicularWritingMode) const
3229 {
3230     if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode())
3231         return containingBlockLogicalWidthForPositioned(containingBlock, 0, false);
3232 
3233     // Use viewport as container for top-level fixed-position elements.
3234     if (style()->position() == FixedPosition && containingBlock->isRenderView()) {
3235         const RenderView* view = toRenderView(containingBlock);
3236         if (FrameView* frameView = view->frameView()) {
3237             LayoutRect viewportRect = frameView->viewportConstrainedVisibleContentRect();
3238             return containingBlock->isHorizontalWritingMode() ? viewportRect.height() : viewportRect.width();
3239         }
3240     }
3241 
3242     if (containingBlock->isBox()) {
3243         const RenderBlock* cb = toRenderBlock(containingBlock);
3244         LayoutUnit result = cb->clientLogicalHeight();
3245         RenderFlowThread* flowThread = flowThreadContainingBlock();
3246         if (flowThread && containingBlock->isRenderFlowThread() && flowThread->isHorizontalWritingMode() == containingBlock->isHorizontalWritingMode())
3247             return toRenderFlowThread(containingBlock)->contentLogicalHeightOfFirstRegion();
3248         return result;
3249     }
3250 
3251     ASSERT(containingBlock->isRenderInline() && containingBlock->isInFlowPositioned());
3252 
3253     const RenderInline* flow = toRenderInline(containingBlock);
3254     InlineFlowBox* first = flow->firstLineBox();
3255     InlineFlowBox* last = flow->lastLineBox();
3256 
3257     // If the containing block is empty, return a height of 0.
3258     if (!first || !last)
3259         return 0;
3260 
3261     LayoutUnit heightResult;
3262     LayoutRect boundingBox = flow->linesBoundingBox();
3263     if (containingBlock->isHorizontalWritingMode())
3264         heightResult = boundingBox.height();
3265     else
3266         heightResult = boundingBox.width();
3267     heightResult -= (containingBlock->borderBefore() + containingBlock->borderAfter());
3268     return heightResult;
3269 }
3270 
computeInlineStaticDistance(Length & logicalLeft,Length & logicalRight,const RenderBox * child,const RenderBoxModelObject * containerBlock,LayoutUnit containerLogicalWidth,RenderRegion * region)3271 static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRight, const RenderBox* child, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalWidth, RenderRegion* region)
3272 {
3273     if (!logicalLeft.isAuto() || !logicalRight.isAuto())
3274         return;
3275 
3276     // FIXME: The static distance computation has not been patched for mixed writing modes yet.
3277     if (child->parent()->style()->direction() == LTR) {
3278         LayoutUnit staticPosition = child->layer()->staticInlinePosition() - containerBlock->borderLogicalLeft();
3279         for (RenderObject* curr = child->parent(); curr && curr != containerBlock; curr = curr->container()) {
3280             if (curr->isBox()) {
3281                 staticPosition += toRenderBox(curr)->logicalLeft();
3282                 if (toRenderBox(curr)->isRelPositioned())
3283                     staticPosition += toRenderBox(curr)->relativePositionOffset().width();
3284                 if (region && curr->isRenderBlock()) {
3285                     const RenderBlock* cb = toRenderBlock(curr);
3286                     region = cb->clampToStartAndEndRegions(region);
3287                     RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(region);
3288                     if (boxInfo)
3289                         staticPosition += boxInfo->logicalLeft();
3290                 }
3291             } else if (curr->isInline()) {
3292                 if (curr->isRelPositioned()) {
3293                     if (!curr->style()->logicalLeft().isAuto())
3294                         staticPosition += curr->style()->logicalLeft().value();
3295                     else
3296                         staticPosition -= curr->style()->logicalRight().value();
3297                 }
3298             }
3299         }
3300         logicalLeft.setValue(Fixed, staticPosition);
3301     } else {
3302         RenderBox* enclosingBox = child->parent()->enclosingBox();
3303         LayoutUnit staticPosition = child->layer()->staticInlinePosition() + containerLogicalWidth + containerBlock->borderLogicalLeft();
3304         for (RenderObject* curr = child->parent(); curr; curr = curr->container()) {
3305             if (curr->isBox()) {
3306                 if (curr != containerBlock) {
3307                     staticPosition -= toRenderBox(curr)->logicalLeft();
3308                     if (toRenderBox(curr)->isRelPositioned())
3309                         staticPosition -= toRenderBox(curr)->relativePositionOffset().width();
3310                 }
3311                 if (curr == enclosingBox)
3312                     staticPosition -= enclosingBox->logicalWidth();
3313                 if (region && curr->isRenderBlock()) {
3314                     const RenderBlock* cb = toRenderBlock(curr);
3315                     region = cb->clampToStartAndEndRegions(region);
3316                     RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(region);
3317                     if (boxInfo) {
3318                         if (curr != containerBlock)
3319                             staticPosition -= cb->logicalWidth() - (boxInfo->logicalLeft() + boxInfo->logicalWidth());
3320                         if (curr == enclosingBox)
3321                             staticPosition += enclosingBox->logicalWidth() - boxInfo->logicalWidth();
3322                     }
3323                 }
3324             } else if (curr->isInline()) {
3325                 if (curr->isRelPositioned()) {
3326                     if (!curr->style()->logicalLeft().isAuto())
3327                         staticPosition -= curr->style()->logicalLeft().value();
3328                     else
3329                         staticPosition += curr->style()->logicalRight().value();
3330                 }
3331             }
3332             if (curr == containerBlock)
3333                 break;
3334         }
3335         logicalRight.setValue(Fixed, staticPosition);
3336     }
3337 }
3338 
computePositionedLogicalWidth(LogicalExtentComputedValues & computedValues,RenderRegion * region) const3339 void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& computedValues, RenderRegion* region) const
3340 {
3341     if (isReplaced()) {
3342         // FIXME: Positioned replaced elements inside a flow thread are not working properly
3343         // with variable width regions (see https://bugs.webkit.org/show_bug.cgi?id=69896 ).
3344         computePositionedLogicalWidthReplaced(computedValues);
3345         return;
3346     }
3347 
3348     // QUESTIONS
3349     // FIXME 1: Should we still deal with these the cases of 'left' or 'right' having
3350     // the type 'static' in determining whether to calculate the static distance?
3351     // NOTE: 'static' is not a legal value for 'left' or 'right' as of CSS 2.1.
3352 
3353     // FIXME 2: Can perhaps optimize out cases when max-width/min-width are greater
3354     // than or less than the computed width().  Be careful of box-sizing and
3355     // percentage issues.
3356 
3357     // The following is based off of the W3C Working Draft from April 11, 2006 of
3358     // CSS 2.1: Section 10.3.7 "Absolutely positioned, non-replaced elements"
3359     // <http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width>
3360     // (block-style-comments in this function and in computePositionedLogicalWidthUsing()
3361     // correspond to text from the spec)
3362 
3363 
3364     // We don't use containingBlock(), since we may be positioned by an enclosing
3365     // relative positioned inline.
3366     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
3367 
3368     const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, region);
3369 
3370     // Use the container block's direction except when calculating the static distance
3371     // This conforms with the reference results for abspos-replaced-width-margin-000.htm
3372     // of the CSS 2.1 test suite
3373     TextDirection containerDirection = containerBlock->style()->direction();
3374 
3375     bool isHorizontal = isHorizontalWritingMode();
3376     const LayoutUnit bordersPlusPadding = borderAndPaddingLogicalWidth();
3377     const Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop();
3378     const Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()->marginBottom();
3379 
3380     Length logicalLeftLength = style()->logicalLeft();
3381     Length logicalRightLength = style()->logicalRight();
3382 
3383     /*---------------------------------------------------------------------------*\
3384      * For the purposes of this section and the next, the term "static position"
3385      * (of an element) refers, roughly, to the position an element would have had
3386      * in the normal flow. More precisely:
3387      *
3388      * * The static position for 'left' is the distance from the left edge of the
3389      *   containing block to the left margin edge of a hypothetical box that would
3390      *   have been the first box of the element if its 'position' property had
3391      *   been 'static' and 'float' had been 'none'. The value is negative if the
3392      *   hypothetical box is to the left of the containing block.
3393      * * The static position for 'right' is the distance from the right edge of the
3394      *   containing block to the right margin edge of the same hypothetical box as
3395      *   above. The value is positive if the hypothetical box is to the left of the
3396      *   containing block's edge.
3397      *
3398      * But rather than actually calculating the dimensions of that hypothetical box,
3399      * user agents are free to make a guess at its probable position.
3400      *
3401      * For the purposes of calculating the static position, the containing block of
3402      * fixed positioned elements is the initial containing block instead of the
3403      * viewport, and all scrollable boxes should be assumed to be scrolled to their
3404      * origin.
3405     \*---------------------------------------------------------------------------*/
3406 
3407     // see FIXME 1
3408     // Calculate the static distance if needed.
3409     computeInlineStaticDistance(logicalLeftLength, logicalRightLength, this, containerBlock, containerLogicalWidth, region);
3410 
3411     // Calculate constraint equation values for 'width' case.
3412     computePositionedLogicalWidthUsing(style()->logicalWidth(), containerBlock, containerDirection,
3413                                        containerLogicalWidth, bordersPlusPadding,
3414                                        logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
3415                                        computedValues);
3416 
3417     // Calculate constraint equation values for 'max-width' case.
3418     if (!style()->logicalMaxWidth().isUndefined()) {
3419         LogicalExtentComputedValues maxValues;
3420 
3421         computePositionedLogicalWidthUsing(style()->logicalMaxWidth(), containerBlock, containerDirection,
3422                                            containerLogicalWidth, bordersPlusPadding,
3423                                            logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
3424                                            maxValues);
3425 
3426         if (computedValues.m_extent > maxValues.m_extent) {
3427             computedValues.m_extent = maxValues.m_extent;
3428             computedValues.m_position = maxValues.m_position;
3429             computedValues.m_margins.m_start = maxValues.m_margins.m_start;
3430             computedValues.m_margins.m_end = maxValues.m_margins.m_end;
3431         }
3432     }
3433 
3434     // Calculate constraint equation values for 'min-width' case.
3435     if (!style()->logicalMinWidth().isZero() || style()->logicalMinWidth().isIntrinsic()) {
3436         LogicalExtentComputedValues minValues;
3437 
3438         computePositionedLogicalWidthUsing(style()->logicalMinWidth(), containerBlock, containerDirection,
3439                                            containerLogicalWidth, bordersPlusPadding,
3440                                            logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
3441                                            minValues);
3442 
3443         if (computedValues.m_extent < minValues.m_extent) {
3444             computedValues.m_extent = minValues.m_extent;
3445             computedValues.m_position = minValues.m_position;
3446             computedValues.m_margins.m_start = minValues.m_margins.m_start;
3447             computedValues.m_margins.m_end = minValues.m_margins.m_end;
3448         }
3449     }
3450 
3451     computedValues.m_extent += bordersPlusPadding;
3452 
3453     // Adjust logicalLeft if we need to for the flipped version of our writing mode in regions.
3454     // FIXME: Add support for other types of objects as containerBlock, not only RenderBlock.
3455     RenderFlowThread* flowThread = flowThreadContainingBlock();
3456     if (flowThread && !region && isWritingModeRoot() && isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode() && containerBlock->isRenderBlock()) {
3457         ASSERT(containerBlock->canHaveBoxInfoInRegion());
3458         LayoutUnit logicalLeftPos = computedValues.m_position;
3459         const RenderBlock* cb = toRenderBlock(containerBlock);
3460         LayoutUnit cbPageOffset = cb->offsetFromLogicalTopOfFirstPage();
3461         RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset);
3462         if (cbRegion) {
3463             cbRegion = cb->clampToStartAndEndRegions(cbRegion);
3464             RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(cbRegion);
3465             if (boxInfo) {
3466                 logicalLeftPos += boxInfo->logicalLeft();
3467                 computedValues.m_position = logicalLeftPos;
3468             }
3469         }
3470     }
3471 }
3472 
computeLogicalLeftPositionedOffset(LayoutUnit & logicalLeftPos,const RenderBox * child,LayoutUnit logicalWidthValue,const RenderBoxModelObject * containerBlock,LayoutUnit containerLogicalWidth)3473 static void computeLogicalLeftPositionedOffset(LayoutUnit& logicalLeftPos, const RenderBox* child, LayoutUnit logicalWidthValue, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalWidth)
3474 {
3475     // Deal with differing writing modes here.  Our offset needs to be in the containing block's coordinate space. If the containing block is flipped
3476     // along this axis, then we need to flip the coordinate.  This can only happen if the containing block is both a flipped mode and perpendicular to us.
3477     if (containerBlock->isHorizontalWritingMode() != child->isHorizontalWritingMode() && containerBlock->style()->isFlippedBlocksWritingMode()) {
3478         logicalLeftPos = containerLogicalWidth - logicalWidthValue - logicalLeftPos;
3479         logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->borderRight() : containerBlock->borderBottom());
3480     } else
3481         logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->borderLeft() : containerBlock->borderTop());
3482 }
3483 
shrinkToFitWidth(const LayoutUnit availableSpace,const LayoutUnit logicalLeftValue,const LayoutUnit bordersPlusPadding,LogicalExtentComputedValues & computedValues) const3484 void RenderBox::shrinkToFitWidth(const LayoutUnit availableSpace, const LayoutUnit logicalLeftValue, const LayoutUnit bordersPlusPadding, LogicalExtentComputedValues& computedValues) const
3485 {
3486     // FIXME: would it be better to have shrink-to-fit in one step?
3487     LayoutUnit preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding;
3488     LayoutUnit preferredMinWidth = minPreferredLogicalWidth() - bordersPlusPadding;
3489     LayoutUnit availableWidth = availableSpace - logicalLeftValue;
3490     computedValues.m_extent = min(max(preferredMinWidth, availableWidth), preferredWidth);
3491 }
3492 
computePositionedLogicalWidthUsing(Length logicalWidth,const RenderBoxModelObject * containerBlock,TextDirection containerDirection,LayoutUnit containerLogicalWidth,LayoutUnit bordersPlusPadding,Length logicalLeft,Length logicalRight,Length marginLogicalLeft,Length marginLogicalRight,LogicalExtentComputedValues & computedValues) const3493 void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const RenderBoxModelObject* containerBlock, TextDirection containerDirection,
3494                                                    LayoutUnit containerLogicalWidth, LayoutUnit bordersPlusPadding,
3495                                                    Length logicalLeft, Length logicalRight, Length marginLogicalLeft, Length marginLogicalRight,
3496                                                    LogicalExtentComputedValues& computedValues) const
3497 {
3498     if (logicalWidth.isIntrinsic())
3499         logicalWidth = Length(computeIntrinsicLogicalWidthUsing(logicalWidth, containerLogicalWidth, bordersPlusPadding) - bordersPlusPadding, Fixed);
3500 
3501     // 'left' and 'right' cannot both be 'auto' because one would of been
3502     // converted to the static position already
3503     ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto()));
3504 
3505     LayoutUnit logicalLeftValue = 0;
3506 
3507     const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, 0, false);
3508 
3509     bool logicalWidthIsAuto = logicalWidth.isIntrinsicOrAuto();
3510     bool logicalLeftIsAuto = logicalLeft.isAuto();
3511     bool logicalRightIsAuto = logicalRight.isAuto();
3512     RenderView* renderView = view();
3513     LayoutUnit& marginLogicalLeftValue = style()->isLeftToRightDirection() ? computedValues.m_margins.m_start : computedValues.m_margins.m_end;
3514     LayoutUnit& marginLogicalRightValue = style()->isLeftToRightDirection() ? computedValues.m_margins.m_end : computedValues.m_margins.m_start;
3515     if (!logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) {
3516         /*-----------------------------------------------------------------------*\
3517          * If none of the three is 'auto': If both 'margin-left' and 'margin-
3518          * right' are 'auto', solve the equation under the extra constraint that
3519          * the two margins get equal values, unless this would make them negative,
3520          * in which case when direction of the containing block is 'ltr' ('rtl'),
3521          * set 'margin-left' ('margin-right') to zero and solve for 'margin-right'
3522          * ('margin-left'). If one of 'margin-left' or 'margin-right' is 'auto',
3523          * solve the equation for that value. If the values are over-constrained,
3524          * ignore the value for 'left' (in case the 'direction' property of the
3525          * containing block is 'rtl') or 'right' (in case 'direction' is 'ltr')
3526          * and solve for that value.
3527         \*-----------------------------------------------------------------------*/
3528         // NOTE:  It is not necessary to solve for 'right' in the over constrained
3529         // case because the value is not used for any further calculations.
3530 
3531         logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
3532         computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, containerLogicalWidth, renderView));
3533 
3534         const LayoutUnit availableSpace = containerLogicalWidth - (logicalLeftValue + computedValues.m_extent + valueForLength(logicalRight, containerLogicalWidth, renderView) + bordersPlusPadding);
3535 
3536         // Margins are now the only unknown
3537         if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) {
3538             // Both margins auto, solve for equality
3539             if (availableSpace >= 0) {
3540                 marginLogicalLeftValue = availableSpace / 2; // split the difference
3541                 marginLogicalRightValue = availableSpace - marginLogicalLeftValue; // account for odd valued differences
3542             } else {
3543                 // Use the containing block's direction rather than the parent block's
3544                 // per CSS 2.1 reference test abspos-non-replaced-width-margin-000.
3545                 if (containerDirection == LTR) {
3546                     marginLogicalLeftValue = 0;
3547                     marginLogicalRightValue = availableSpace; // will be negative
3548                 } else {
3549                     marginLogicalLeftValue = availableSpace; // will be negative
3550                     marginLogicalRightValue = 0;
3551                 }
3552             }
3553         } else if (marginLogicalLeft.isAuto()) {
3554             // Solve for left margin
3555             marginLogicalRightValue = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView);
3556             marginLogicalLeftValue = availableSpace - marginLogicalRightValue;
3557         } else if (marginLogicalRight.isAuto()) {
3558             // Solve for right margin
3559             marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView);
3560             marginLogicalRightValue = availableSpace - marginLogicalLeftValue;
3561         } else {
3562             // Over-constrained, solve for left if direction is RTL
3563             marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView);
3564             marginLogicalRightValue = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView);
3565 
3566             // Use the containing block's direction rather than the parent block's
3567             // per CSS 2.1 reference test abspos-non-replaced-width-margin-000.
3568             if (containerDirection == RTL)
3569                 logicalLeftValue = (availableSpace + logicalLeftValue) - marginLogicalLeftValue - marginLogicalRightValue;
3570         }
3571     } else {
3572         /*--------------------------------------------------------------------*\
3573          * Otherwise, set 'auto' values for 'margin-left' and 'margin-right'
3574          * to 0, and pick the one of the following six rules that applies.
3575          *
3576          * 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the
3577          *    width is shrink-to-fit. Then solve for 'left'
3578          *
3579          *              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
3580          * ------------------------------------------------------------------
3581          * 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if
3582          *    the 'direction' property of the containing block is 'ltr' set
3583          *    'left' to the static position, otherwise set 'right' to the
3584          *    static position. Then solve for 'left' (if 'direction is 'rtl')
3585          *    or 'right' (if 'direction' is 'ltr').
3586          * ------------------------------------------------------------------
3587          *
3588          * 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the
3589          *    width is shrink-to-fit . Then solve for 'right'
3590          * 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve
3591          *    for 'left'
3592          * 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve
3593          *    for 'width'
3594          * 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve
3595          *    for 'right'
3596          *
3597          * Calculation of the shrink-to-fit width is similar to calculating the
3598          * width of a table cell using the automatic table layout algorithm.
3599          * Roughly: calculate the preferred width by formatting the content
3600          * without breaking lines other than where explicit line breaks occur,
3601          * and also calculate the preferred minimum width, e.g., by trying all
3602          * possible line breaks. CSS 2.1 does not define the exact algorithm.
3603          * Thirdly, calculate the available width: this is found by solving
3604          * for 'width' after setting 'left' (in case 1) or 'right' (in case 3)
3605          * to 0.
3606          *
3607          * Then the shrink-to-fit width is:
3608          * min(max(preferred minimum width, available width), preferred width).
3609         \*--------------------------------------------------------------------*/
3610         // NOTE: For rules 3 and 6 it is not necessary to solve for 'right'
3611         // because the value is not used for any further calculations.
3612 
3613         // Calculate margins, 'auto' margins are ignored.
3614         marginLogicalLeftValue = minimumValueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView);
3615         marginLogicalRightValue = minimumValueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView);
3616 
3617         const LayoutUnit availableSpace = containerLogicalWidth - (marginLogicalLeftValue + marginLogicalRightValue + bordersPlusPadding);
3618 
3619         // FIXME: Is there a faster way to find the correct case?
3620         // Use rule/case that applies.
3621         if (logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) {
3622             // RULE 1: (use shrink-to-fit for width, and solve of left)
3623             LayoutUnit logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView);
3624 
3625             // FIXME: would it be better to have shrink-to-fit in one step?
3626             LayoutUnit preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding;
3627             LayoutUnit preferredMinWidth = minPreferredLogicalWidth() - bordersPlusPadding;
3628             LayoutUnit availableWidth = availableSpace - logicalRightValue;
3629             computedValues.m_extent = min(max(preferredMinWidth, availableWidth), preferredWidth);
3630             logicalLeftValue = availableSpace - (computedValues.m_extent + logicalRightValue);
3631         } else if (!logicalLeftIsAuto && logicalWidthIsAuto && logicalRightIsAuto) {
3632             // RULE 3: (use shrink-to-fit for width, and no need solve of right)
3633             logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
3634 
3635             shrinkToFitWidth(availableSpace, logicalLeftValue, bordersPlusPadding, computedValues);
3636         } else if (logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) {
3637             // RULE 4: (solve for left)
3638             computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, containerLogicalWidth, renderView));
3639             logicalLeftValue = availableSpace - (computedValues.m_extent + valueForLength(logicalRight, containerLogicalWidth, renderView));
3640         } else if (!logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) {
3641             // RULE 5: (solve for width)
3642             logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
3643             if (autoWidthShouldFitContent())
3644                 shrinkToFitWidth(availableSpace, logicalLeftValue, bordersPlusPadding, computedValues);
3645             else
3646                 computedValues.m_extent = availableSpace - (logicalLeftValue + valueForLength(logicalRight, containerLogicalWidth, renderView));
3647         } else if (!logicalLeftIsAuto && !logicalWidthIsAuto && logicalRightIsAuto) {
3648             // RULE 6: (no need solve for right)
3649             logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
3650             computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, containerLogicalWidth, renderView));
3651         }
3652     }
3653 
3654     // Use computed values to calculate the horizontal position.
3655 
3656     // FIXME: This hack is needed to calculate the  logical left position for a 'rtl' relatively
3657     // positioned, inline because right now, it is using the logical left position
3658     // of the first line box when really it should use the last line box.  When
3659     // this is fixed elsewhere, this block should be removed.
3660     if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRightDirection()) {
3661         const RenderInline* flow = toRenderInline(containerBlock);
3662         InlineFlowBox* firstLine = flow->firstLineBox();
3663         InlineFlowBox* lastLine = flow->lastLineBox();
3664         if (firstLine && lastLine && firstLine != lastLine) {
3665             computedValues.m_position = logicalLeftValue + marginLogicalLeftValue + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logicalLeft());
3666             return;
3667         }
3668     }
3669 
3670     if (containerBlock->isBox() && toRenderBox(containerBlock)->scrollsOverflowY() && containerBlock->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
3671         logicalLeftValue = logicalLeftValue + toRenderBox(containerBlock)->verticalScrollbarWidth();
3672     }
3673 
3674     computedValues.m_position = logicalLeftValue + marginLogicalLeftValue;
3675     computeLogicalLeftPositionedOffset(computedValues.m_position, this, computedValues.m_extent, containerBlock, containerLogicalWidth);
3676 }
3677 
computeBlockStaticDistance(Length & logicalTop,Length & logicalBottom,const RenderBox * child,const RenderBoxModelObject * containerBlock)3678 static void computeBlockStaticDistance(Length& logicalTop, Length& logicalBottom, const RenderBox* child, const RenderBoxModelObject* containerBlock)
3679 {
3680     if (!logicalTop.isAuto() || !logicalBottom.isAuto())
3681         return;
3682 
3683     // FIXME: The static distance computation has not been patched for mixed writing modes.
3684     LayoutUnit staticLogicalTop = child->layer()->staticBlockPosition() - containerBlock->borderBefore();
3685     for (RenderObject* curr = child->parent(); curr && curr != containerBlock; curr = curr->container()) {
3686         if (curr->isBox() && !curr->isTableRow())
3687             staticLogicalTop += toRenderBox(curr)->logicalTop();
3688     }
3689     logicalTop.setValue(Fixed, staticLogicalTop);
3690 }
3691 
computePositionedLogicalHeight(LogicalExtentComputedValues & computedValues) const3692 void RenderBox::computePositionedLogicalHeight(LogicalExtentComputedValues& computedValues) const
3693 {
3694     if (isReplaced()) {
3695         computePositionedLogicalHeightReplaced(computedValues);
3696         return;
3697     }
3698 
3699     // The following is based off of the W3C Working Draft from April 11, 2006 of
3700     // CSS 2.1: Section 10.6.4 "Absolutely positioned, non-replaced elements"
3701     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-non-replaced-height>
3702     // (block-style-comments in this function and in computePositionedLogicalHeightUsing()
3703     // correspond to text from the spec)
3704 
3705 
3706     // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
3707     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
3708 
3709     const LayoutUnit containerLogicalHeight = containingBlockLogicalHeightForPositioned(containerBlock);
3710 
3711     RenderStyle* styleToUse = style();
3712     const LayoutUnit bordersPlusPadding = borderAndPaddingLogicalHeight();
3713     const Length marginBefore = styleToUse->marginBefore();
3714     const Length marginAfter = styleToUse->marginAfter();
3715     Length logicalTopLength = styleToUse->logicalTop();
3716     Length logicalBottomLength = styleToUse->logicalBottom();
3717 
3718     /*---------------------------------------------------------------------------*\
3719      * For the purposes of this section and the next, the term "static position"
3720      * (of an element) refers, roughly, to the position an element would have had
3721      * in the normal flow. More precisely, the static position for 'top' is the
3722      * distance from the top edge of the containing block to the top margin edge
3723      * of a hypothetical box that would have been the first box of the element if
3724      * its 'position' property had been 'static' and 'float' had been 'none'. The
3725      * value is negative if the hypothetical box is above the containing block.
3726      *
3727      * But rather than actually calculating the dimensions of that hypothetical
3728      * box, user agents are free to make a guess at its probable position.
3729      *
3730      * For the purposes of calculating the static position, the containing block
3731      * of fixed positioned elements is the initial containing block instead of
3732      * the viewport.
3733     \*---------------------------------------------------------------------------*/
3734 
3735     // see FIXME 1
3736     // Calculate the static distance if needed.
3737     computeBlockStaticDistance(logicalTopLength, logicalBottomLength, this, containerBlock);
3738 
3739     // Calculate constraint equation values for 'height' case.
3740     LayoutUnit logicalHeight = computedValues.m_extent;
3741     computePositionedLogicalHeightUsing(styleToUse->logicalHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight,
3742                                         logicalTopLength, logicalBottomLength, marginBefore, marginAfter,
3743                                         computedValues);
3744 
3745     // Avoid doing any work in the common case (where the values of min-height and max-height are their defaults).
3746     // see FIXME 2
3747 
3748     // Calculate constraint equation values for 'max-height' case.
3749     if (!styleToUse->logicalMaxHeight().isUndefined()) {
3750         LogicalExtentComputedValues maxValues;
3751 
3752         computePositionedLogicalHeightUsing(styleToUse->logicalMaxHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight,
3753                                             logicalTopLength, logicalBottomLength, marginBefore, marginAfter,
3754                                             maxValues);
3755 
3756         if (computedValues.m_extent > maxValues.m_extent) {
3757             computedValues.m_extent = maxValues.m_extent;
3758             computedValues.m_position = maxValues.m_position;
3759             computedValues.m_margins.m_before = maxValues.m_margins.m_before;
3760             computedValues.m_margins.m_after = maxValues.m_margins.m_after;
3761         }
3762     }
3763 
3764     // Calculate constraint equation values for 'min-height' case.
3765     if (!styleToUse->logicalMinHeight().isZero() || styleToUse->logicalMinHeight().isIntrinsic()) {
3766         LogicalExtentComputedValues minValues;
3767 
3768         computePositionedLogicalHeightUsing(styleToUse->logicalMinHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight,
3769                                             logicalTopLength, logicalBottomLength, marginBefore, marginAfter,
3770                                             minValues);
3771 
3772         if (computedValues.m_extent < minValues.m_extent) {
3773             computedValues.m_extent = minValues.m_extent;
3774             computedValues.m_position = minValues.m_position;
3775             computedValues.m_margins.m_before = minValues.m_margins.m_before;
3776             computedValues.m_margins.m_after = minValues.m_margins.m_after;
3777         }
3778     }
3779 
3780     // Set final height value.
3781     computedValues.m_extent += bordersPlusPadding;
3782 
3783     // Adjust logicalTop if we need to for perpendicular writing modes in regions.
3784     // FIXME: Add support for other types of objects as containerBlock, not only RenderBlock.
3785     RenderFlowThread* flowThread = flowThreadContainingBlock();
3786     if (flowThread && isHorizontalWritingMode() != containerBlock->isHorizontalWritingMode() && containerBlock->isRenderBlock()) {
3787         ASSERT(containerBlock->canHaveBoxInfoInRegion());
3788         LayoutUnit logicalTopPos = computedValues.m_position;
3789         const RenderBlock* cb = toRenderBlock(containerBlock);
3790         LayoutUnit cbPageOffset = cb->offsetFromLogicalTopOfFirstPage() - logicalLeft();
3791         RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset);
3792         if (cbRegion) {
3793             cbRegion = cb->clampToStartAndEndRegions(cbRegion);
3794             RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(cbRegion);
3795             if (boxInfo) {
3796                 logicalTopPos += boxInfo->logicalLeft();
3797                 computedValues.m_position = logicalTopPos;
3798             }
3799         }
3800     }
3801 }
3802 
computeLogicalTopPositionedOffset(LayoutUnit & logicalTopPos,const RenderBox * child,LayoutUnit logicalHeightValue,const RenderBoxModelObject * containerBlock,LayoutUnit containerLogicalHeight)3803 static void computeLogicalTopPositionedOffset(LayoutUnit& logicalTopPos, const RenderBox* child, LayoutUnit logicalHeightValue, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalHeight)
3804 {
3805     // Deal with differing writing modes here.  Our offset needs to be in the containing block's coordinate space. If the containing block is flipped
3806     // along this axis, then we need to flip the coordinate.  This can only happen if the containing block is both a flipped mode and perpendicular to us.
3807     if ((child->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() != containerBlock->isHorizontalWritingMode())
3808         || (child->style()->isFlippedBlocksWritingMode() != containerBlock->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode()))
3809         logicalTopPos = containerLogicalHeight - logicalHeightValue - logicalTopPos;
3810 
3811     // Our offset is from the logical bottom edge in a flipped environment, e.g., right for vertical-rl and bottom for horizontal-bt.
3812     if (containerBlock->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode()) {
3813         if (child->isHorizontalWritingMode())
3814             logicalTopPos += containerBlock->borderBottom();
3815         else
3816             logicalTopPos += containerBlock->borderRight();
3817     } else {
3818         if (child->isHorizontalWritingMode())
3819             logicalTopPos += containerBlock->borderTop();
3820         else
3821             logicalTopPos += containerBlock->borderLeft();
3822     }
3823 }
3824 
computePositionedLogicalHeightUsing(Length logicalHeightLength,const RenderBoxModelObject * containerBlock,LayoutUnit containerLogicalHeight,LayoutUnit bordersPlusPadding,LayoutUnit logicalHeight,Length logicalTop,Length logicalBottom,Length marginBefore,Length marginAfter,LogicalExtentComputedValues & computedValues) const3825 void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength, const RenderBoxModelObject* containerBlock,
3826                                                     LayoutUnit containerLogicalHeight, LayoutUnit bordersPlusPadding, LayoutUnit logicalHeight,
3827                                                     Length logicalTop, Length logicalBottom, Length marginBefore, Length marginAfter,
3828                                                     LogicalExtentComputedValues& computedValues) const
3829 {
3830     // 'top' and 'bottom' cannot both be 'auto' because 'top would of been
3831     // converted to the static position in computePositionedLogicalHeight()
3832     ASSERT(!(logicalTop.isAuto() && logicalBottom.isAuto()));
3833 
3834     LayoutUnit logicalHeightValue;
3835     LayoutUnit contentLogicalHeight = logicalHeight - bordersPlusPadding;
3836 
3837     const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, 0, false);
3838 
3839     LayoutUnit logicalTopValue = 0;
3840 
3841     bool logicalHeightIsAuto = logicalHeightLength.isAuto();
3842     bool logicalTopIsAuto = logicalTop.isAuto();
3843     bool logicalBottomIsAuto = logicalBottom.isAuto();
3844     RenderView* renderView = view();
3845 
3846     LayoutUnit resolvedLogicalHeight;
3847     // Height is never unsolved for tables.
3848     if (isTable()) {
3849         resolvedLogicalHeight = contentLogicalHeight;
3850         logicalHeightIsAuto = false;
3851     } else {
3852         if (logicalHeightLength.isIntrinsic())
3853             resolvedLogicalHeight = computeIntrinsicLogicalContentHeightUsing(logicalHeightLength, contentLogicalHeight, bordersPlusPadding);
3854         else
3855             resolvedLogicalHeight = adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeightLength, containerLogicalHeight, renderView));
3856     }
3857 
3858     if (!logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) {
3859         /*-----------------------------------------------------------------------*\
3860          * If none of the three are 'auto': If both 'margin-top' and 'margin-
3861          * bottom' are 'auto', solve the equation under the extra constraint that
3862          * the two margins get equal values. If one of 'margin-top' or 'margin-
3863          * bottom' is 'auto', solve the equation for that value. If the values
3864          * are over-constrained, ignore the value for 'bottom' and solve for that
3865          * value.
3866         \*-----------------------------------------------------------------------*/
3867         // NOTE:  It is not necessary to solve for 'bottom' in the over constrained
3868         // case because the value is not used for any further calculations.
3869 
3870         logicalHeightValue = resolvedLogicalHeight;
3871         logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
3872 
3873         const LayoutUnit availableSpace = containerLogicalHeight - (logicalTopValue + logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight, renderView) + bordersPlusPadding);
3874 
3875         // Margins are now the only unknown
3876         if (marginBefore.isAuto() && marginAfter.isAuto()) {
3877             // Both margins auto, solve for equality
3878             // NOTE: This may result in negative values.
3879             computedValues.m_margins.m_before = availableSpace / 2; // split the difference
3880             computedValues.m_margins.m_after = availableSpace - computedValues.m_margins.m_before; // account for odd valued differences
3881         } else if (marginBefore.isAuto()) {
3882             // Solve for top margin
3883             computedValues.m_margins.m_after = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView);
3884             computedValues.m_margins.m_before = availableSpace - computedValues.m_margins.m_after;
3885         } else if (marginAfter.isAuto()) {
3886             // Solve for bottom margin
3887             computedValues.m_margins.m_before = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView);
3888             computedValues.m_margins.m_after = availableSpace - computedValues.m_margins.m_before;
3889         } else {
3890             // Over-constrained, (no need solve for bottom)
3891             computedValues.m_margins.m_before = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView);
3892             computedValues.m_margins.m_after = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView);
3893         }
3894     } else {
3895         /*--------------------------------------------------------------------*\
3896          * Otherwise, set 'auto' values for 'margin-top' and 'margin-bottom'
3897          * to 0, and pick the one of the following six rules that applies.
3898          *
3899          * 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then
3900          *    the height is based on the content, and solve for 'top'.
3901          *
3902          *              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
3903          * ------------------------------------------------------------------
3904          * 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then
3905          *    set 'top' to the static position, and solve for 'bottom'.
3906          * ------------------------------------------------------------------
3907          *
3908          * 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then
3909          *    the height is based on the content, and solve for 'bottom'.
3910          * 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', and
3911          *    solve for 'top'.
3912          * 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', and
3913          *    solve for 'height'.
3914          * 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', and
3915          *    solve for 'bottom'.
3916         \*--------------------------------------------------------------------*/
3917         // NOTE: For rules 3 and 6 it is not necessary to solve for 'bottom'
3918         // because the value is not used for any further calculations.
3919 
3920         // Calculate margins, 'auto' margins are ignored.
3921         computedValues.m_margins.m_before = minimumValueForLength(marginBefore, containerRelativeLogicalWidth, renderView);
3922         computedValues.m_margins.m_after = minimumValueForLength(marginAfter, containerRelativeLogicalWidth, renderView);
3923 
3924         const LayoutUnit availableSpace = containerLogicalHeight - (computedValues.m_margins.m_before + computedValues.m_margins.m_after + bordersPlusPadding);
3925 
3926         // Use rule/case that applies.
3927         if (logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) {
3928             // RULE 1: (height is content based, solve of top)
3929             logicalHeightValue = contentLogicalHeight;
3930             logicalTopValue = availableSpace - (logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight, renderView));
3931         } else if (!logicalTopIsAuto && logicalHeightIsAuto && logicalBottomIsAuto) {
3932             // RULE 3: (height is content based, no need solve of bottom)
3933             logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
3934             logicalHeightValue = contentLogicalHeight;
3935         } else if (logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) {
3936             // RULE 4: (solve of top)
3937             logicalHeightValue = resolvedLogicalHeight;
3938             logicalTopValue = availableSpace - (logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight, renderView));
3939         } else if (!logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) {
3940             // RULE 5: (solve of height)
3941             logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
3942             logicalHeightValue = max<LayoutUnit>(0, availableSpace - (logicalTopValue + valueForLength(logicalBottom, containerLogicalHeight, renderView)));
3943         } else if (!logicalTopIsAuto && !logicalHeightIsAuto && logicalBottomIsAuto) {
3944             // RULE 6: (no need solve of bottom)
3945             logicalHeightValue = resolvedLogicalHeight;
3946             logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
3947         }
3948     }
3949     computedValues.m_extent = logicalHeightValue;
3950 
3951     // Use computed values to calculate the vertical position.
3952     computedValues.m_position = logicalTopValue + computedValues.m_margins.m_before;
3953     computeLogicalTopPositionedOffset(computedValues.m_position, this, logicalHeightValue, containerBlock, containerLogicalHeight);
3954 }
3955 
computePositionedLogicalWidthReplaced(LogicalExtentComputedValues & computedValues) const3956 void RenderBox::computePositionedLogicalWidthReplaced(LogicalExtentComputedValues& computedValues) const
3957 {
3958     // The following is based off of the W3C Working Draft from April 11, 2006 of
3959     // CSS 2.1: Section 10.3.8 "Absolutely positioned, replaced elements"
3960     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-width>
3961     // (block-style-comments in this function correspond to text from the spec and
3962     // the numbers correspond to numbers in spec)
3963 
3964     // We don't use containingBlock(), since we may be positioned by an enclosing
3965     // relative positioned inline.
3966     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
3967 
3968     const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock);
3969     const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, 0, false);
3970 
3971     // To match WinIE, in quirks mode use the parent's 'direction' property
3972     // instead of the the container block's.
3973     TextDirection containerDirection = containerBlock->style()->direction();
3974 
3975     // Variables to solve.
3976     bool isHorizontal = isHorizontalWritingMode();
3977     Length logicalLeft = style()->logicalLeft();
3978     Length logicalRight = style()->logicalRight();
3979     Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop();
3980     Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()->marginBottom();
3981     LayoutUnit& marginLogicalLeftAlias = style()->isLeftToRightDirection() ? computedValues.m_margins.m_start : computedValues.m_margins.m_end;
3982     LayoutUnit& marginLogicalRightAlias = style()->isLeftToRightDirection() ? computedValues.m_margins.m_end : computedValues.m_margins.m_start;
3983 
3984     /*-----------------------------------------------------------------------*\
3985      * 1. The used value of 'width' is determined as for inline replaced
3986      *    elements.
3987     \*-----------------------------------------------------------------------*/
3988     // NOTE: This value of width is FINAL in that the min/max width calculations
3989     // are dealt with in computeReplacedWidth().  This means that the steps to produce
3990     // correct max/min in the non-replaced version, are not necessary.
3991     computedValues.m_extent = computeReplacedLogicalWidth() + borderAndPaddingLogicalWidth();
3992 
3993     const LayoutUnit availableSpace = containerLogicalWidth - computedValues.m_extent;
3994 
3995     /*-----------------------------------------------------------------------*\
3996      * 2. If both 'left' and 'right' have the value 'auto', then if 'direction'
3997      *    of the containing block is 'ltr', set 'left' to the static position;
3998      *    else if 'direction' is 'rtl', set 'right' to the static position.
3999     \*-----------------------------------------------------------------------*/
4000     // see FIXME 1
4001     computeInlineStaticDistance(logicalLeft, logicalRight, this, containerBlock, containerLogicalWidth, 0); // FIXME: Pass the region.
4002 
4003     /*-----------------------------------------------------------------------*\
4004      * 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left'
4005      *    or 'margin-right' with '0'.
4006     \*-----------------------------------------------------------------------*/
4007     if (logicalLeft.isAuto() || logicalRight.isAuto()) {
4008         if (marginLogicalLeft.isAuto())
4009             marginLogicalLeft.setValue(Fixed, 0);
4010         if (marginLogicalRight.isAuto())
4011             marginLogicalRight.setValue(Fixed, 0);
4012     }
4013 
4014     /*-----------------------------------------------------------------------*\
4015      * 4. If at this point both 'margin-left' and 'margin-right' are still
4016      *    'auto', solve the equation under the extra constraint that the two
4017      *    margins must get equal values, unless this would make them negative,
4018      *    in which case when the direction of the containing block is 'ltr'
4019      *    ('rtl'), set 'margin-left' ('margin-right') to zero and solve for
4020      *    'margin-right' ('margin-left').
4021     \*-----------------------------------------------------------------------*/
4022     LayoutUnit logicalLeftValue = 0;
4023     LayoutUnit logicalRightValue = 0;
4024     RenderView* renderView = view();
4025 
4026     if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) {
4027         // 'left' and 'right' cannot be 'auto' due to step 3
4028         ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto()));
4029 
4030         logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
4031         logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView);
4032 
4033         LayoutUnit difference = availableSpace - (logicalLeftValue + logicalRightValue);
4034         if (difference > 0) {
4035             marginLogicalLeftAlias = difference / 2; // split the difference
4036             marginLogicalRightAlias = difference - marginLogicalLeftAlias; // account for odd valued differences
4037         } else {
4038             // Use the containing block's direction rather than the parent block's
4039             // per CSS 2.1 reference test abspos-replaced-width-margin-000.
4040             if (containerDirection == LTR) {
4041                 marginLogicalLeftAlias = 0;
4042                 marginLogicalRightAlias = difference; // will be negative
4043             } else {
4044                 marginLogicalLeftAlias = difference; // will be negative
4045                 marginLogicalRightAlias = 0;
4046             }
4047         }
4048 
4049     /*-----------------------------------------------------------------------*\
4050      * 5. If at this point there is an 'auto' left, solve the equation for
4051      *    that value.
4052     \*-----------------------------------------------------------------------*/
4053     } else if (logicalLeft.isAuto()) {
4054         marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView);
4055         marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView);
4056         logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView);
4057 
4058         // Solve for 'left'
4059         logicalLeftValue = availableSpace - (logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias);
4060     } else if (logicalRight.isAuto()) {
4061         marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView);
4062         marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView);
4063         logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
4064 
4065         // Solve for 'right'
4066         logicalRightValue = availableSpace - (logicalLeftValue + marginLogicalLeftAlias + marginLogicalRightAlias);
4067     } else if (marginLogicalLeft.isAuto()) {
4068         marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView);
4069         logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
4070         logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView);
4071 
4072         // Solve for 'margin-left'
4073         marginLogicalLeftAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalRightAlias);
4074     } else if (marginLogicalRight.isAuto()) {
4075         marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView);
4076         logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
4077         logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView);
4078 
4079         // Solve for 'margin-right'
4080         marginLogicalRightAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalLeftAlias);
4081     } else {
4082         // Nothing is 'auto', just calculate the values.
4083         marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView);
4084         marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView);
4085         logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView);
4086         logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
4087         // If the containing block is right-to-left, then push the left position as far to the right as possible
4088         if (containerDirection == RTL) {
4089             int totalLogicalWidth = computedValues.m_extent + logicalLeftValue + logicalRightValue +  marginLogicalLeftAlias + marginLogicalRightAlias;
4090             logicalLeftValue = containerLogicalWidth - (totalLogicalWidth - logicalLeftValue);
4091         }
4092     }
4093 
4094     /*-----------------------------------------------------------------------*\
4095      * 6. If at this point the values are over-constrained, ignore the value
4096      *    for either 'left' (in case the 'direction' property of the
4097      *    containing block is 'rtl') or 'right' (in case 'direction' is
4098      *    'ltr') and solve for that value.
4099     \*-----------------------------------------------------------------------*/
4100     // NOTE: Constraints imposed by the width of the containing block and its content have already been accounted for above.
4101 
4102     // FIXME: Deal with differing writing modes here.  Our offset needs to be in the containing block's coordinate space, so that
4103     // can make the result here rather complicated to compute.
4104 
4105     // Use computed values to calculate the horizontal position.
4106 
4107     // FIXME: This hack is needed to calculate the logical left position for a 'rtl' relatively
4108     // positioned, inline containing block because right now, it is using the logical left position
4109     // of the first line box when really it should use the last line box.  When
4110     // this is fixed elsewhere, this block should be removed.
4111     if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRightDirection()) {
4112         const RenderInline* flow = toRenderInline(containerBlock);
4113         InlineFlowBox* firstLine = flow->firstLineBox();
4114         InlineFlowBox* lastLine = flow->lastLineBox();
4115         if (firstLine && lastLine && firstLine != lastLine) {
4116             computedValues.m_position = logicalLeftValue + marginLogicalLeftAlias + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logicalLeft());
4117             return;
4118         }
4119     }
4120 
4121     LayoutUnit logicalLeftPos = logicalLeftValue + marginLogicalLeftAlias;
4122     computeLogicalLeftPositionedOffset(logicalLeftPos, this, computedValues.m_extent, containerBlock, containerLogicalWidth);
4123     computedValues.m_position = logicalLeftPos;
4124 }
4125 
computePositionedLogicalHeightReplaced(LogicalExtentComputedValues & computedValues) const4126 void RenderBox::computePositionedLogicalHeightReplaced(LogicalExtentComputedValues& computedValues) const
4127 {
4128     // The following is based off of the W3C Working Draft from April 11, 2006 of
4129     // CSS 2.1: Section 10.6.5 "Absolutely positioned, replaced elements"
4130     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-height>
4131     // (block-style-comments in this function correspond to text from the spec and
4132     // the numbers correspond to numbers in spec)
4133 
4134     // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
4135     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
4136 
4137     const LayoutUnit containerLogicalHeight = containingBlockLogicalHeightForPositioned(containerBlock);
4138     const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, 0, false);
4139 
4140     // Variables to solve.
4141     Length marginBefore = style()->marginBefore();
4142     Length marginAfter = style()->marginAfter();
4143     LayoutUnit& marginBeforeAlias = computedValues.m_margins.m_before;
4144     LayoutUnit& marginAfterAlias = computedValues.m_margins.m_after;
4145 
4146     Length logicalTop = style()->logicalTop();
4147     Length logicalBottom = style()->logicalBottom();
4148     RenderView* renderView = view();
4149 
4150     /*-----------------------------------------------------------------------*\
4151      * 1. The used value of 'height' is determined as for inline replaced
4152      *    elements.
4153     \*-----------------------------------------------------------------------*/
4154     // NOTE: This value of height is FINAL in that the min/max height calculations
4155     // are dealt with in computeReplacedHeight().  This means that the steps to produce
4156     // correct max/min in the non-replaced version, are not necessary.
4157     computedValues.m_extent = computeReplacedLogicalHeight() + borderAndPaddingLogicalHeight();
4158     const LayoutUnit availableSpace = containerLogicalHeight - computedValues.m_extent;
4159 
4160     /*-----------------------------------------------------------------------*\
4161      * 2. If both 'top' and 'bottom' have the value 'auto', replace 'top'
4162      *    with the element's static position.
4163     \*-----------------------------------------------------------------------*/
4164     // see FIXME 1
4165     computeBlockStaticDistance(logicalTop, logicalBottom, this, containerBlock);
4166 
4167     /*-----------------------------------------------------------------------*\
4168      * 3. If 'bottom' is 'auto', replace any 'auto' on 'margin-top' or
4169      *    'margin-bottom' with '0'.
4170     \*-----------------------------------------------------------------------*/
4171     // FIXME: The spec. says that this step should only be taken when bottom is
4172     // auto, but if only top is auto, this makes step 4 impossible.
4173     if (logicalTop.isAuto() || logicalBottom.isAuto()) {
4174         if (marginBefore.isAuto())
4175             marginBefore.setValue(Fixed, 0);
4176         if (marginAfter.isAuto())
4177             marginAfter.setValue(Fixed, 0);
4178     }
4179 
4180     /*-----------------------------------------------------------------------*\
4181      * 4. If at this point both 'margin-top' and 'margin-bottom' are still
4182      *    'auto', solve the equation under the extra constraint that the two
4183      *    margins must get equal values.
4184     \*-----------------------------------------------------------------------*/
4185     LayoutUnit logicalTopValue = 0;
4186     LayoutUnit logicalBottomValue = 0;
4187 
4188     if (marginBefore.isAuto() && marginAfter.isAuto()) {
4189         // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combined.
4190         ASSERT(!(logicalTop.isAuto() || logicalBottom.isAuto()));
4191 
4192         logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
4193         logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView);
4194 
4195         LayoutUnit difference = availableSpace - (logicalTopValue + logicalBottomValue);
4196         // NOTE: This may result in negative values.
4197         marginBeforeAlias =  difference / 2; // split the difference
4198         marginAfterAlias = difference - marginBeforeAlias; // account for odd valued differences
4199 
4200     /*-----------------------------------------------------------------------*\
4201      * 5. If at this point there is only one 'auto' left, solve the equation
4202      *    for that value.
4203     \*-----------------------------------------------------------------------*/
4204     } else if (logicalTop.isAuto()) {
4205         marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView);
4206         marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView);
4207         logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView);
4208 
4209         // Solve for 'top'
4210         logicalTopValue = availableSpace - (logicalBottomValue + marginBeforeAlias + marginAfterAlias);
4211     } else if (logicalBottom.isAuto()) {
4212         marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView);
4213         marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView);
4214         logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
4215 
4216         // Solve for 'bottom'
4217         // NOTE: It is not necessary to solve for 'bottom' because we don't ever
4218         // use the value.
4219     } else if (marginBefore.isAuto()) {
4220         marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView);
4221         logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
4222         logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView);
4223 
4224         // Solve for 'margin-top'
4225         marginBeforeAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginAfterAlias);
4226     } else if (marginAfter.isAuto()) {
4227         marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView);
4228         logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
4229         logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView);
4230 
4231         // Solve for 'margin-bottom'
4232         marginAfterAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginBeforeAlias);
4233     } else {
4234         // Nothing is 'auto', just calculate the values.
4235         marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView);
4236         marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView);
4237         logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
4238         // NOTE: It is not necessary to solve for 'bottom' because we don't ever
4239         // use the value.
4240      }
4241 
4242     /*-----------------------------------------------------------------------*\
4243      * 6. If at this point the values are over-constrained, ignore the value
4244      *    for 'bottom' and solve for that value.
4245     \*-----------------------------------------------------------------------*/
4246     // NOTE: It is not necessary to do this step because we don't end up using
4247     // the value of 'bottom' regardless of whether the values are over-constrained
4248     // or not.
4249 
4250     // Use computed values to calculate the vertical position.
4251     LayoutUnit logicalTopPos = logicalTopValue + marginBeforeAlias;
4252     computeLogicalTopPositionedOffset(logicalTopPos, this, computedValues.m_extent, containerBlock, containerLogicalHeight);
4253     computedValues.m_position = logicalTopPos;
4254 }
4255 
localCaretRect(InlineBox * box,int caretOffset,LayoutUnit * extraWidthToEndOfLine)4256 LayoutRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, LayoutUnit* extraWidthToEndOfLine)
4257 {
4258     // VisiblePositions at offsets inside containers either a) refer to the positions before/after
4259     // those containers (tables and select elements) or b) refer to the position inside an empty block.
4260     // They never refer to children.
4261     // FIXME: Paint the carets inside empty blocks differently than the carets before/after elements.
4262 
4263     LayoutRect rect(location(), LayoutSize(caretWidth, height()));
4264     bool ltr = box ? box->isLeftToRightDirection() : style()->isLeftToRightDirection();
4265 
4266     if ((!caretOffset) ^ ltr)
4267         rect.move(LayoutSize(width() - caretWidth, 0));
4268 
4269     if (box) {
4270         RootInlineBox* rootBox = box->root();
4271         LayoutUnit top = rootBox->lineTop();
4272         rect.setY(top);
4273         rect.setHeight(rootBox->lineBottom() - top);
4274     }
4275 
4276     // If height of box is smaller than font height, use the latter one,
4277     // otherwise the caret might become invisible.
4278     //
4279     // Also, if the box is not a replaced element, always use the font height.
4280     // This prevents the "big caret" bug described in:
4281     // <rdar://problem/3777804> Deleting all content in a document can result in giant tall-as-window insertion point
4282     //
4283     // FIXME: ignoring :first-line, missing good reason to take care of
4284     LayoutUnit fontHeight = style()->fontMetrics().height();
4285     if (fontHeight > rect.height() || (!isReplaced() && !isTable()))
4286         rect.setHeight(fontHeight);
4287 
4288     if (extraWidthToEndOfLine)
4289         *extraWidthToEndOfLine = x() + width() - rect.maxX();
4290 
4291     // Move to local coords
4292     rect.moveBy(-location());
4293 
4294     // FIXME: Border/padding should be added for all elements but this workaround
4295     // is needed because we use offsets inside an "atomic" element to represent
4296     // positions before and after the element in deprecated editing offsets.
4297     if (node() && !(editingIgnoresContent(node()) || isRenderedTable(node()))) {
4298         rect.setX(rect.x() + borderLeft() + paddingLeft());
4299         rect.setY(rect.y() + paddingTop() + borderTop());
4300     }
4301 
4302     if (!isHorizontalWritingMode())
4303         return rect.transposedRect();
4304 
4305     return rect;
4306 }
4307 
positionForPoint(const LayoutPoint & point)4308 PositionWithAffinity RenderBox::positionForPoint(const LayoutPoint& point)
4309 {
4310     // no children...return this render object's element, if there is one, and offset 0
4311     if (!firstChild())
4312         return createPositionWithAffinity(nonPseudoNode() ? firstPositionInOrBeforeNode(nonPseudoNode()) : Position());
4313 
4314     if (isTable() && nonPseudoNode()) {
4315         LayoutUnit right = contentWidth() + borderAndPaddingWidth();
4316         LayoutUnit bottom = contentHeight() + borderAndPaddingHeight();
4317 
4318         if (point.x() < 0 || point.x() > right || point.y() < 0 || point.y() > bottom) {
4319             if (point.x() <= right / 2)
4320                 return createPositionWithAffinity(firstPositionInOrBeforeNode(nonPseudoNode()));
4321             return createPositionWithAffinity(lastPositionInOrAfterNode(nonPseudoNode()));
4322         }
4323     }
4324 
4325     // Pass off to the closest child.
4326     LayoutUnit minDist = LayoutUnit::max();
4327     RenderBox* closestRenderer = 0;
4328     LayoutPoint adjustedPoint = point;
4329     if (isTableRow())
4330         adjustedPoint.moveBy(location());
4331 
4332     for (RenderObject* renderObject = firstChild(); renderObject; renderObject = renderObject->nextSibling()) {
4333         if ((!renderObject->firstChild() && !renderObject->isInline() && !renderObject->isRenderBlockFlow() )
4334             || renderObject->style()->visibility() != VISIBLE)
4335             continue;
4336 
4337         if (!renderObject->isBox())
4338             continue;
4339 
4340         RenderBox* renderer = toRenderBox(renderObject);
4341 
4342         LayoutUnit top = renderer->borderTop() + renderer->paddingTop() + (isTableRow() ? LayoutUnit() : renderer->y());
4343         LayoutUnit bottom = top + renderer->contentHeight();
4344         LayoutUnit left = renderer->borderLeft() + renderer->paddingLeft() + (isTableRow() ? LayoutUnit() : renderer->x());
4345         LayoutUnit right = left + renderer->contentWidth();
4346 
4347         if (point.x() <= right && point.x() >= left && point.y() <= top && point.y() >= bottom) {
4348             if (renderer->isTableRow())
4349                 return renderer->positionForPoint(point + adjustedPoint - renderer->locationOffset());
4350             return renderer->positionForPoint(point - renderer->locationOffset());
4351         }
4352 
4353         // Find the distance from (x, y) to the box.  Split the space around the box into 8 pieces
4354         // and use a different compare depending on which piece (x, y) is in.
4355         LayoutPoint cmp;
4356         if (point.x() > right) {
4357             if (point.y() < top)
4358                 cmp = LayoutPoint(right, top);
4359             else if (point.y() > bottom)
4360                 cmp = LayoutPoint(right, bottom);
4361             else
4362                 cmp = LayoutPoint(right, point.y());
4363         } else if (point.x() < left) {
4364             if (point.y() < top)
4365                 cmp = LayoutPoint(left, top);
4366             else if (point.y() > bottom)
4367                 cmp = LayoutPoint(left, bottom);
4368             else
4369                 cmp = LayoutPoint(left, point.y());
4370         } else {
4371             if (point.y() < top)
4372                 cmp = LayoutPoint(point.x(), top);
4373             else
4374                 cmp = LayoutPoint(point.x(), bottom);
4375         }
4376 
4377         LayoutSize difference = cmp - point;
4378 
4379         LayoutUnit dist = difference.width() * difference.width() + difference.height() * difference.height();
4380         if (dist < minDist) {
4381             closestRenderer = renderer;
4382             minDist = dist;
4383         }
4384     }
4385 
4386     if (closestRenderer)
4387         return closestRenderer->positionForPoint(adjustedPoint - closestRenderer->locationOffset());
4388     return createPositionWithAffinity(firstPositionInOrBeforeNode(nonPseudoNode()));
4389 }
4390 
shrinkToAvoidFloats() const4391 bool RenderBox::shrinkToAvoidFloats() const
4392 {
4393     // Floating objects don't shrink.  Objects that don't avoid floats don't shrink.  Marquees don't shrink.
4394     if ((isInline() && !isMarquee()) || !avoidsFloats() || isFloating())
4395         return false;
4396 
4397     // Only auto width objects can possibly shrink to avoid floats.
4398     return style()->width().isAuto();
4399 }
4400 
avoidsFloats() const4401 bool RenderBox::avoidsFloats() const
4402 {
4403     return isReplaced() || hasOverflowClip() || isHR() || isLegend() || isWritingModeRoot() || isFlexItemIncludingDeprecated();
4404 }
4405 
addVisualEffectOverflow()4406 void RenderBox::addVisualEffectOverflow()
4407 {
4408     if (!style()->boxShadow() && !style()->hasBorderImageOutsets())
4409         return;
4410 
4411     bool isFlipped = style()->isFlippedBlocksWritingMode();
4412     bool isHorizontal = isHorizontalWritingMode();
4413 
4414     LayoutRect borderBox = borderBoxRect();
4415     LayoutUnit overflowMinX = borderBox.x();
4416     LayoutUnit overflowMaxX = borderBox.maxX();
4417     LayoutUnit overflowMinY = borderBox.y();
4418     LayoutUnit overflowMaxY = borderBox.maxY();
4419 
4420     // Compute box-shadow overflow first.
4421     if (style()->boxShadow()) {
4422         LayoutUnit shadowLeft;
4423         LayoutUnit shadowRight;
4424         LayoutUnit shadowTop;
4425         LayoutUnit shadowBottom;
4426         style()->getBoxShadowExtent(shadowTop, shadowRight, shadowBottom, shadowLeft);
4427 
4428         // In flipped blocks writing modes such as vertical-rl, the physical right shadow value is actually at the lower x-coordinate.
4429         overflowMinX = borderBox.x() + ((!isFlipped || isHorizontal) ? shadowLeft : -shadowRight);
4430         overflowMaxX = borderBox.maxX() + ((!isFlipped || isHorizontal) ? shadowRight : -shadowLeft);
4431         overflowMinY = borderBox.y() + ((!isFlipped || !isHorizontal) ? shadowTop : -shadowBottom);
4432         overflowMaxY = borderBox.maxY() + ((!isFlipped || !isHorizontal) ? shadowBottom : -shadowTop);
4433     }
4434 
4435     // Now compute border-image-outset overflow.
4436     if (style()->hasBorderImageOutsets()) {
4437         LayoutBoxExtent borderOutsets = style()->borderImageOutsets();
4438 
4439         // In flipped blocks writing modes, the physical sides are inverted. For example in vertical-rl, the right
4440         // border is at the lower x coordinate value.
4441         overflowMinX = min(overflowMinX, borderBox.x() - ((!isFlipped || isHorizontal) ? borderOutsets.left() : borderOutsets.right()));
4442         overflowMaxX = max(overflowMaxX, borderBox.maxX() + ((!isFlipped || isHorizontal) ? borderOutsets.right() : borderOutsets.left()));
4443         overflowMinY = min(overflowMinY, borderBox.y() - ((!isFlipped || !isHorizontal) ? borderOutsets.top() : borderOutsets.bottom()));
4444         overflowMaxY = max(overflowMaxY, borderBox.maxY() + ((!isFlipped || !isHorizontal) ? borderOutsets.bottom() : borderOutsets.top()));
4445     }
4446 
4447     // Add in the final overflow with shadows and outsets combined.
4448     LayoutRect visualEffectOverflow(overflowMinX, overflowMinY, overflowMaxX - overflowMinX, overflowMaxY - overflowMinY);
4449     addVisualOverflow(visualEffectOverflow);
4450 }
4451 
addOverflowFromChild(RenderBox * child,const LayoutSize & delta)4452 void RenderBox::addOverflowFromChild(RenderBox* child, const LayoutSize& delta)
4453 {
4454     // Never allow flow threads to propagate overflow up to a parent.
4455     if (child->isRenderFlowThread())
4456         return;
4457 
4458     // Only propagate layout overflow from the child if the child isn't clipping its overflow.  If it is, then
4459     // its overflow is internal to it, and we don't care about it.  layoutOverflowRectForPropagation takes care of this
4460     // and just propagates the border box rect instead.
4461     LayoutRect childLayoutOverflowRect = child->layoutOverflowRectForPropagation(style());
4462     childLayoutOverflowRect.move(delta);
4463     addLayoutOverflow(childLayoutOverflowRect);
4464 
4465     // Add in visual overflow from the child.  Even if the child clips its overflow, it may still
4466     // have visual overflow of its own set from box shadows or reflections.  It is unnecessary to propagate this
4467     // overflow if we are clipping our own overflow.
4468     if (child->hasSelfPaintingLayer())
4469         return;
4470     LayoutRect childVisualOverflowRect = child->visualOverflowRectForPropagation(style());
4471     childVisualOverflowRect.move(delta);
4472     addContentsVisualOverflow(childVisualOverflowRect);
4473 }
4474 
addLayoutOverflow(const LayoutRect & rect)4475 void RenderBox::addLayoutOverflow(const LayoutRect& rect)
4476 {
4477     LayoutRect clientBox = noOverflowRect();
4478     if (clientBox.contains(rect) || rect.isEmpty())
4479         return;
4480 
4481     // For overflow clip objects, we don't want to propagate overflow into unreachable areas.
4482     LayoutRect overflowRect(rect);
4483     if (hasOverflowClip() || isRenderView()) {
4484         // Overflow is in the block's coordinate space and thus is flipped for horizontal-bt and vertical-rl
4485         // writing modes.  At this stage that is actually a simplification, since we can treat horizontal-tb/bt as the same
4486         // and vertical-lr/rl as the same.
4487         bool hasTopOverflow = !style()->isLeftToRightDirection() && !isHorizontalWritingMode();
4488         bool hasLeftOverflow = !style()->isLeftToRightDirection() && isHorizontalWritingMode();
4489         if (isFlexibleBox() && style()->isReverseFlexDirection()) {
4490             RenderFlexibleBox* flexibleBox = toRenderFlexibleBox(this);
4491             if (flexibleBox->isHorizontalFlow())
4492                 hasLeftOverflow = true;
4493             else
4494                 hasTopOverflow = true;
4495         }
4496 
4497         if (hasColumns() && style()->columnProgression() == ReverseColumnProgression) {
4498             if (isHorizontalWritingMode() ^ !style()->hasInlineColumnAxis())
4499                 hasLeftOverflow = !hasLeftOverflow;
4500             else
4501                 hasTopOverflow = !hasTopOverflow;
4502         }
4503 
4504         if (!hasTopOverflow)
4505             overflowRect.shiftYEdgeTo(max(overflowRect.y(), clientBox.y()));
4506         else
4507             overflowRect.shiftMaxYEdgeTo(min(overflowRect.maxY(), clientBox.maxY()));
4508         if (!hasLeftOverflow)
4509             overflowRect.shiftXEdgeTo(max(overflowRect.x(), clientBox.x()));
4510         else
4511             overflowRect.shiftMaxXEdgeTo(min(overflowRect.maxX(), clientBox.maxX()));
4512 
4513         // Now re-test with the adjusted rectangle and see if it has become unreachable or fully
4514         // contained.
4515         if (clientBox.contains(overflowRect) || overflowRect.isEmpty())
4516             return;
4517     }
4518 
4519     if (!m_overflow)
4520         m_overflow = adoptPtr(new RenderOverflow(clientBox, borderBoxRect()));
4521 
4522     m_overflow->addLayoutOverflow(overflowRect);
4523 }
4524 
addVisualOverflow(const LayoutRect & rect)4525 void RenderBox::addVisualOverflow(const LayoutRect& rect)
4526 {
4527     LayoutRect borderBox = borderBoxRect();
4528     if (borderBox.contains(rect) || rect.isEmpty())
4529         return;
4530 
4531     if (!m_overflow)
4532         m_overflow = adoptPtr(new RenderOverflow(noOverflowRect(), borderBox));
4533 
4534     m_overflow->addVisualOverflow(rect);
4535 }
4536 
addContentsVisualOverflow(const LayoutRect & rect)4537 void RenderBox::addContentsVisualOverflow(const LayoutRect& rect)
4538 {
4539     if (!hasOverflowClip()) {
4540         addVisualOverflow(rect);
4541         return;
4542     }
4543 
4544     if (!m_overflow)
4545         m_overflow = adoptPtr(new RenderOverflow(clientBoxRect(), borderBoxRect()));
4546     m_overflow->addContentsVisualOverflow(rect);
4547 }
4548 
clearLayoutOverflow()4549 void RenderBox::clearLayoutOverflow()
4550 {
4551     if (!m_overflow)
4552         return;
4553 
4554     if (!hasVisualOverflow() && contentsVisualOverflowRect().isEmpty()) {
4555         m_overflow.clear();
4556         return;
4557     }
4558 
4559     m_overflow->setLayoutOverflow(noOverflowRect());
4560 }
4561 
percentageLogicalHeightIsResolvable(const RenderBox * box)4562 inline static bool percentageLogicalHeightIsResolvable(const RenderBox* box)
4563 {
4564     return RenderBox::percentageLogicalHeightIsResolvableFromBlock(box->containingBlock(), box->isOutOfFlowPositioned());
4565 }
4566 
percentageLogicalHeightIsResolvableFromBlock(const RenderBlock * containingBlock,bool isOutOfFlowPositioned)4567 bool RenderBox::percentageLogicalHeightIsResolvableFromBlock(const RenderBlock* containingBlock, bool isOutOfFlowPositioned)
4568 {
4569     // In quirks mode, blocks with auto height are skipped, and we keep looking for an enclosing
4570     // block that may have a specified height and then use it. In strict mode, this violates the
4571     // specification, which states that percentage heights just revert to auto if the containing
4572     // block has an auto height. We still skip anonymous containing blocks in both modes, though, and look
4573     // only at explicit containers.
4574     const RenderBlock* cb = containingBlock;
4575     bool inQuirksMode = cb->document().inQuirksMode();
4576     while (!cb->isRenderView() && !cb->isBody() && !cb->isTableCell() && !cb->isOutOfFlowPositioned() && cb->style()->logicalHeight().isAuto()) {
4577         if (!inQuirksMode && !cb->isAnonymousBlock())
4578             break;
4579         cb = cb->containingBlock();
4580     }
4581 
4582     // A positioned element that specified both top/bottom or that specifies height should be treated as though it has a height
4583     // explicitly specified that can be used for any percentage computations.
4584     // FIXME: We can't just check top/bottom here.
4585     // https://bugs.webkit.org/show_bug.cgi?id=46500
4586     bool isOutOfFlowPositionedWithSpecifiedHeight = cb->isOutOfFlowPositioned() && (!cb->style()->logicalHeight().isAuto() || (!cb->style()->top().isAuto() && !cb->style()->bottom().isAuto()));
4587 
4588     // Table cells violate what the CSS spec says to do with heights.  Basically we
4589     // don't care if the cell specified a height or not.  We just always make ourselves
4590     // be a percentage of the cell's current content height.
4591     if (cb->isTableCell())
4592         return true;
4593 
4594     // Otherwise we only use our percentage height if our containing block had a specified
4595     // height.
4596     if (cb->style()->logicalHeight().isFixed())
4597         return true;
4598     if (cb->style()->logicalHeight().isPercent() && !isOutOfFlowPositionedWithSpecifiedHeight)
4599         return percentageLogicalHeightIsResolvableFromBlock(cb->containingBlock(), cb->isOutOfFlowPositioned());
4600     if (cb->isRenderView() || inQuirksMode || isOutOfFlowPositionedWithSpecifiedHeight)
4601         return true;
4602     if (cb->isRoot() && isOutOfFlowPositioned) {
4603         // Match the positioned objects behavior, which is that positioned objects will fill their viewport
4604         // always.  Note we could only hit this case by recurring into computePercentageLogicalHeight on a positioned containing block.
4605         return true;
4606     }
4607 
4608     return false;
4609 }
4610 
hasUnsplittableScrollingOverflow() const4611 bool RenderBox::hasUnsplittableScrollingOverflow() const
4612 {
4613     // We will paginate as long as we don't scroll overflow in the pagination direction.
4614     bool isHorizontal = isHorizontalWritingMode();
4615     if ((isHorizontal && !scrollsOverflowY()) || (!isHorizontal && !scrollsOverflowX()))
4616         return false;
4617 
4618     // We do have overflow. We'll still be willing to paginate as long as the block
4619     // has auto logical height, auto or undefined max-logical-height and a zero or auto min-logical-height.
4620     // Note this is just a heuristic, and it's still possible to have overflow under these
4621     // conditions, but it should work out to be good enough for common cases. Paginating overflow
4622     // with scrollbars present is not the end of the world and is what we used to do in the old model anyway.
4623     return !style()->logicalHeight().isIntrinsicOrAuto()
4624         || (!style()->logicalMaxHeight().isIntrinsicOrAuto() && !style()->logicalMaxHeight().isUndefined() && (!style()->logicalMaxHeight().isPercent() || percentageLogicalHeightIsResolvable(this)))
4625         || (!style()->logicalMinHeight().isIntrinsicOrAuto() && style()->logicalMinHeight().isPositive() && (!style()->logicalMinHeight().isPercent() || percentageLogicalHeightIsResolvable(this)));
4626 }
4627 
isUnsplittableForPagination() const4628 bool RenderBox::isUnsplittableForPagination() const
4629 {
4630     return isReplaced() || hasUnsplittableScrollingOverflow() || (parent() && isWritingModeRoot());
4631 }
4632 
lineHeight(bool,LineDirectionMode direction,LinePositionMode) const4633 LayoutUnit RenderBox::lineHeight(bool /*firstLine*/, LineDirectionMode direction, LinePositionMode /*linePositionMode*/) const
4634 {
4635     if (isReplaced())
4636         return direction == HorizontalLine ? m_marginBox.top() + height() + m_marginBox.bottom() : m_marginBox.right() + width() + m_marginBox.left();
4637     return 0;
4638 }
4639 
baselinePosition(FontBaseline baselineType,bool,LineDirectionMode direction,LinePositionMode linePositionMode) const4640 int RenderBox::baselinePosition(FontBaseline baselineType, bool /*firstLine*/, LineDirectionMode direction, LinePositionMode linePositionMode) const
4641 {
4642     ASSERT(linePositionMode == PositionOnContainingLine);
4643     if (isReplaced()) {
4644         int result = direction == HorizontalLine ? m_marginBox.top() + height() + m_marginBox.bottom() : m_marginBox.right() + width() + m_marginBox.left();
4645         if (baselineType == AlphabeticBaseline)
4646             return result;
4647         return result - result / 2;
4648     }
4649     return 0;
4650 }
4651 
4652 
enclosingFloatPaintingLayer() const4653 RenderLayer* RenderBox::enclosingFloatPaintingLayer() const
4654 {
4655     const RenderObject* curr = this;
4656     while (curr) {
4657         RenderLayer* layer = curr->hasLayer() && curr->isBox() ? toRenderBox(curr)->layer() : 0;
4658         if (layer && layer->isSelfPaintingLayer())
4659             return layer;
4660         curr = curr->parent();
4661     }
4662     return 0;
4663 }
4664 
logicalVisualOverflowRectForPropagation(RenderStyle * parentStyle) const4665 LayoutRect RenderBox::logicalVisualOverflowRectForPropagation(RenderStyle* parentStyle) const
4666 {
4667     LayoutRect rect = visualOverflowRectForPropagation(parentStyle);
4668     if (!parentStyle->isHorizontalWritingMode())
4669         return rect.transposedRect();
4670     return rect;
4671 }
4672 
visualOverflowRectForPropagation(RenderStyle * parentStyle) const4673 LayoutRect RenderBox::visualOverflowRectForPropagation(RenderStyle* parentStyle) const
4674 {
4675     // If the writing modes of the child and parent match, then we don't have to
4676     // do anything fancy. Just return the result.
4677     LayoutRect rect = visualOverflowRect();
4678     if (parentStyle->writingMode() == style()->writingMode())
4679         return rect;
4680 
4681     // We are putting ourselves into our parent's coordinate space.  If there is a flipped block mismatch
4682     // in a particular axis, then we have to flip the rect along that axis.
4683     if (style()->writingMode() == RightToLeftWritingMode || parentStyle->writingMode() == RightToLeftWritingMode)
4684         rect.setX(width() - rect.maxX());
4685     else if (style()->writingMode() == BottomToTopWritingMode || parentStyle->writingMode() == BottomToTopWritingMode)
4686         rect.setY(height() - rect.maxY());
4687 
4688     return rect;
4689 }
4690 
logicalLayoutOverflowRectForPropagation(RenderStyle * parentStyle) const4691 LayoutRect RenderBox::logicalLayoutOverflowRectForPropagation(RenderStyle* parentStyle) const
4692 {
4693     LayoutRect rect = layoutOverflowRectForPropagation(parentStyle);
4694     if (!parentStyle->isHorizontalWritingMode())
4695         return rect.transposedRect();
4696     return rect;
4697 }
4698 
layoutOverflowRectForPropagation(RenderStyle * parentStyle) const4699 LayoutRect RenderBox::layoutOverflowRectForPropagation(RenderStyle* parentStyle) const
4700 {
4701     // Only propagate interior layout overflow if we don't clip it.
4702     LayoutRect rect = borderBoxRect();
4703     // We want to include the margin, but only when it adds height. Quirky margins don't contribute height
4704     // nor do the margins of self-collapsing blocks.
4705     if (!style()->hasMarginAfterQuirk() && !isSelfCollapsingBlock())
4706         rect.expand(isHorizontalWritingMode() ? LayoutSize(LayoutUnit(), marginAfter()) : LayoutSize(marginAfter(), LayoutUnit()));
4707 
4708     if (!hasOverflowClip())
4709         rect.unite(layoutOverflowRect());
4710 
4711     bool hasTransform = hasLayer() && layer()->transform();
4712     if (isInFlowPositioned() || hasTransform) {
4713         // If we are relatively positioned or if we have a transform, then we have to convert
4714         // this rectangle into physical coordinates, apply relative positioning and transforms
4715         // to it, and then convert it back.
4716         flipForWritingMode(rect);
4717 
4718         if (hasTransform)
4719             rect = layer()->currentTransform().mapRect(rect);
4720 
4721         if (isInFlowPositioned())
4722             rect.move(offsetForInFlowPosition());
4723 
4724         // Now we need to flip back.
4725         flipForWritingMode(rect);
4726     }
4727 
4728     // If the writing modes of the child and parent match, then we don't have to
4729     // do anything fancy. Just return the result.
4730     if (parentStyle->writingMode() == style()->writingMode())
4731         return rect;
4732 
4733     // We are putting ourselves into our parent's coordinate space.  If there is a flipped block mismatch
4734     // in a particular axis, then we have to flip the rect along that axis.
4735     if (style()->writingMode() == RightToLeftWritingMode || parentStyle->writingMode() == RightToLeftWritingMode)
4736         rect.setX(width() - rect.maxX());
4737     else if (style()->writingMode() == BottomToTopWritingMode || parentStyle->writingMode() == BottomToTopWritingMode)
4738         rect.setY(height() - rect.maxY());
4739 
4740     return rect;
4741 }
4742 
noOverflowRect() const4743 LayoutRect RenderBox::noOverflowRect() const
4744 {
4745     // Because of the special coodinate system used for overflow rectangles and many other
4746     // rectangles (not quite logical, not quite physical), we need to flip the block progression
4747     // coordinate in vertical-rl and horizontal-bt writing modes. In other words, the rectangle
4748     // returned is physical, except for the block direction progression coordinate (y in horizontal
4749     // writing modes, x in vertical writing modes), which is always "logical top". Apart from the
4750     // flipping, this method does the same as clientBoxRect().
4751 
4752     LayoutUnit left = borderLeft() + (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft() ? verticalScrollbarWidth() : 0);
4753     LayoutUnit top = borderTop();
4754     LayoutUnit right = borderRight();
4755     LayoutUnit bottom = borderBottom();
4756     LayoutRect rect(left, top, width() - left - right, height() - top - bottom);
4757     flipForWritingMode(rect);
4758     // Subtract space occupied by scrollbars. Order is important here: first flip, then subtract
4759     // scrollbars. This may seem backwards and weird, since one would think that a horizontal
4760     // scrollbar at the physical bottom in horizontal-bt ought to be at the logical top (physical
4761     // bottom), between the logical top (physical bottom) border and the logical top (physical
4762     // bottom) padding. But this is how the rest of the code expects us to behave. This is highly
4763     // related to https://bugs.webkit.org/show_bug.cgi?id=76129
4764     // FIXME: when the above mentioned bug is fixed, it should hopefully be possible to call
4765     // clientBoxRect() or paddingBoxRect() in this method, rather than fiddling with the edges on
4766     // our own.
4767     if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
4768         rect.contract(0, horizontalScrollbarHeight());
4769     else
4770         rect.contract(verticalScrollbarWidth(), horizontalScrollbarHeight());
4771     return rect;
4772 }
4773 
overflowRectForPaintRejection() const4774 LayoutRect RenderBox::overflowRectForPaintRejection() const
4775 {
4776     LayoutRect overflowRect = visualOverflowRect();
4777     if (!m_overflow || !usesCompositedScrolling())
4778         return overflowRect;
4779 
4780     overflowRect.unite(layoutOverflowRect());
4781     overflowRect.move(-scrolledContentOffset());
4782     return overflowRect;
4783 }
4784 
offsetLeft() const4785 LayoutUnit RenderBox::offsetLeft() const
4786 {
4787     return adjustedPositionRelativeToOffsetParent(topLeftLocation()).x();
4788 }
4789 
offsetTop() const4790 LayoutUnit RenderBox::offsetTop() const
4791 {
4792     return adjustedPositionRelativeToOffsetParent(topLeftLocation()).y();
4793 }
4794 
flipForWritingModeForChild(const RenderBox * child,const LayoutPoint & point) const4795 LayoutPoint RenderBox::flipForWritingModeForChild(const RenderBox* child, const LayoutPoint& point) const
4796 {
4797     if (!style()->isFlippedBlocksWritingMode())
4798         return point;
4799 
4800     // The child is going to add in its x() and y(), so we have to make sure it ends up in
4801     // the right place.
4802     if (isHorizontalWritingMode())
4803         return LayoutPoint(point.x(), point.y() + height() - child->height() - (2 * child->y()));
4804     return LayoutPoint(point.x() + width() - child->width() - (2 * child->x()), point.y());
4805 }
4806 
flipForWritingMode(LayoutRect & rect) const4807 void RenderBox::flipForWritingMode(LayoutRect& rect) const
4808 {
4809     if (!style()->isFlippedBlocksWritingMode())
4810         return;
4811 
4812     if (isHorizontalWritingMode())
4813         rect.setY(height() - rect.maxY());
4814     else
4815         rect.setX(width() - rect.maxX());
4816 }
4817 
flipForWritingMode(LayoutUnit position) const4818 LayoutUnit RenderBox::flipForWritingMode(LayoutUnit position) const
4819 {
4820     if (!style()->isFlippedBlocksWritingMode())
4821         return position;
4822     return logicalHeight() - position;
4823 }
4824 
flipForWritingMode(const LayoutPoint & position) const4825 LayoutPoint RenderBox::flipForWritingMode(const LayoutPoint& position) const
4826 {
4827     if (!style()->isFlippedBlocksWritingMode())
4828         return position;
4829     return isHorizontalWritingMode() ? LayoutPoint(position.x(), height() - position.y()) : LayoutPoint(width() - position.x(), position.y());
4830 }
4831 
flipForWritingModeIncludingColumns(const LayoutPoint & point) const4832 LayoutPoint RenderBox::flipForWritingModeIncludingColumns(const LayoutPoint& point) const
4833 {
4834     if (!hasColumns() || !style()->isFlippedBlocksWritingMode())
4835         return flipForWritingMode(point);
4836     return toRenderBlock(this)->flipForWritingModeIncludingColumns(point);
4837 }
4838 
flipForWritingMode(const LayoutSize & offset) const4839 LayoutSize RenderBox::flipForWritingMode(const LayoutSize& offset) const
4840 {
4841     if (!style()->isFlippedBlocksWritingMode())
4842         return offset;
4843     return isHorizontalWritingMode() ? LayoutSize(offset.width(), height() - offset.height()) : LayoutSize(width() - offset.width(), offset.height());
4844 }
4845 
flipForWritingMode(const FloatPoint & position) const4846 FloatPoint RenderBox::flipForWritingMode(const FloatPoint& position) const
4847 {
4848     if (!style()->isFlippedBlocksWritingMode())
4849         return position;
4850     return isHorizontalWritingMode() ? FloatPoint(position.x(), height() - position.y()) : FloatPoint(width() - position.x(), position.y());
4851 }
4852 
flipForWritingMode(FloatRect & rect) const4853 void RenderBox::flipForWritingMode(FloatRect& rect) const
4854 {
4855     if (!style()->isFlippedBlocksWritingMode())
4856         return;
4857 
4858     if (isHorizontalWritingMode())
4859         rect.setY(height() - rect.maxY());
4860     else
4861         rect.setX(width() - rect.maxX());
4862 }
4863 
topLeftLocation() const4864 LayoutPoint RenderBox::topLeftLocation() const
4865 {
4866     RenderBlock* containerBlock = containingBlock();
4867     if (!containerBlock || containerBlock == this)
4868         return location();
4869     return containerBlock->flipForWritingModeForChild(this, location());
4870 }
4871 
topLeftLocationOffset() const4872 LayoutSize RenderBox::topLeftLocationOffset() const
4873 {
4874     RenderBlock* containerBlock = containingBlock();
4875     if (!containerBlock || containerBlock == this)
4876         return locationOffset();
4877 
4878     LayoutRect rect(frameRect());
4879     containerBlock->flipForWritingMode(rect); // FIXME: This is wrong if we are an absolutely positioned object enclosed by a relative-positioned inline.
4880     return LayoutSize(rect.x(), rect.y());
4881 }
4882 
hasRelativeDimensions() const4883 bool RenderBox::hasRelativeDimensions() const
4884 {
4885     // FIXME: This should probably include viewport percentage heights as well.
4886     return style()->height().isPercent() || style()->width().isPercent()
4887         || style()->maxHeight().isPercent() || style()->maxWidth().isPercent()
4888         || style()->minHeight().isPercent() || style()->minWidth().isPercent();
4889 }
4890 
hasRelativeLogicalHeight() const4891 bool RenderBox::hasRelativeLogicalHeight() const
4892 {
4893     return style()->logicalHeight().isPercent()
4894         || style()->logicalMinHeight().isPercent()
4895         || style()->logicalMaxHeight().isPercent()
4896         || style()->logicalHeight().isViewportPercentage()
4897         || style()->logicalMinHeight().isViewportPercentage()
4898         || style()->logicalMaxHeight().isViewportPercentage();
4899 }
4900 
markBoxForRelayoutAfterSplit(RenderBox * box)4901 static void markBoxForRelayoutAfterSplit(RenderBox* box)
4902 {
4903     // FIXME: The table code should handle that automatically. If not,
4904     // we should fix it and remove the table part checks.
4905     if (box->isTable()) {
4906         // Because we may have added some sections with already computed column structures, we need to
4907         // sync the table structure with them now. This avoids crashes when adding new cells to the table.
4908         toRenderTable(box)->forceSectionsRecalc();
4909     } else if (box->isTableSection())
4910         toRenderTableSection(box)->setNeedsCellRecalc();
4911 
4912     box->setNeedsLayoutAndPrefWidthsRecalc();
4913 }
4914 
splitAnonymousBoxesAroundChild(RenderObject * beforeChild)4915 RenderObject* RenderBox::splitAnonymousBoxesAroundChild(RenderObject* beforeChild)
4916 {
4917     bool didSplitParentAnonymousBoxes = false;
4918 
4919     while (beforeChild->parent() != this) {
4920         RenderBox* boxToSplit = toRenderBox(beforeChild->parent());
4921         if (boxToSplit->firstChild() != beforeChild && boxToSplit->isAnonymous()) {
4922             didSplitParentAnonymousBoxes = true;
4923 
4924             // We have to split the parent box into two boxes and move children
4925             // from |beforeChild| to end into the new post box.
4926             RenderBox* postBox = boxToSplit->createAnonymousBoxWithSameTypeAs(this);
4927             postBox->setChildrenInline(boxToSplit->childrenInline());
4928             RenderBox* parentBox = toRenderBox(boxToSplit->parent());
4929             // We need to invalidate the |parentBox| before inserting the new node
4930             // so that the table repainting logic knows the structure is dirty.
4931             // See for example RenderTableCell:clippedOverflowRectForRepaint.
4932             markBoxForRelayoutAfterSplit(parentBox);
4933             parentBox->virtualChildren()->insertChildNode(parentBox, postBox, boxToSplit->nextSibling());
4934             boxToSplit->moveChildrenTo(postBox, beforeChild, 0, true);
4935 
4936             markBoxForRelayoutAfterSplit(boxToSplit);
4937             markBoxForRelayoutAfterSplit(postBox);
4938 
4939             beforeChild = postBox;
4940         } else
4941             beforeChild = boxToSplit;
4942     }
4943 
4944     if (didSplitParentAnonymousBoxes)
4945         markBoxForRelayoutAfterSplit(this);
4946 
4947     ASSERT(beforeChild->parent() == this);
4948     return beforeChild;
4949 }
4950 
offsetFromLogicalTopOfFirstPage() const4951 LayoutUnit RenderBox::offsetFromLogicalTopOfFirstPage() const
4952 {
4953     LayoutState* layoutState = view()->layoutState();
4954     if (layoutState && !layoutState->isPaginated())
4955         return 0;
4956 
4957     if (!layoutState && !flowThreadContainingBlock())
4958         return 0;
4959 
4960     RenderBlock* containerBlock = containingBlock();
4961     return containerBlock->offsetFromLogicalTopOfFirstPage() + logicalTop();
4962 }
4963 
4964 } // namespace WebCore
4965