Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(347)

Side by Side Diff: Source/core/rendering/RenderBox.cpp

Issue 926193003: Move rendering/RenderBox to layout/LayoutBox. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/core/rendering/RenderBox.h ('k') | Source/core/rendering/RenderDeprecatedFlexibleBox.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 reserv ed.
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 "core/HTMLNames.h"
30 #include "core/dom/Document.h"
31 #include "core/editing/htmlediting.h"
32 #include "core/frame/FrameHost.h"
33 #include "core/frame/FrameView.h"
34 #include "core/frame/LocalFrame.h"
35 #include "core/frame/PinchViewport.h"
36 #include "core/frame/Settings.h"
37 #include "core/html/HTMLElement.h"
38 #include "core/html/HTMLFrameElementBase.h"
39 #include "core/html/HTMLFrameOwnerElement.h"
40 #include "core/layout/HitTestResult.h"
41 #include "core/layout/Layer.h"
42 #include "core/layout/LayoutGeometryMap.h"
43 #include "core/layout/LayoutListBox.h"
44 #include "core/layout/LayoutListMarker.h"
45 #include "core/layout/LayoutMultiColumnSpannerPlaceholder.h"
46 #include "core/layout/LayoutScrollbarPart.h"
47 #include "core/layout/LayoutTableCell.h"
48 #include "core/layout/PaintInfo.h"
49 #include "core/layout/compositing/LayerCompositor.h"
50 #include "core/layout/style/ShadowList.h"
51 #include "core/page/AutoscrollController.h"
52 #include "core/page/EventHandler.h"
53 #include "core/page/Page.h"
54 #include "core/paint/BackgroundImageGeometry.h"
55 #include "core/paint/BoxPainter.h"
56 #include "core/rendering/RenderDeprecatedFlexibleBox.h"
57 #include "core/rendering/RenderFlexibleBox.h"
58 #include "core/rendering/RenderGrid.h"
59 #include "core/rendering/RenderInline.h"
60 #include "core/rendering/RenderView.h"
61 #include "platform/LengthFunctions.h"
62 #include "platform/geometry/FloatQuad.h"
63 #include "platform/geometry/FloatRoundedRect.h"
64 #include "platform/geometry/TransformState.h"
65 #include "platform/graphics/paint/DisplayItemList.h"
66 #include <algorithm>
67 #include <math.h>
68
69 namespace blink {
70
71 using namespace HTMLNames;
72
73 // Used by flexible boxes when flexing this element and by table cells.
74 typedef WTF::HashMap<const RenderBox*, LayoutUnit> OverrideSizeMap;
75
76 // Used by grid elements to properly size their grid items.
77 // FIXME: Move these into RenderBoxRareData.
78 static OverrideSizeMap* gOverrideContainingBlockLogicalHeightMap = 0;
79 static OverrideSizeMap* gOverrideContainingBlockLogicalWidthMap = 0;
80 static OverrideSizeMap* gExtraInlineOffsetMap = 0;
81 static OverrideSizeMap* gExtraBlockOffsetMap = 0;
82
83
84 // Size of border belt for autoscroll. When mouse pointer in border belt,
85 // autoscroll is started.
86 static const int autoscrollBeltSize = 20;
87 static const unsigned backgroundObscurationTestMaxDepth = 4;
88
89 static bool skipBodyBackground(const RenderBox* bodyElementRenderer)
90 {
91 ASSERT(bodyElementRenderer->isBody());
92 // The <body> only paints its background if the root element has defined a b ackground independent of the body,
93 // or if the <body>'s parent is not the document element's renderer (e.g. in side SVG foreignObject).
94 LayoutObject* documentElementRenderer = bodyElementRenderer->document().docu mentElement()->renderer();
95 return documentElementRenderer
96 && !documentElementRenderer->hasBackground()
97 && (documentElementRenderer == bodyElementRenderer->parent());
98 }
99
100 RenderBox::RenderBox(ContainerNode* node)
101 : LayoutBoxModelObject(node)
102 , m_intrinsicContentLogicalHeight(-1)
103 , m_minPreferredLogicalWidth(-1)
104 , m_maxPreferredLogicalWidth(-1)
105 {
106 setIsBox();
107 }
108
109 LayerType RenderBox::layerTypeRequired() const
110 {
111 // hasAutoZIndex only returns true if the element is positioned or a flex-it em since
112 // position:static elements that are not flex-items get their z-index coerce d to auto.
113 if (isPositioned() || createsGroup() || hasClipPath() || hasTransformRelated Property()
114 || hasHiddenBackface() || hasReflection() || style()->specifiesColumns()
115 || !style()->hasAutoZIndex() || style()->shouldCompositeForCurrentAnimat ions())
116 return NormalLayer;
117
118 // Ensure that explicit use of scroll-blocks-on creates a Layer (since we mi ght need
119 // it to be composited).
120 if (style()->hasScrollBlocksOn()) {
121 if (isDocumentElement()) {
122 ASSERT(style()->scrollBlocksOn() == view()->style()->scrollBlocksOn( ));
123 return NoLayer;
124 }
125 return NormalLayer;
126 }
127 if (hasOverflowClip())
128 return OverflowClipLayer;
129
130 return NoLayer;
131 }
132
133 void RenderBox::willBeDestroyed()
134 {
135 clearOverrideSize();
136 clearContainingBlockOverrideSize();
137 clearExtraInlineAndBlockOffests();
138
139 RenderBlock::removePercentHeightDescendantIfNeeded(this);
140
141 ShapeOutsideInfo::removeInfo(*this);
142
143 LayoutBoxModelObject::willBeDestroyed();
144 }
145
146 void RenderBox::removeFloatingOrPositionedChildFromBlockLists()
147 {
148 ASSERT(isFloatingOrOutOfFlowPositioned());
149
150 if (documentBeingDestroyed())
151 return;
152
153 if (isFloating()) {
154 RenderBlockFlow* parentBlockFlow = 0;
155 for (LayoutObject* curr = parent(); curr && !curr->isRenderView(); curr = curr->parent()) {
156 if (curr->isRenderBlockFlow()) {
157 RenderBlockFlow* currBlockFlow = toRenderBlockFlow(curr);
158 if (!parentBlockFlow || currBlockFlow->containsFloat(this))
159 parentBlockFlow = currBlockFlow;
160 }
161 }
162
163 if (parentBlockFlow) {
164 parentBlockFlow->markSiblingsWithFloatsForLayout(this);
165 parentBlockFlow->markAllDescendantsWithFloatsForLayout(this, false);
166 }
167 }
168
169 if (isOutOfFlowPositioned())
170 RenderBlock::removePositionedObject(this);
171 }
172
173 void RenderBox::styleWillChange(StyleDifference diff, const LayoutStyle& newStyl e)
174 {
175 const LayoutStyle* oldStyle = style();
176 if (oldStyle) {
177 // The background of the root element or the body element could propagat e up to
178 // the canvas. Just dirty the entire canvas when our style changes subst antially.
179 if ((diff.needsPaintInvalidation() || diff.needsLayout()) && node()
180 && (isHTMLHtmlElement(*node()) || isHTMLBodyElement(*node()))) {
181 view()->setShouldDoFullPaintInvalidation();
182
183 if (oldStyle->hasEntirelyFixedBackground() != newStyle.hasEntirelyFi xedBackground())
184 view()->compositor()->setNeedsUpdateFixedBackground();
185 }
186
187 // When a layout hint happens and an object's position style changes, we have to do a layout
188 // to dirty the render tree using the old position value now.
189 if (diff.needsFullLayout() && parent() && oldStyle->position() != newSty le.position()) {
190 markContainingBlocksForLayout();
191 if (oldStyle->position() == StaticPosition)
192 setShouldDoFullPaintInvalidation();
193 else if (newStyle.hasOutOfFlowPosition())
194 parent()->setChildNeedsLayout();
195 if (isFloating() && !isOutOfFlowPositioned() && newStyle.hasOutOfFlo wPosition())
196 removeFloatingOrPositionedChildFromBlockLists();
197 }
198 // FIXME: This branch runs when !oldStyle, which means that layout was never called
199 // so what's the point in invalidating the whole view that we never painted?
200 } else if (isBody()) {
201 view()->setShouldDoFullPaintInvalidation();
202 }
203
204 LayoutBoxModelObject::styleWillChange(diff, newStyle);
205 }
206
207 void RenderBox::styleDidChange(StyleDifference diff, const LayoutStyle* oldStyle )
208 {
209 // Horizontal writing mode definition is updated in LayoutBoxModelObject::up dateFromStyle,
210 // (as part of the LayoutBoxModelObject::styleDidChange call below). So, we can safely cache the horizontal
211 // writing mode value before style change here.
212 bool oldHorizontalWritingMode = isHorizontalWritingMode();
213
214 LayoutBoxModelObject::styleDidChange(diff, oldStyle);
215
216 const LayoutStyle& newStyle = styleRef();
217 if (needsLayout() && oldStyle)
218 RenderBlock::removePercentHeightDescendantIfNeeded(this);
219
220 if (RenderBlock::hasPercentHeightContainerMap() && slowFirstChild()
221 && oldHorizontalWritingMode != isHorizontalWritingMode())
222 RenderBlock::clearPercentHeightDescendantsFrom(this);
223
224 // If our zoom factor changes and we have a defined scrollLeft/Top, we need to adjust that value into the
225 // new zoomed coordinate space.
226 if (hasOverflowClip() && oldStyle && oldStyle->effectiveZoom() != newStyle.e ffectiveZoom() && layer()) {
227 if (int left = layer()->scrollableArea()->scrollXOffset()) {
228 left = (left / oldStyle->effectiveZoom()) * newStyle.effectiveZoom() ;
229 layer()->scrollableArea()->scrollToXOffset(left);
230 }
231 if (int top = layer()->scrollableArea()->scrollYOffset()) {
232 top = (top / oldStyle->effectiveZoom()) * newStyle.effectiveZoom();
233 layer()->scrollableArea()->scrollToYOffset(top);
234 }
235 }
236
237 // Our opaqueness might have changed without triggering layout.
238 if (diff.needsPaintInvalidation()) {
239 LayoutObject* parentToInvalidate = parent();
240 for (unsigned i = 0; i < backgroundObscurationTestMaxDepth && parentToIn validate; ++i) {
241 parentToInvalidate->invalidateBackgroundObscurationStatus();
242 parentToInvalidate = parentToInvalidate->parent();
243 }
244 }
245
246 if (isDocumentElement() || isBody()) {
247 document().view()->recalculateScrollbarOverlayStyle();
248 document().view()->recalculateCustomScrollbarStyle();
249 }
250 updateShapeOutsideInfoAfterStyleChange(*style(), oldStyle);
251 updateGridPositionAfterStyleChange(oldStyle);
252
253 if (LayoutMultiColumnSpannerPlaceholder* placeholder = this->spannerPlacehol der())
254 placeholder->updateMarginProperties();
255 }
256
257 void RenderBox::updateShapeOutsideInfoAfterStyleChange(const LayoutStyle& style, const LayoutStyle* oldStyle)
258 {
259 const ShapeValue* shapeOutside = style.shapeOutside();
260 const ShapeValue* oldShapeOutside = oldStyle ? oldStyle->shapeOutside() : La youtStyle::initialShapeOutside();
261
262 Length shapeMargin = style.shapeMargin();
263 Length oldShapeMargin = oldStyle ? oldStyle->shapeMargin() : LayoutStyle::in itialShapeMargin();
264
265 float shapeImageThreshold = style.shapeImageThreshold();
266 float oldShapeImageThreshold = oldStyle ? oldStyle->shapeImageThreshold() : LayoutStyle::initialShapeImageThreshold();
267
268 // FIXME: A future optimization would do a deep comparison for equality. (bu g 100811)
269 if (shapeOutside == oldShapeOutside && shapeMargin == oldShapeMargin && shap eImageThreshold == oldShapeImageThreshold)
270 return;
271
272 if (!shapeOutside)
273 ShapeOutsideInfo::removeInfo(*this);
274 else
275 ShapeOutsideInfo::ensureInfo(*this).markShapeAsDirty();
276
277 if (shapeOutside || shapeOutside != oldShapeOutside)
278 markShapeOutsideDependentsForLayout();
279 }
280
281 void RenderBox::updateGridPositionAfterStyleChange(const LayoutStyle* oldStyle)
282 {
283 if (!oldStyle || !parent() || !parent()->isRenderGrid())
284 return;
285
286 if (oldStyle->gridColumnStart() == style()->gridColumnStart()
287 && oldStyle->gridColumnEnd() == style()->gridColumnEnd()
288 && oldStyle->gridRowStart() == style()->gridRowStart()
289 && oldStyle->gridRowEnd() == style()->gridRowEnd()
290 && oldStyle->order() == style()->order()
291 && oldStyle->hasOutOfFlowPosition() == style()->hasOutOfFlowPosition())
292 return;
293
294 // It should be possible to not dirty the grid in some cases (like moving an explicitly placed grid item).
295 // For now, it's more simple to just always recompute the grid.
296 toRenderGrid(parent())->dirtyGrid();
297 }
298
299 void RenderBox::updateFromStyle()
300 {
301 LayoutBoxModelObject::updateFromStyle();
302
303 const LayoutStyle& styleToUse = styleRef();
304 bool isRootObject = isDocumentElement();
305 bool isViewObject = isRenderView();
306 bool rootLayerScrolls = document().settings() && document().settings()->root LayerScrolls();
307
308 // The root and the RenderView always paint their backgrounds/borders.
309 if (isRootObject || isViewObject)
310 setHasBoxDecorationBackground(true);
311
312 setFloating(!isOutOfFlowPositioned() && styleToUse.isFloating());
313
314 bool boxHasOverflowClip = false;
315 if (!styleToUse.isOverflowVisible() && isRenderBlock() && (rootLayerScrolls || !isViewObject)) {
316 // If overflow has been propagated to the viewport, it has no effect her e.
317 if (node() != document().viewportDefiningElement())
318 boxHasOverflowClip = true;
319 }
320
321 if (boxHasOverflowClip != hasOverflowClip()) {
322 // FIXME: This shouldn't be required if we tracked the visual overflow
323 // generated by positioned children or self painting layers. crbug.com/3 45403
324 for (LayoutObject* child = slowFirstChild(); child; child = child->nextS ibling())
325 child->setMayNeedPaintInvalidation();
326 }
327
328 setHasOverflowClip(boxHasOverflowClip);
329
330 setHasTransformRelatedProperty(styleToUse.hasTransformRelatedProperty());
331 setHasReflection(styleToUse.boxReflect());
332 }
333
334 void RenderBox::layout()
335 {
336 ASSERT(needsLayout());
337
338 LayoutObject* child = slowFirstChild();
339 if (!child) {
340 clearNeedsLayout();
341 return;
342 }
343
344 LayoutState state(*this, locationOffset());
345 while (child) {
346 child->layoutIfNeeded();
347 ASSERT(!child->needsLayout());
348 child = child->nextSibling();
349 }
350 invalidateBackgroundObscurationStatus();
351 clearNeedsLayout();
352 }
353
354 // More IE extensions. clientWidth and clientHeight represent the interior of a n object
355 // excluding border and scrollbar.
356 LayoutUnit RenderBox::clientWidth() const
357 {
358 return m_frameRect.width() - borderLeft() - borderRight() - verticalScrollba rWidth();
359 }
360
361 LayoutUnit RenderBox::clientHeight() const
362 {
363 return m_frameRect.height() - borderTop() - borderBottom() - horizontalScrol lbarHeight();
364 }
365
366 int RenderBox::pixelSnappedClientWidth() const
367 {
368 return snapSizeToPixel(clientWidth(), location().x() + clientLeft());
369 }
370
371 int RenderBox::pixelSnappedClientHeight() const
372 {
373 return snapSizeToPixel(clientHeight(), location().y() + clientTop());
374 }
375
376 int RenderBox::pixelSnappedOffsetWidth() const
377 {
378 return snapSizeToPixel(offsetWidth(), location().x() + clientLeft());
379 }
380
381 int RenderBox::pixelSnappedOffsetHeight() const
382 {
383 return snapSizeToPixel(offsetHeight(), location().y() + clientTop());
384 }
385
386 LayoutUnit RenderBox::scrollWidth() const
387 {
388 if (hasOverflowClip())
389 return layer()->scrollableArea()->scrollWidth();
390 // For objects with visible overflow, this matches IE.
391 // FIXME: Need to work right with writing modes.
392 if (style()->isLeftToRightDirection())
393 return std::max(clientWidth(), layoutOverflowRect().maxX() - borderLeft( ));
394 return clientWidth() - std::min(LayoutUnit(), layoutOverflowRect().x() - bor derLeft());
395 }
396
397 LayoutUnit RenderBox::scrollHeight() const
398 {
399 if (hasOverflowClip())
400 return layer()->scrollableArea()->scrollHeight();
401 // For objects with visible overflow, this matches IE.
402 // FIXME: Need to work right with writing modes.
403 return std::max(clientHeight(), layoutOverflowRect().maxY() - borderTop());
404 }
405
406 LayoutUnit RenderBox::scrollLeft() const
407 {
408 return hasOverflowClip() ? layer()->scrollableArea()->scrollXOffset() : 0;
409 }
410
411 LayoutUnit RenderBox::scrollTop() const
412 {
413 return hasOverflowClip() ? layer()->scrollableArea()->scrollYOffset() : 0;
414 }
415
416 int RenderBox::pixelSnappedScrollWidth() const
417 {
418 return snapSizeToPixel(scrollWidth(), location().x() + clientLeft());
419 }
420
421 int RenderBox::pixelSnappedScrollHeight() const
422 {
423 if (hasOverflowClip())
424 return layer()->scrollableArea()->scrollHeight();
425 // For objects with visible overflow, this matches IE.
426 // FIXME: Need to work right with writing modes.
427 return snapSizeToPixel(scrollHeight(), location().y() + clientTop());
428 }
429
430 void RenderBox::setScrollLeft(LayoutUnit newLeft)
431 {
432 // This doesn't hit in any tests, but since the equivalent code in setScroll Top
433 // does, presumably this code does as well.
434 DisableCompositingQueryAsserts disabler;
435
436 if (hasOverflowClip())
437 layer()->scrollableArea()->scrollToXOffset(newLeft, ScrollOffsetClamped, ScrollBehaviorAuto);
438 }
439
440 void RenderBox::setScrollTop(LayoutUnit newTop)
441 {
442 // Hits in compositing/overflow/do-not-assert-on-invisible-composited-layers .html
443 DisableCompositingQueryAsserts disabler;
444
445 if (hasOverflowClip())
446 layer()->scrollableArea()->scrollToYOffset(newTop, ScrollOffsetClamped, ScrollBehaviorAuto);
447 }
448
449 void RenderBox::scrollToOffset(const DoubleSize& offset, ScrollBehavior scrollBe havior)
450 {
451 // This doesn't hit in any tests, but since the equivalent code in setScroll Top
452 // does, presumably this code does as well.
453 DisableCompositingQueryAsserts disabler;
454
455 if (hasOverflowClip())
456 layer()->scrollableArea()->scrollToOffset(offset, ScrollOffsetClamped, s crollBehavior);
457 }
458
459 static inline bool frameElementAndViewPermitScroll(HTMLFrameElementBase* frameEl ementBase, FrameView* frameView)
460 {
461 // If scrollbars aren't explicitly forbidden, permit scrolling.
462 if (frameElementBase && frameElementBase->scrollingMode() != ScrollbarAlways Off)
463 return true;
464
465 // If scrollbars are forbidden, user initiated scrolls should obviously be i gnored.
466 if (frameView->wasScrolledByUser())
467 return false;
468
469 // Forbid autoscrolls when scrollbars are off, but permits other programmati c scrolls,
470 // like navigation to an anchor.
471 Page* page = frameView->frame().page();
472 if (!page)
473 return false;
474 return !page->autoscrollController().autoscrollInProgress();
475 }
476
477 void RenderBox::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignmen t& alignX, const ScrollAlignment& alignY)
478 {
479 // Presumably the same issue as in setScrollTop. See crbug.com/343132.
480 DisableCompositingQueryAsserts disabler;
481
482 RenderBox* parentBox = 0;
483 LayoutRect newRect = rect;
484
485 bool restrictedByLineClamp = false;
486 if (parent()) {
487 parentBox = parent()->enclosingBox();
488 restrictedByLineClamp = !parent()->style()->lineClamp().isNone();
489 }
490
491 if (hasOverflowClip() && !restrictedByLineClamp) {
492 // Don't scroll to reveal an overflow layer that is restricted by the -w ebkit-line-clamp property.
493 // This will prevent us from revealing text hidden by the slider in Safa ri RSS.
494 newRect = layer()->scrollableArea()->exposeRect(rect, alignX, alignY);
495 } else if (!parentBox && canBeProgramaticallyScrolled()) {
496 if (FrameView* frameView = this->frameView()) {
497 HTMLFrameOwnerElement* ownerElement = document().ownerElement();
498
499 if (ownerElement && ownerElement->renderer()) {
500 HTMLFrameElementBase* frameElementBase = isHTMLFrameElementBase( *ownerElement) ? toHTMLFrameElementBase(ownerElement) : 0;
501 if (frameElementAndViewPermitScroll(frameElementBase, frameView) ) {
502 LayoutRect viewRect = frameView->visibleContentRect();
503 LayoutRect exposeRect = ScrollAlignment::getRectToExpose(vie wRect, rect, alignX, alignY);
504
505 double xOffset = exposeRect.x();
506 double yOffset = exposeRect.y();
507 // Adjust offsets if they're outside of the allowable range.
508 xOffset = std::max(0.0, std::min<double>(frameView->contents Width(), xOffset));
509 yOffset = std::max(0.0, std::min<double>(frameView->contents Height(), yOffset));
510
511 frameView->setScrollPosition(DoublePoint(xOffset, yOffset));
512 if (frameView->safeToPropagateScrollToParent()) {
513 parentBox = ownerElement->renderer()->enclosingBox();
514 // FIXME: This doesn't correctly convert the rect to
515 // absolute coordinates in the parent.
516 newRect.setX(rect.x() - frameView->scrollX() + frameView ->x());
517 newRect.setY(rect.y() - frameView->scrollY() + frameView ->y());
518 } else {
519 parentBox = 0;
520 }
521 }
522 } else {
523 if (frame()->settings()->pinchVirtualViewportEnabled()) {
524 PinchViewport& pinchViewport = frame()->page()->frameHost(). pinchViewport();
525
526 // We want to move the rect into the viewport that excludes the scrollbars so we intersect
527 // the pinch viewport with the scrollbar-excluded frameView content rect.
528 LayoutRect viewRect = intersection(
529 LayoutRect(pinchViewport.visibleRectInDocument()), frame View->visibleContentRect());
530 LayoutRect r = ScrollAlignment::getRectToExpose(viewRect, re ct, alignX, alignY);
531
532 // pinchViewport.scrollIntoView will attempt to center the g iven rect within the viewport
533 // so to prevent it from adjusting r's coordinates the rect must match the viewport's size
534 // i.e. add the subtracted scrollbars from above back in.
535 // FIXME: This is hacky and required because getRectToExpose doesn't naturally account
536 // for the two viewports. crbug.com/449340.
537 r.setSize(LayoutSize(pinchViewport.visibleRectInDocument().s ize()));
538
539 pinchViewport.scrollIntoView(r);
540 } else {
541 LayoutRect viewRect = frameView->visibleContentRect();
542 LayoutRect r = ScrollAlignment::getRectToExpose(viewRect, re ct, alignX, alignY);
543 frameView->setScrollPosition(DoublePoint(r.location()));
544 }
545 }
546 }
547 }
548
549 if (frame()->page()->autoscrollController().autoscrollInProgress())
550 parentBox = enclosingScrollableBox();
551
552 if (parentBox)
553 parentBox->scrollRectToVisible(newRect, alignX, alignY);
554 }
555
556 void RenderBox::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumul atedOffset) const
557 {
558 rects.append(pixelSnappedIntRect(accumulatedOffset, size()));
559 }
560
561 void RenderBox::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
562 {
563 quads.append(localToAbsoluteQuad(FloatRect(0, 0, m_frameRect.width().toFloat (), m_frameRect.height().toFloat()), 0 /* mode */, wasFixed));
564 }
565
566 void RenderBox::updateLayerTransformAfterLayout()
567 {
568 // Transform-origin depends on box size, so we need to update the layer tran sform after layout.
569 if (hasLayer())
570 layer()->updateTransformationMatrix();
571 }
572
573 LayoutUnit RenderBox::constrainLogicalWidthByMinMax(LayoutUnit logicalWidth, Lay outUnit availableWidth, RenderBlock* cb) const
574 {
575 const LayoutStyle& styleToUse = styleRef();
576 if (!styleToUse.logicalMaxWidth().isMaxSizeNone())
577 logicalWidth = std::min(logicalWidth, computeLogicalWidthUsing(MaxSize, styleToUse.logicalMaxWidth(), availableWidth, cb));
578 return std::max(logicalWidth, computeLogicalWidthUsing(MinSize, styleToUse.l ogicalMinWidth(), availableWidth, cb));
579 }
580
581 LayoutUnit RenderBox::constrainLogicalHeightByMinMax(LayoutUnit logicalHeight, L ayoutUnit intrinsicContentHeight) const
582 {
583 const LayoutStyle& styleToUse = styleRef();
584 if (!styleToUse.logicalMaxHeight().isMaxSizeNone()) {
585 LayoutUnit maxH = computeLogicalHeightUsing(styleToUse.logicalMaxHeight( ), intrinsicContentHeight);
586 if (maxH != -1)
587 logicalHeight = std::min(logicalHeight, maxH);
588 }
589 return std::max(logicalHeight, computeLogicalHeightUsing(styleToUse.logicalM inHeight(), intrinsicContentHeight));
590 }
591
592 LayoutUnit RenderBox::constrainContentBoxLogicalHeightByMinMax(LayoutUnit logica lHeight, LayoutUnit intrinsicContentHeight) const
593 {
594 const LayoutStyle& styleToUse = styleRef();
595 if (!styleToUse.logicalMaxHeight().isMaxSizeNone()) {
596 LayoutUnit maxH = computeContentLogicalHeight(styleToUse.logicalMaxHeigh t(), intrinsicContentHeight);
597 if (maxH != -1)
598 logicalHeight = std::min(logicalHeight, maxH);
599 }
600 return std::max(logicalHeight, computeContentLogicalHeight(styleToUse.logica lMinHeight(), intrinsicContentHeight));
601 }
602
603 IntRect RenderBox::absoluteContentBox() const
604 {
605 // This is wrong with transforms and flipped writing modes.
606 IntRect rect = pixelSnappedIntRect(contentBoxRect());
607 FloatPoint absPos = localToAbsolute();
608 rect.move(absPos.x(), absPos.y());
609 return rect;
610 }
611
612 IntSize RenderBox::absoluteContentBoxOffset() const
613 {
614 IntPoint offset = roundedIntPoint(contentBoxOffset());
615 FloatPoint absPos = localToAbsolute();
616 offset.move(absPos.x(), absPos.y());
617 return toIntSize(offset);
618 }
619
620 FloatQuad RenderBox::absoluteContentQuad() const
621 {
622 LayoutRect rect = contentBoxRect();
623 return localToAbsoluteQuad(FloatRect(rect));
624 }
625
626 void RenderBox::addFocusRingRects(Vector<LayoutRect>& rects, const LayoutPoint& additionalOffset) const
627 {
628 if (!size().isEmpty())
629 rects.append(LayoutRect(additionalOffset, size()));
630 }
631
632 bool RenderBox::canResize() const
633 {
634 // We need a special case for <iframe> because they never have
635 // hasOverflowClip(). However, they do "implicitly" clip their contents, so
636 // we want to allow resizing them also.
637 return (hasOverflowClip() || isLayoutIFrame()) && style()->resize() != RESIZ E_NONE;
638 }
639
640 void RenderBox::addLayerHitTestRects(LayerHitTestRects& layerRects, const Layer* currentLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const
641 {
642 LayoutPoint adjustedLayerOffset = layerOffset + locationOffset();
643 LayoutBoxModelObject::addLayerHitTestRects(layerRects, currentLayer, adjuste dLayerOffset, containerRect);
644 }
645
646 void RenderBox::computeSelfHitTestRects(Vector<LayoutRect>& rects, const LayoutP oint& layerOffset) const
647 {
648 if (!size().isEmpty())
649 rects.append(LayoutRect(layerOffset, size()));
650 }
651
652 int RenderBox::reflectionOffset() const
653 {
654 if (!style()->boxReflect())
655 return 0;
656 if (style()->boxReflect()->direction() == ReflectionLeft || style()->boxRefl ect()->direction() == ReflectionRight)
657 return valueForLength(style()->boxReflect()->offset(), borderBoxRect().w idth());
658 return valueForLength(style()->boxReflect()->offset(), borderBoxRect().heigh t());
659 }
660
661 LayoutRect RenderBox::reflectedRect(const LayoutRect& r) const
662 {
663 if (!style()->boxReflect())
664 return LayoutRect();
665
666 LayoutRect box = borderBoxRect();
667 LayoutRect result = r;
668 switch (style()->boxReflect()->direction()) {
669 case ReflectionBelow:
670 result.setY(box.maxY() + reflectionOffset() + (box.maxY() - r.maxY() ));
671 break;
672 case ReflectionAbove:
673 result.setY(box.y() - reflectionOffset() - box.height() + (box.maxY( ) - r.maxY()));
674 break;
675 case ReflectionLeft:
676 result.setX(box.x() - reflectionOffset() - box.width() + (box.maxX() - r.maxX()));
677 break;
678 case ReflectionRight:
679 result.setX(box.maxX() + reflectionOffset() + (box.maxX() - r.maxX() ));
680 break;
681 }
682 return result;
683 }
684
685 int RenderBox::verticalScrollbarWidth() const
686 {
687 if (!hasOverflowClip() || style()->overflowY() == OOVERLAY)
688 return 0;
689
690 return layer()->scrollableArea()->verticalScrollbarWidth();
691 }
692
693 int RenderBox::horizontalScrollbarHeight() const
694 {
695 if (!hasOverflowClip() || style()->overflowX() == OOVERLAY)
696 return 0;
697
698 return layer()->scrollableArea()->horizontalScrollbarHeight();
699 }
700
701 int RenderBox::intrinsicScrollbarLogicalWidth() const
702 {
703 if (!hasOverflowClip())
704 return 0;
705
706 if (isHorizontalWritingMode() && style()->overflowY() == OSCROLL) {
707 ASSERT(layer()->scrollableArea() && layer()->scrollableArea()->hasVertic alScrollbar());
708 return verticalScrollbarWidth();
709 }
710
711 if (!isHorizontalWritingMode() && style()->overflowX() == OSCROLL) {
712 ASSERT(layer()->scrollableArea() && layer()->scrollableArea()->hasHorizo ntalScrollbar());
713 return horizontalScrollbarHeight();
714 }
715
716 return 0;
717 }
718
719 bool RenderBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float delta)
720 {
721 // Presumably the same issue as in setScrollTop. See crbug.com/343132.
722 DisableCompositingQueryAsserts disabler;
723
724 // Logical scroll is a higher level concept, all directions by here must be physical
725 ASSERT(!isLogical(direction));
726
727 if (!layer() || !layer()->scrollableArea())
728 return false;
729
730 return layer()->scrollableArea()->scroll(direction, granularity, delta);
731 }
732
733 bool RenderBox::canBeScrolledAndHasScrollableArea() const
734 {
735 return canBeProgramaticallyScrolled() && (pixelSnappedScrollHeight() != pixe lSnappedClientHeight() || pixelSnappedScrollWidth() != pixelSnappedClientWidth() );
736 }
737
738 bool RenderBox::canBeProgramaticallyScrolled() const
739 {
740 Node* node = this->node();
741 if (node && node->isDocumentNode())
742 return true;
743
744 if (!hasOverflowClip())
745 return false;
746
747 bool hasScrollableOverflow = hasScrollableOverflowX() || hasScrollableOverfl owY();
748 if (scrollsOverflow() && hasScrollableOverflow)
749 return true;
750
751 return node && node->hasEditableStyle();
752 }
753
754 bool RenderBox::usesCompositedScrolling() const
755 {
756 return hasOverflowClip() && hasLayer() && layer()->scrollableArea()->usesCom positedScrolling();
757 }
758
759 void RenderBox::autoscroll(const IntPoint& position)
760 {
761 LocalFrame* frame = this->frame();
762 if (!frame)
763 return;
764
765 FrameView* frameView = frame->view();
766 if (!frameView)
767 return;
768
769 IntPoint currentDocumentPosition = frameView->windowToContents(position);
770 scrollRectToVisible(LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), S crollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
771 }
772
773 // There are two kinds of renderer that can autoscroll.
774 bool RenderBox::canAutoscroll() const
775 {
776 if (node() && node()->isDocumentNode())
777 return view()->frameView()->isScrollable();
778
779 // Check for a box that can be scrolled in its own right.
780 return canBeScrolledAndHasScrollableArea();
781 }
782
783 // If specified point is in border belt, returned offset denotes direction of
784 // scrolling.
785 IntSize RenderBox::calculateAutoscrollDirection(const IntPoint& windowPoint) con st
786 {
787 if (!frame())
788 return IntSize();
789
790 FrameView* frameView = frame()->view();
791 if (!frameView)
792 return IntSize();
793
794 IntRect box(absoluteBoundingBoxRect());
795 box.move(view()->frameView()->scrollOffset());
796 IntRect windowBox = view()->frameView()->contentsToWindow(box);
797
798 IntPoint windowAutoscrollPoint = windowPoint;
799
800 if (windowAutoscrollPoint.x() < windowBox.x() + autoscrollBeltSize)
801 windowAutoscrollPoint.move(-autoscrollBeltSize, 0);
802 else if (windowAutoscrollPoint.x() > windowBox.maxX() - autoscrollBeltSize)
803 windowAutoscrollPoint.move(autoscrollBeltSize, 0);
804
805 if (windowAutoscrollPoint.y() < windowBox.y() + autoscrollBeltSize)
806 windowAutoscrollPoint.move(0, -autoscrollBeltSize);
807 else if (windowAutoscrollPoint.y() > windowBox.maxY() - autoscrollBeltSize)
808 windowAutoscrollPoint.move(0, autoscrollBeltSize);
809
810 return windowAutoscrollPoint - windowPoint;
811 }
812
813 RenderBox* RenderBox::findAutoscrollable(LayoutObject* renderer)
814 {
815 while (renderer && !(renderer->isBox() && toRenderBox(renderer)->canAutoscro ll())) {
816 if (!renderer->parent() && renderer->node() == renderer->document() && r enderer->document().ownerElement())
817 renderer = renderer->document().ownerElement()->renderer();
818 else
819 renderer = renderer->parent();
820 }
821
822 return renderer && renderer->isBox() ? toRenderBox(renderer) : 0;
823 }
824
825 static inline int adjustedScrollDelta(int beginningDelta)
826 {
827 // This implemention matches Firefox's.
828 // http://mxr.mozilla.org/firefox/source/toolkit/content/widgets/browser.xml #856.
829 const int speedReducer = 12;
830
831 int adjustedDelta = beginningDelta / speedReducer;
832 if (adjustedDelta > 1)
833 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double >(adjustedDelta))) - 1;
834 else if (adjustedDelta < -1)
835 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double >(-adjustedDelta))) + 1;
836
837 return adjustedDelta;
838 }
839
840 static inline IntSize adjustedScrollDelta(const IntSize& delta)
841 {
842 return IntSize(adjustedScrollDelta(delta.width()), adjustedScrollDelta(delta .height()));
843 }
844
845 void RenderBox::panScroll(const IntPoint& sourcePoint)
846 {
847 LocalFrame* frame = this->frame();
848 if (!frame)
849 return;
850
851 IntPoint lastKnownMousePosition = frame->eventHandler().lastKnownMousePositi on();
852
853 // We need to check if the last known mouse position is out of the window. W hen the mouse is out of the window, the position is incoherent
854 static IntPoint previousMousePosition;
855 if (lastKnownMousePosition.x() < 0 || lastKnownMousePosition.y() < 0)
856 lastKnownMousePosition = previousMousePosition;
857 else
858 previousMousePosition = lastKnownMousePosition;
859
860 IntSize delta = lastKnownMousePosition - sourcePoint;
861
862 if (abs(delta.width()) <= FrameView::noPanScrollRadius) // at the center we let the space for the icon
863 delta.setWidth(0);
864 if (abs(delta.height()) <= FrameView::noPanScrollRadius)
865 delta.setHeight(0);
866 scrollByRecursively(adjustedScrollDelta(delta), ScrollOffsetClamped);
867 }
868
869 void RenderBox::scrollByRecursively(const DoubleSize& delta, ScrollOffsetClampin g clamp)
870 {
871 if (delta.isZero())
872 return;
873
874 bool restrictedByLineClamp = false;
875 if (parent())
876 restrictedByLineClamp = !parent()->style()->lineClamp().isNone();
877
878 if (hasOverflowClip() && !restrictedByLineClamp) {
879 DoubleSize newScrollOffset = layer()->scrollableArea()->adjustedScrollOf fset() + delta;
880 layer()->scrollableArea()->scrollToOffset(newScrollOffset, clamp);
881
882 // If this layer can't do the scroll we ask the next layer up that can s croll to try
883 DoubleSize remainingScrollOffset = newScrollOffset - layer()->scrollable Area()->adjustedScrollOffset();
884 if (!remainingScrollOffset.isZero() && parent()) {
885 if (RenderBox* scrollableBox = enclosingScrollableBox())
886 scrollableBox->scrollByRecursively(remainingScrollOffset, clamp) ;
887
888 LocalFrame* frame = this->frame();
889 if (frame && frame->page())
890 frame->page()->autoscrollController().updateAutoscrollRenderer() ;
891 }
892 } else if (view()->frameView()) {
893 // If we are here, we were called on a renderer that can be programmatic ally scrolled, but doesn't
894 // have an overflow clip. Which means that it is a document node that ca n be scrolled.
895 // FIXME: Pass in DoubleSize. crbug.com/414283.
896 view()->frameView()->scrollBy(flooredIntSize(delta));
897
898 // FIXME: If we didn't scroll the whole way, do we want to try looking a t the frames ownerElement?
899 // https://bugs.webkit.org/show_bug.cgi?id=28237
900 }
901 }
902
903 bool RenderBox::needsPreferredWidthsRecalculation() const
904 {
905 return style()->paddingStart().isPercent() || style()->paddingEnd().isPercen t();
906 }
907
908 IntSize RenderBox::scrolledContentOffset() const
909 {
910 ASSERT(hasOverflowClip());
911 ASSERT(hasLayer());
912 // FIXME: Return DoubleSize here. crbug.com/414283.
913 return flooredIntSize(layer()->scrollableArea()->scrollOffset());
914 }
915
916 void RenderBox::applyCachedClipAndScrollOffsetForPaintInvalidation(LayoutRect& p aintRect) const
917 {
918 ASSERT(hasLayer());
919 ASSERT(hasOverflowClip());
920
921 flipForWritingMode(paintRect);
922 paintRect.move(-scrolledContentOffset()); // For overflow:auto/scroll/hidden .
923
924 // Do not clip scroll layer contents because the compositor expects the whol e layer
925 // to be always invalidated in-time.
926 if (usesCompositedScrolling()) {
927 flipForWritingMode(paintRect);
928 return;
929 }
930
931 // size() is inaccurate if we're in the middle of a layout of this RenderBox , so use the
932 // layer's size instead. Even if the layer's size is wrong, the layer itself will issue paint invalidations
933 // anyway if its size does change.
934 LayoutRect clipRect(LayoutPoint(), LayoutSize(layer()->size()));
935 paintRect = intersection(paintRect, clipRect);
936 flipForWritingMode(paintRect);
937 }
938
939 void RenderBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, Layou tUnit& maxLogicalWidth) const
940 {
941 minLogicalWidth = minPreferredLogicalWidth() - borderAndPaddingLogicalWidth( );
942 maxLogicalWidth = maxPreferredLogicalWidth() - borderAndPaddingLogicalWidth( );
943 }
944
945 LayoutUnit RenderBox::minPreferredLogicalWidth() const
946 {
947 if (preferredLogicalWidthsDirty()) {
948 #if ENABLE(ASSERT)
949 SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<RenderBox& >(*this));
950 #endif
951 const_cast<RenderBox*>(this)->computePreferredLogicalWidths();
952 }
953
954 return m_minPreferredLogicalWidth;
955 }
956
957 LayoutUnit RenderBox::maxPreferredLogicalWidth() const
958 {
959 if (preferredLogicalWidthsDirty()) {
960 #if ENABLE(ASSERT)
961 SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<RenderBox& >(*this));
962 #endif
963 const_cast<RenderBox*>(this)->computePreferredLogicalWidths();
964 }
965
966 return m_maxPreferredLogicalWidth;
967 }
968
969 bool RenderBox::hasOverrideHeight() const
970 {
971 return m_rareData && m_rareData->m_overrideLogicalContentHeight != -1;
972 }
973
974 bool RenderBox::hasOverrideWidth() const
975 {
976 return m_rareData && m_rareData->m_overrideLogicalContentWidth != -1;
977 }
978
979 void RenderBox::setOverrideLogicalContentHeight(LayoutUnit height)
980 {
981 ASSERT(height >= 0);
982 ensureRareData().m_overrideLogicalContentHeight = height;
983 }
984
985 void RenderBox::setOverrideLogicalContentWidth(LayoutUnit width)
986 {
987 ASSERT(width >= 0);
988 ensureRareData().m_overrideLogicalContentWidth = width;
989 }
990
991 void RenderBox::clearOverrideLogicalContentHeight()
992 {
993 if (m_rareData)
994 m_rareData->m_overrideLogicalContentHeight = -1;
995 }
996
997 void RenderBox::clearOverrideLogicalContentWidth()
998 {
999 if (m_rareData)
1000 m_rareData->m_overrideLogicalContentWidth = -1;
1001 }
1002
1003 void RenderBox::clearOverrideSize()
1004 {
1005 clearOverrideLogicalContentHeight();
1006 clearOverrideLogicalContentWidth();
1007 }
1008
1009 LayoutUnit RenderBox::overrideLogicalContentWidth() const
1010 {
1011 ASSERT(hasOverrideWidth());
1012 return m_rareData->m_overrideLogicalContentWidth;
1013 }
1014
1015 LayoutUnit RenderBox::overrideLogicalContentHeight() const
1016 {
1017 ASSERT(hasOverrideHeight());
1018 return m_rareData->m_overrideLogicalContentHeight;
1019 }
1020
1021 LayoutUnit RenderBox::overrideContainingBlockContentLogicalWidth() const
1022 {
1023 ASSERT(hasOverrideContainingBlockLogicalWidth());
1024 return gOverrideContainingBlockLogicalWidthMap->get(this);
1025 }
1026
1027 LayoutUnit RenderBox::overrideContainingBlockContentLogicalHeight() const
1028 {
1029 ASSERT(hasOverrideContainingBlockLogicalHeight());
1030 return gOverrideContainingBlockLogicalHeightMap->get(this);
1031 }
1032
1033 bool RenderBox::hasOverrideContainingBlockLogicalWidth() const
1034 {
1035 return gOverrideContainingBlockLogicalWidthMap && gOverrideContainingBlockLo gicalWidthMap->contains(this);
1036 }
1037
1038 bool RenderBox::hasOverrideContainingBlockLogicalHeight() const
1039 {
1040 return gOverrideContainingBlockLogicalHeightMap && gOverrideContainingBlockL ogicalHeightMap->contains(this);
1041 }
1042
1043 void RenderBox::setOverrideContainingBlockContentLogicalWidth(LayoutUnit logical Width)
1044 {
1045 if (!gOverrideContainingBlockLogicalWidthMap)
1046 gOverrideContainingBlockLogicalWidthMap = new OverrideSizeMap;
1047 gOverrideContainingBlockLogicalWidthMap->set(this, logicalWidth);
1048 }
1049
1050 void RenderBox::setOverrideContainingBlockContentLogicalHeight(LayoutUnit logica lHeight)
1051 {
1052 if (!gOverrideContainingBlockLogicalHeightMap)
1053 gOverrideContainingBlockLogicalHeightMap = new OverrideSizeMap;
1054 gOverrideContainingBlockLogicalHeightMap->set(this, logicalHeight);
1055 }
1056
1057 void RenderBox::clearContainingBlockOverrideSize()
1058 {
1059 if (gOverrideContainingBlockLogicalWidthMap)
1060 gOverrideContainingBlockLogicalWidthMap->remove(this);
1061 clearOverrideContainingBlockContentLogicalHeight();
1062 }
1063
1064 void RenderBox::clearOverrideContainingBlockContentLogicalHeight()
1065 {
1066 if (gOverrideContainingBlockLogicalHeightMap)
1067 gOverrideContainingBlockLogicalHeightMap->remove(this);
1068 }
1069
1070 LayoutUnit RenderBox::extraInlineOffset() const
1071 {
1072 return gExtraInlineOffsetMap ? gExtraInlineOffsetMap->get(this) : LayoutUnit ();
1073 }
1074
1075 LayoutUnit RenderBox::extraBlockOffset() const
1076 {
1077 return gExtraBlockOffsetMap ? gExtraBlockOffsetMap->get(this) : LayoutUnit() ;
1078 }
1079
1080 void RenderBox::setExtraInlineOffset(LayoutUnit inlineOffest)
1081 {
1082 if (!gExtraInlineOffsetMap)
1083 gExtraInlineOffsetMap = new OverrideSizeMap;
1084 gExtraInlineOffsetMap->set(this, inlineOffest);
1085 }
1086
1087 void RenderBox::setExtraBlockOffset(LayoutUnit blockOffest)
1088 {
1089 if (!gExtraBlockOffsetMap)
1090 gExtraBlockOffsetMap = new OverrideSizeMap;
1091 gExtraBlockOffsetMap->set(this, blockOffest);
1092 }
1093
1094 void RenderBox::clearExtraInlineAndBlockOffests()
1095 {
1096 if (gExtraInlineOffsetMap)
1097 gExtraInlineOffsetMap->remove(this);
1098 if (gExtraBlockOffsetMap)
1099 gExtraBlockOffsetMap->remove(this);
1100 }
1101
1102 LayoutUnit RenderBox::adjustBorderBoxLogicalWidthForBoxSizing(LayoutUnit width) const
1103 {
1104 LayoutUnit bordersPlusPadding = borderAndPaddingLogicalWidth();
1105 if (style()->boxSizing() == CONTENT_BOX)
1106 return width + bordersPlusPadding;
1107 return std::max(width, bordersPlusPadding);
1108 }
1109
1110 LayoutUnit RenderBox::adjustBorderBoxLogicalHeightForBoxSizing(LayoutUnit height ) const
1111 {
1112 LayoutUnit bordersPlusPadding = borderAndPaddingLogicalHeight();
1113 if (style()->boxSizing() == CONTENT_BOX)
1114 return height + bordersPlusPadding;
1115 return std::max(height, bordersPlusPadding);
1116 }
1117
1118 LayoutUnit RenderBox::adjustContentBoxLogicalWidthForBoxSizing(LayoutUnit width) const
1119 {
1120 if (style()->boxSizing() == BORDER_BOX)
1121 width -= borderAndPaddingLogicalWidth();
1122 return std::max(LayoutUnit(), width);
1123 }
1124
1125 LayoutUnit RenderBox::adjustContentBoxLogicalHeightForBoxSizing(LayoutUnit heigh t) const
1126 {
1127 if (style()->boxSizing() == BORDER_BOX)
1128 height -= borderAndPaddingLogicalHeight();
1129 return std::max(LayoutUnit(), height);
1130 }
1131
1132 // Hit Testing
1133 bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result , const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffs et, HitTestAction action)
1134 {
1135 LayoutPoint adjustedLocation = accumulatedOffset + location();
1136
1137 // Check kids first.
1138 for (LayoutObject* child = slowLastChild(); child; child = child->previousSi bling()) {
1139 if ((!child->hasLayer() || !toLayoutBoxModelObject(child)->layer()->isSe lfPaintingLayer()) && child->nodeAtPoint(request, result, locationInContainer, a djustedLocation, action)) {
1140 updateHitTestResult(result, locationInContainer.point() - toLayoutSi ze(adjustedLocation));
1141 return true;
1142 }
1143 }
1144
1145 // Check our bounds next. For this purpose always assume that we can only be hit in the
1146 // foreground phase (which is true for replaced elements like images).
1147 LayoutRect boundsRect = borderBoxRect();
1148 boundsRect.moveBy(adjustedLocation);
1149 if (visibleToHitTestRequest(request) && action == HitTestForeground && locat ionInContainer.intersects(boundsRect)) {
1150 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(a djustedLocation));
1151 if (!result.addNodeToListBasedTestResult(node(), request, locationInCont ainer, boundsRect))
1152 return true;
1153 }
1154
1155 return false;
1156 }
1157
1158 void RenderBox::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset )
1159 {
1160 BoxPainter(*this).paint(paintInfo, paintOffset);
1161 }
1162
1163
1164 void RenderBox::paintBoxDecorationBackground(const PaintInfo& paintInfo, const L ayoutPoint& paintOffset)
1165 {
1166 BoxPainter(*this).paintBoxDecorationBackground(paintInfo, paintOffset);
1167 }
1168
1169
1170 bool RenderBox::getBackgroundPaintedExtent(LayoutRect& paintedExtent)
1171 {
1172 ASSERT(hasBackground());
1173 LayoutRect backgroundRect = pixelSnappedIntRect(borderBoxRect());
1174
1175 Color backgroundColor = resolveColor(CSSPropertyBackgroundColor);
1176 if (backgroundColor.alpha()) {
1177 paintedExtent = backgroundRect;
1178 return true;
1179 }
1180
1181 if (!style()->backgroundLayers().image() || style()->backgroundLayers().next ()) {
1182 paintedExtent = backgroundRect;
1183 return true;
1184 }
1185
1186 BackgroundImageGeometry geometry;
1187 BoxPainter::calculateBackgroundImageGeometry(*this, 0, style()->backgroundLa yers(), backgroundRect, geometry);
1188 if (geometry.hasNonLocalGeometry())
1189 return false;
1190 paintedExtent = geometry.destRect();
1191 return true;
1192 }
1193
1194 bool RenderBox::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) c onst
1195 {
1196 if (isBody() && skipBodyBackground(this))
1197 return false;
1198
1199 Color backgroundColor = resolveColor(CSSPropertyBackgroundColor);
1200 if (backgroundColor.hasAlpha())
1201 return false;
1202
1203 // If the element has appearance, it might be painted by theme.
1204 // We cannot be sure if theme paints the background opaque.
1205 // In this case it is safe to not assume opaqueness.
1206 // FIXME: May be ask theme if it paints opaque.
1207 if (style()->hasAppearance())
1208 return false;
1209 // FIXME: Check the opaqueness of background images.
1210
1211 // FIXME: Use rounded rect if border radius is present.
1212 if (style()->hasBorderRadius())
1213 return false;
1214 // FIXME: The background color clip is defined by the last layer.
1215 if (style()->backgroundLayers().next())
1216 return false;
1217 LayoutRect backgroundRect;
1218 switch (style()->backgroundClip()) {
1219 case BorderFillBox:
1220 backgroundRect = borderBoxRect();
1221 break;
1222 case PaddingFillBox:
1223 backgroundRect = paddingBoxRect();
1224 break;
1225 case ContentFillBox:
1226 backgroundRect = contentBoxRect();
1227 break;
1228 default:
1229 break;
1230 }
1231 return backgroundRect.contains(localRect);
1232 }
1233
1234 static bool isCandidateForOpaquenessTest(const RenderBox& childBox)
1235 {
1236 const LayoutStyle& childStyle = childBox.styleRef();
1237 if (childStyle.position() != StaticPosition && childBox.containingBlock() != childBox.parent())
1238 return false;
1239 if (childStyle.visibility() != VISIBLE || childStyle.shapeOutside())
1240 return false;
1241 if (childBox.size().isZero())
1242 return false;
1243 if (Layer* childLayer = childBox.layer()) {
1244 // FIXME: perhaps this could be less conservative?
1245 if (childLayer->compositingState() != NotComposited)
1246 return false;
1247 // FIXME: Deal with z-index.
1248 if (!childStyle.hasAutoZIndex())
1249 return false;
1250 if (childLayer->hasTransformRelatedProperty() || childLayer->isTranspare nt() || childLayer->hasFilter())
1251 return false;
1252 if (childBox.hasOverflowClip() && childStyle.hasBorderRadius())
1253 return false;
1254 }
1255 return true;
1256 }
1257
1258 bool RenderBox::foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, u nsigned maxDepthToTest) const
1259 {
1260 if (!maxDepthToTest)
1261 return false;
1262 for (LayoutObject* child = slowFirstChild(); child; child = child->nextSibli ng()) {
1263 if (!child->isBox())
1264 continue;
1265 RenderBox* childBox = toRenderBox(child);
1266 if (!isCandidateForOpaquenessTest(*childBox))
1267 continue;
1268 LayoutPoint childLocation = childBox->location();
1269 if (childBox->isRelPositioned())
1270 childLocation.move(childBox->relativePositionOffset());
1271 LayoutRect childLocalRect = localRect;
1272 childLocalRect.moveBy(-childLocation);
1273 if (childLocalRect.y() < 0 || childLocalRect.x() < 0) {
1274 // If there is unobscured area above/left of a static positioned box then the rect is probably not covered.
1275 if (childBox->style()->position() == StaticPosition)
1276 return false;
1277 continue;
1278 }
1279 if (childLocalRect.maxY() > childBox->size().height() || childLocalRect. maxX() > childBox->size().width())
1280 continue;
1281 if (childBox->backgroundIsKnownToBeOpaqueInRect(childLocalRect))
1282 return true;
1283 if (childBox->foregroundIsKnownToBeOpaqueInRect(childLocalRect, maxDepth ToTest - 1))
1284 return true;
1285 }
1286 return false;
1287 }
1288
1289 bool RenderBox::computeBackgroundIsKnownToBeObscured()
1290 {
1291 // Test to see if the children trivially obscure the background.
1292 // FIXME: This test can be much more comprehensive.
1293 if (!hasBackground())
1294 return false;
1295 // Table and root background painting is special.
1296 if (isTable() || isDocumentElement())
1297 return false;
1298 // FIXME: box-shadow is painted while background painting.
1299 if (style()->boxShadow())
1300 return false;
1301 LayoutRect backgroundRect;
1302 if (!getBackgroundPaintedExtent(backgroundRect))
1303 return false;
1304 return foregroundIsKnownToBeOpaqueInRect(backgroundRect, backgroundObscurati onTestMaxDepth);
1305 }
1306
1307 bool RenderBox::backgroundHasOpaqueTopLayer() const
1308 {
1309 const FillLayer& fillLayer = style()->backgroundLayers();
1310 if (fillLayer.clip() != BorderFillBox)
1311 return false;
1312
1313 // Clipped with local scrolling
1314 if (hasOverflowClip() && fillLayer.attachment() == LocalBackgroundAttachment )
1315 return false;
1316
1317 if (fillLayer.hasOpaqueImage(this) && fillLayer.hasRepeatXY() && fillLayer.i mage()->canRender(*this, style()->effectiveZoom()))
1318 return true;
1319
1320 // If there is only one layer and no image, check whether the background col or is opaque
1321 if (!fillLayer.next() && !fillLayer.hasImage()) {
1322 Color bgColor = resolveColor(CSSPropertyBackgroundColor);
1323 if (bgColor.alpha() == 255)
1324 return true;
1325 }
1326
1327 return false;
1328 }
1329
1330 void RenderBox::paintMask(const PaintInfo& paintInfo, const LayoutPoint& paintOf fset)
1331 {
1332 BoxPainter(*this).paintMask(paintInfo, paintOffset);
1333 }
1334
1335 void RenderBox::paintClippingMask(const PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1336 {
1337 BoxPainter(*this).paintClippingMask(paintInfo, paintOffset);
1338 }
1339
1340 void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*)
1341 {
1342 if (!parent())
1343 return;
1344
1345 if ((style()->borderImage().image() && style()->borderImage().image()->data( ) == image) ||
1346 (style()->maskBoxImage().image() && style()->maskBoxImage().image()->dat a() == image)) {
1347 setShouldDoFullPaintInvalidation();
1348 return;
1349 }
1350
1351 ShapeValue* shapeOutsideValue = style()->shapeOutside();
1352 if (!frameView()->isInPerformLayout() && isFloating() && shapeOutsideValue & & shapeOutsideValue->image() && shapeOutsideValue->image()->data() == image) {
1353 ShapeOutsideInfo& info = ShapeOutsideInfo::ensureInfo(*this);
1354 if (!info.isComputingShape()) {
1355 info.markShapeAsDirty();
1356 markShapeOutsideDependentsForLayout();
1357 }
1358 }
1359
1360 if (!paintInvalidationLayerRectsForImage(image, style()->backgroundLayers(), true))
1361 paintInvalidationLayerRectsForImage(image, style()->maskLayers(), false) ;
1362 }
1363
1364 bool RenderBox::paintInvalidationLayerRectsForImage(WrappedImagePtr image, const FillLayer& layers, bool drawingBackground)
1365 {
1366 Vector<LayoutObject*> layerRenderers;
1367
1368 // A background of the body or document must extend to the total visible siz e of the document. This means the union of the
1369 // view and document bounds, since it can be the case that the view is large r than the document and vice-versa.
1370 // http://dev.w3.org/csswg/css-backgrounds/#the-background
1371 if (drawingBackground && (isDocumentElement() || (isBody() && !document().do cumentElement()->renderer()->hasBackground()))) {
1372 layerRenderers.append(document().documentElement()->renderer());
1373 layerRenderers.append(view());
1374 if (view()->frameView())
1375 view()->frameView()->setNeedsFullPaintInvalidation();
1376 } else {
1377 layerRenderers.append(this);
1378 }
1379 for (const FillLayer* curLayer = &layers; curLayer; curLayer = curLayer->nex t()) {
1380 if (curLayer->image() && image == curLayer->image()->data() && curLayer- >image()->canRender(*this, style()->effectiveZoom())) {
1381 for (LayoutObject* layerRenderer : layerRenderers)
1382 layerRenderer->setShouldDoFullPaintInvalidation();
1383 return true;
1384 }
1385 }
1386 return false;
1387 }
1388
1389 PaintInvalidationReason RenderBox::invalidatePaintIfNeeded(const PaintInvalidati onState& paintInvalidationState, const LayoutBoxModelObject& newPaintInvalidatio nContainer)
1390 {
1391 PaintInvalidationReason reason = LayoutBoxModelObject::invalidatePaintIfNeed ed(paintInvalidationState, newPaintInvalidationContainer);
1392
1393 // If we are set to do a full paint invalidation that means the RenderView w ill be
1394 // issue paint invalidations. We can then skip issuing of paint invalidation s for the child
1395 // renderers as they'll be covered by the RenderView.
1396 if (!view()->doingFullPaintInvalidation() && !isFullPaintInvalidationReason( reason)) {
1397 invalidatePaintForOverflowIfNeeded();
1398
1399 // Issue paint invalidations for any scrollbars if there is a scrollable area for this renderer.
1400 if (ScrollableArea* area = scrollableArea()) {
1401 if (area->hasVerticalBarDamage())
1402 invalidatePaintRectangle(area->verticalBarDamage());
1403 if (area->hasHorizontalBarDamage())
1404 invalidatePaintRectangle(area->horizontalBarDamage());
1405 }
1406 }
1407
1408 // This is for the next invalidatePaintIfNeeded so must be at the end.
1409 savePreviousBorderBoxSizeIfNeeded();
1410 return reason;
1411 }
1412
1413 void RenderBox::clearPaintInvalidationState(const PaintInvalidationState& paintI nvalidationState)
1414 {
1415 LayoutBoxModelObject::clearPaintInvalidationState(paintInvalidationState);
1416
1417 if (ScrollableArea* area = scrollableArea())
1418 area->resetScrollbarDamage();
1419 }
1420
1421 #if ENABLE(ASSERT)
1422 bool RenderBox::paintInvalidationStateIsDirty() const
1423 {
1424 if (ScrollableArea* area = scrollableArea()) {
1425 if (area->hasVerticalBarDamage() || area->hasHorizontalBarDamage())
1426 return true;
1427 }
1428 return LayoutBoxModelObject::paintInvalidationStateIsDirty();
1429 }
1430 #endif
1431
1432 LayoutRect RenderBox::overflowClipRect(const LayoutPoint& location, OverlayScrol lbarSizeRelevancy relevancy)
1433 {
1434 // FIXME: When overflow-clip (CSS3) is implemented, we'll obtain the propert y
1435 // here.
1436 LayoutRect clipRect = borderBoxRect();
1437 clipRect.setLocation(location + clipRect.location() + LayoutSize(borderLeft( ), borderTop()));
1438 clipRect.setSize(clipRect.size() - LayoutSize(borderLeft() + borderRight(), borderTop() + borderBottom()));
1439
1440 if (!hasOverflowClip())
1441 return clipRect;
1442
1443 // Subtract out scrollbars if we have them.
1444 if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
1445 clipRect.move(layer()->scrollableArea()->verticalScrollbarWidth(relevanc y), 0);
1446 clipRect.contract(layer()->scrollableArea()->verticalScrollbarWidth(relevanc y), layer()->scrollableArea()->horizontalScrollbarHeight(relevancy));
1447
1448 return clipRect;
1449 }
1450
1451 LayoutRect RenderBox::clipRect(const LayoutPoint& location)
1452 {
1453 LayoutRect borderBoxRect = this->borderBoxRect();
1454 LayoutRect clipRect = LayoutRect(borderBoxRect.location() + location, border BoxRect.size());
1455
1456 if (!style()->clipLeft().isAuto()) {
1457 LayoutUnit c = valueForLength(style()->clipLeft(), borderBoxRect.width() );
1458 clipRect.move(c, 0);
1459 clipRect.contract(c, 0);
1460 }
1461
1462 if (!style()->clipRight().isAuto())
1463 clipRect.contract(size().width() - valueForLength(style()->clipRight(), size().width()), 0);
1464
1465 if (!style()->clipTop().isAuto()) {
1466 LayoutUnit c = valueForLength(style()->clipTop(), borderBoxRect.height() );
1467 clipRect.move(0, c);
1468 clipRect.contract(0, c);
1469 }
1470
1471 if (!style()->clipBottom().isAuto())
1472 clipRect.contract(0, size().height() - valueForLength(style()->clipBotto m(), size().height()));
1473
1474 return clipRect;
1475 }
1476
1477 static LayoutUnit portionOfMarginNotConsumedByFloat(LayoutUnit childMargin, Layo utUnit contentSide, LayoutUnit offset)
1478 {
1479 if (childMargin <= 0)
1480 return LayoutUnit();
1481 LayoutUnit contentSideWithMargin = contentSide + childMargin;
1482 if (offset > contentSideWithMargin)
1483 return childMargin;
1484 return offset - contentSide;
1485 }
1486
1487 LayoutUnit RenderBox::shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStar t, LayoutUnit childMarginEnd, const RenderBlockFlow* cb) const
1488 {
1489 LayoutUnit logicalTopPosition = logicalTop();
1490 LayoutUnit startOffsetForContent = cb->startOffsetForContent();
1491 LayoutUnit endOffsetForContent = cb->endOffsetForContent();
1492 LayoutUnit logicalHeight = cb->logicalHeightForChild(*this);
1493 LayoutUnit startOffsetForLine = cb->startOffsetForLine(logicalTopPosition, f alse, logicalHeight);
1494 LayoutUnit endOffsetForLine = cb->endOffsetForLine(logicalTopPosition, false , logicalHeight);
1495
1496 // If there aren't any floats constraining us then allow the margins to shri nk/expand the width as much as they want.
1497 if (startOffsetForContent == startOffsetForLine && endOffsetForContent == en dOffsetForLine)
1498 return cb->availableLogicalWidthForLine(logicalTopPosition, false, logic alHeight) - childMarginStart - childMarginEnd;
1499
1500 LayoutUnit width = cb->availableLogicalWidthForLine(logicalTopPosition, fals e, logicalHeight) - std::max(LayoutUnit(), childMarginStart) - std::max(LayoutUn it(), childMarginEnd);
1501 // We need to see if margins on either the start side or the end side can co ntain the floats in question. If they can,
1502 // then just using the line width is inaccurate. In the case where a float c ompletely fits, we don't need to use the line
1503 // offset at all, but can instead push all the way to the content edge of th e containing block. In the case where the float
1504 // doesn't fit, we can use the line offset, but we need to grow it by the ma rgin to reflect the fact that the margin was
1505 // "consumed" by the float. Negative margins aren't consumed by the float, a nd so we ignore them.
1506 width += portionOfMarginNotConsumedByFloat(childMarginStart, startOffsetForC ontent, startOffsetForLine);
1507 width += portionOfMarginNotConsumedByFloat(childMarginEnd, endOffsetForConte nt, endOffsetForLine);
1508 return width;
1509 }
1510
1511 LayoutUnit RenderBox::containingBlockLogicalWidthForContent() const
1512 {
1513 if (hasOverrideContainingBlockLogicalWidth())
1514 return overrideContainingBlockContentLogicalWidth();
1515
1516 RenderBlock* cb = containingBlock();
1517 return cb->availableLogicalWidth();
1518 }
1519
1520 LayoutUnit RenderBox::containingBlockLogicalHeightForContent(AvailableLogicalHei ghtType heightType) const
1521 {
1522 if (hasOverrideContainingBlockLogicalHeight())
1523 return overrideContainingBlockContentLogicalHeight();
1524
1525 RenderBlock* cb = containingBlock();
1526 return cb->availableLogicalHeight(heightType);
1527 }
1528
1529 LayoutUnit RenderBox::containingBlockAvailableLineWidth() const
1530 {
1531 RenderBlock* cb = containingBlock();
1532 if (cb->isRenderBlockFlow())
1533 return toRenderBlockFlow(cb)->availableLogicalWidthForLine(logicalTop(), false, availableLogicalHeight(IncludeMarginBorderPadding));
1534 return LayoutUnit();
1535 }
1536
1537 LayoutUnit RenderBox::perpendicularContainingBlockLogicalHeight() const
1538 {
1539 if (hasOverrideContainingBlockLogicalHeight())
1540 return overrideContainingBlockContentLogicalHeight();
1541
1542 RenderBlock* cb = containingBlock();
1543 if (cb->hasOverrideHeight())
1544 return cb->overrideLogicalContentHeight();
1545
1546 const LayoutStyle& containingBlockStyle = cb->styleRef();
1547 Length logicalHeightLength = containingBlockStyle.logicalHeight();
1548
1549 // FIXME: For now just support fixed heights. Eventually should support per centage heights as well.
1550 if (!logicalHeightLength.isFixed()) {
1551 LayoutUnit fillFallbackExtent = containingBlockStyle.isHorizontalWriting Mode()
1552 ? view()->frameView()->unscaledVisibleContentSize().height()
1553 : view()->frameView()->unscaledVisibleContentSize().width();
1554 LayoutUnit fillAvailableExtent = containingBlock()->availableLogicalHeig ht(ExcludeMarginBorderPadding);
1555 return std::min(fillAvailableExtent, fillFallbackExtent);
1556 }
1557
1558 // Use the content box logical height as specified by the style.
1559 return cb->adjustContentBoxLogicalHeightForBoxSizing(logicalHeightLength.val ue());
1560 }
1561
1562 void RenderBox::mapLocalToContainer(const LayoutBoxModelObject* paintInvalidatio nContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasF ixed, const PaintInvalidationState* paintInvalidationState) const
1563 {
1564 if (paintInvalidationContainer == this)
1565 return;
1566
1567 if (paintInvalidationState && paintInvalidationState->canMapToContainer(pain tInvalidationContainer)) {
1568 LayoutSize offset = paintInvalidationState->paintOffset() + locationOffs et();
1569 if (style()->hasInFlowPosition() && layer())
1570 offset += layer()->offsetForInFlowPosition();
1571 transformState.move(offset);
1572 return;
1573 }
1574
1575 bool containerSkipped;
1576 LayoutObject* o = container(paintInvalidationContainer, &containerSkipped);
1577 if (!o)
1578 return;
1579
1580 bool isFixedPos = style()->position() == FixedPosition;
1581 bool hasTransform = hasLayer() && layer()->transform();
1582 // If this box has a transform, it acts as a fixed position container for fi xed descendants,
1583 // and may itself also be fixed position. So propagate 'fixed' up only if th is box is fixed position.
1584 if (hasTransform && !isFixedPos)
1585 mode &= ~IsFixed;
1586 else if (isFixedPos)
1587 mode |= IsFixed;
1588
1589 if (wasFixed)
1590 *wasFixed = mode & IsFixed;
1591
1592 LayoutSize containerOffset = offsetFromContainer(o, roundedLayoutPoint(trans formState.mappedPoint()));
1593
1594 bool preserve3D = mode & UseTransforms && (o->style()->preserves3D() || styl e()->preserves3D());
1595 if (mode & UseTransforms && shouldUseTransformFromContainer(o)) {
1596 TransformationMatrix t;
1597 getTransformFromContainer(o, containerOffset, t);
1598 transformState.applyTransform(t, preserve3D ? TransformState::Accumulate Transform : TransformState::FlattenTransform);
1599 } else
1600 transformState.move(containerOffset.width(), containerOffset.height(), p reserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransfo rm);
1601
1602 if (containerSkipped) {
1603 // There can't be a transform between paintInvalidationContainer and o, because transforms create containers, so it should be safe
1604 // to just subtract the delta between the paintInvalidationContainer and o.
1605 LayoutSize containerOffset = paintInvalidationContainer->offsetFromAnces torContainer(o);
1606 transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTrans form);
1607 return;
1608 }
1609
1610 mode &= ~ApplyContainerFlip;
1611
1612 o->mapLocalToContainer(paintInvalidationContainer, transformState, mode, was Fixed);
1613 }
1614
1615 void RenderBox::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState & transformState) const
1616 {
1617 bool isFixedPos = style()->position() == FixedPosition;
1618 bool hasTransform = hasLayer() && layer()->transform();
1619 if (hasTransform && !isFixedPos) {
1620 // If this box has a transform, it acts as a fixed position container fo r fixed descendants,
1621 // and may itself also be fixed position. So propagate 'fixed' up only i f this box is fixed position.
1622 mode &= ~IsFixed;
1623 } else if (isFixedPos)
1624 mode |= IsFixed;
1625
1626 LayoutBoxModelObject::mapAbsoluteToLocalPoint(mode, transformState);
1627 }
1628
1629 LayoutSize RenderBox::offsetFromContainer(const LayoutObject* o, const LayoutPoi nt& point, bool* offsetDependsOnPoint) const
1630 {
1631 ASSERT(o == container());
1632
1633 LayoutSize offset;
1634 if (isRelPositioned())
1635 offset += offsetForInFlowPosition();
1636
1637 if (!isInline() || isReplaced()) {
1638 if (!style()->hasOutOfFlowPosition() && o->hasColumns()) {
1639 const RenderBlock* block = toRenderBlock(o);
1640 LayoutRect columnRect(frameRect());
1641 block->adjustStartEdgeForWritingModeIncludingColumns(columnRect);
1642 offset += toSize(columnRect.location());
1643 LayoutPoint columnPoint = block->flipForWritingModeIncludingColumns( point + offset);
1644 offset = toLayoutSize(block->flipForWritingModeIncludingColumns(toLa youtPoint(offset)));
1645 offset += o->columnOffset(columnPoint);
1646 offset = block->flipForWritingMode(offset);
1647
1648 if (offsetDependsOnPoint)
1649 *offsetDependsOnPoint = true;
1650 } else {
1651 offset += topLeftLocationOffset();
1652 if (o->isLayoutFlowThread()) {
1653 // So far the point has been in flow thread coordinates (i.e. as if everything in
1654 // the fragmentation context lived in one tall single column). C onvert it to a
1655 // visual point now.
1656 LayoutPoint pointInContainer = point + offset;
1657 offset += o->columnOffset(pointInContainer);
1658 if (offsetDependsOnPoint)
1659 *offsetDependsOnPoint = true;
1660 }
1661 }
1662 }
1663
1664 if (o->hasOverflowClip())
1665 offset -= toRenderBox(o)->scrolledContentOffset();
1666
1667 if (style()->position() == AbsolutePosition && o->isRelPositioned() && o->is RenderInline())
1668 offset += toRenderInline(o)->offsetForInFlowPositionedInline(*this);
1669
1670 return offset;
1671 }
1672
1673 InlineBox* RenderBox::createInlineBox()
1674 {
1675 return new InlineBox(*this);
1676 }
1677
1678 void RenderBox::dirtyLineBoxes(bool fullLayout)
1679 {
1680 if (inlineBoxWrapper()) {
1681 if (fullLayout) {
1682 inlineBoxWrapper()->destroy();
1683 ASSERT(m_rareData);
1684 m_rareData->m_inlineBoxWrapper = 0;
1685 } else {
1686 inlineBoxWrapper()->dirtyLineBoxes();
1687 }
1688 }
1689 }
1690
1691 void RenderBox::positionLineBox(InlineBox* box)
1692 {
1693 if (isOutOfFlowPositioned()) {
1694 // Cache the x position only if we were an INLINE type originally.
1695 bool originallyInline = style()->isOriginalDisplayInlineType();
1696 if (originallyInline) {
1697 // The value is cached in the xPos of the box. We only need this va lue if
1698 // our object was inline originally, since otherwise it would have e nded up underneath
1699 // the inlines.
1700 RootInlineBox& root = box->root();
1701 root.block().setStaticInlinePositionForChild(*this, LayoutUnit::from FloatRound(box->logicalLeft()));
1702 } else {
1703 // Our object was a block originally, so we make our normal flow pos ition be
1704 // just below the line box (as though all the inlines that came befo re us got
1705 // wrapped in an anonymous block, which is what would have happened had we been
1706 // in flow). This value was cached in the y() of the box.
1707 layer()->setStaticBlockPosition(box->logicalTop());
1708 }
1709 markStaticPositionedBoxForLayout(box->isHorizontal(), originallyInline);
1710
1711 if (container()->isRenderInline())
1712 moveWithEdgeOfInlineContainerIfNecessary(box->isHorizontal());
1713
1714 // Nuke the box.
1715 box->remove(DontMarkLineBoxes);
1716 box->destroy();
1717 } else if (isReplaced()) {
1718 // FIXME: the call to roundedLayoutPoint() below is temporary and should be removed once
1719 // the transition to LayoutUnit-based types is complete (crbug.com/32123 7)
1720 setLocation(box->topLeft().roundedLayoutPoint());
1721 setInlineBoxWrapper(box);
1722 }
1723 }
1724
1725 void RenderBox::markStaticPositionedBoxForLayout(bool isHorizontal, bool isInlin e)
1726 {
1727 ASSERT(isOutOfFlowPositioned());
1728 if (normalChildNeedsLayout())
1729 return;
1730 if (isInline ? style()->hasStaticInlinePosition(isHorizontal) : style()->has StaticBlockPosition(isHorizontal))
1731 setChildNeedsLayout(MarkOnlyThis);
1732 }
1733
1734 void RenderBox::moveWithEdgeOfInlineContainerIfNecessary(bool isHorizontal)
1735 {
1736 ASSERT(isOutOfFlowPositioned() && container()->isRenderInline() && container ()->isRelPositioned());
1737 // If this object is inside a relative positioned inline and its inline posi tion is an explicit offset from the edge of its container
1738 // then it will need to move if its inline container has changed width. We d o not track if the width has changed
1739 // but if we are here then we are laying out lines inside it, so it probably has - mark our object for layout so that it can
1740 // move to the new offset created by the new width.
1741 if (!normalChildNeedsLayout() && !style()->hasStaticInlinePosition(isHorizon tal))
1742 setChildNeedsLayout(MarkOnlyThis);
1743 }
1744
1745 void RenderBox::deleteLineBoxWrapper()
1746 {
1747 if (inlineBoxWrapper()) {
1748 if (!documentBeingDestroyed())
1749 inlineBoxWrapper()->remove();
1750 inlineBoxWrapper()->destroy();
1751 ASSERT(m_rareData);
1752 m_rareData->m_inlineBoxWrapper = 0;
1753 }
1754 }
1755
1756 void RenderBox::setSpannerPlaceholder(LayoutMultiColumnSpannerPlaceholder& place holder)
1757 {
1758 RELEASE_ASSERT(!m_rareData || !m_rareData->m_spannerPlaceholder); // not exp ected to change directly from one spanner to another.
1759 ensureRareData().m_spannerPlaceholder = &placeholder;
1760 }
1761
1762 void RenderBox::clearSpannerPlaceholder()
1763 {
1764 if (!m_rareData)
1765 return;
1766 m_rareData->m_spannerPlaceholder = 0;
1767 }
1768
1769 LayoutRect RenderBox::clippedOverflowRectForPaintInvalidation(const LayoutBoxMod elObject* paintInvalidationContainer, const PaintInvalidationState* paintInvalid ationState) const
1770 {
1771 if (style()->visibility() != VISIBLE) {
1772 Layer* layer = enclosingLayer();
1773 layer->updateDescendantDependentFlags();
1774 if (layer->subtreeIsInvisible())
1775 return LayoutRect();
1776 }
1777
1778 LayoutRect r = visualOverflowRect();
1779 mapRectToPaintInvalidationBacking(paintInvalidationContainer, r, paintInvali dationState);
1780 return r;
1781 }
1782
1783 void RenderBox::mapRectToPaintInvalidationBacking(const LayoutBoxModelObject* pa intInvalidationContainer, LayoutRect& rect, const PaintInvalidationState* paintI nvalidationState) const
1784 {
1785 // The rect we compute at each step is shifted by our x/y offset in the pare nt container's coordinate space.
1786 // Only when we cross a writing mode boundary will we have to possibly flipF orWritingMode (to convert into a more appropriate
1787 // offset corner for the enclosing container). This allows for a fully RL or BT document to issue paint invalidations
1788 // properly even during layout, since the rect remains flipped all the way u ntil the end.
1789 //
1790 // RenderView::computeRectForPaintInvalidation then converts the rect to phy sical coordinates. We also convert to
1791 // physical when we hit a paintInvalidationContainer boundary. Therefore the final rect returned is always in the
1792 // physical coordinate space of the paintInvalidationContainer.
1793 const LayoutStyle& styleToUse = styleRef();
1794
1795 EPosition position = styleToUse.position();
1796
1797 // We need to inflate the paint invalidation rect before we use paintInvalid ationState,
1798 // else we would forget to inflate it for the current renderer. FIXME: If th ese were
1799 // included into the visual overflow for repaint, we wouldn't have this issu e.
1800 inflatePaintInvalidationRectForReflectionAndFilter(rect);
1801
1802 if (paintInvalidationState && paintInvalidationState->canMapToContainer(pain tInvalidationContainer) && position != FixedPosition) {
1803 if (layer() && layer()->transform())
1804 rect = layer()->transform()->mapRect(pixelSnappedIntRect(rect));
1805
1806 // We can't trust the bits on LayoutObject, because this might be called while re-resolving style.
1807 if (styleToUse.hasInFlowPosition() && layer())
1808 rect.move(layer()->offsetForInFlowPosition());
1809
1810 rect.moveBy(location());
1811 rect.move(paintInvalidationState->paintOffset());
1812 if (paintInvalidationState->isClipped())
1813 rect.intersect(paintInvalidationState->clipRect());
1814 return;
1815 }
1816
1817 if (paintInvalidationContainer == this) {
1818 if (paintInvalidationContainer->style()->isFlippedBlocksWritingMode())
1819 flipForWritingMode(rect);
1820 return;
1821 }
1822
1823 bool containerSkipped;
1824 LayoutObject* o = container(paintInvalidationContainer, &containerSkipped);
1825 if (!o)
1826 return;
1827
1828 if (isWritingModeRoot())
1829 flipForWritingMode(rect);
1830
1831 LayoutPoint topLeft = rect.location();
1832 topLeft.move(locationOffset());
1833
1834 // We are now in our parent container's coordinate space. Apply our transfo rm to obtain a bounding box
1835 // in the parent's coordinate space that encloses us.
1836 if (hasLayer() && layer()->transform()) {
1837 rect = layer()->transform()->mapRect(pixelSnappedIntRect(rect));
1838 topLeft = rect.location();
1839 topLeft.move(locationOffset());
1840 }
1841
1842 if (position == AbsolutePosition && o->isRelPositioned() && o->isRenderInlin e()) {
1843 topLeft += toRenderInline(o)->offsetForInFlowPositionedInline(*this);
1844 } else if (styleToUse.hasInFlowPosition() && layer()) {
1845 // Apply the relative position offset when invalidating a rectangle. Th e layer
1846 // is translated, but the render box isn't, so we need to do this to get the
1847 // right dirty rect. Since this is called from LayoutObject::setStyle, the relative position
1848 // flag on the LayoutObject has been cleared, so use the one on the styl e().
1849 topLeft += layer()->offsetForInFlowPosition();
1850 }
1851
1852 if (position != AbsolutePosition && position != FixedPosition && o->hasColum ns() && o->isRenderBlockFlow()) {
1853 LayoutRect paintInvalidationRect(topLeft, rect.size());
1854 toRenderBlock(o)->adjustRectForColumns(paintInvalidationRect);
1855 topLeft = paintInvalidationRect.location();
1856 rect = paintInvalidationRect;
1857 }
1858
1859 // FIXME: We ignore the lightweight clipping rect that controls use, since i f |o| is in mid-layout,
1860 // its controlClipRect will be wrong. For overflow clip we use the values ca ched by the layer.
1861 rect.setLocation(topLeft);
1862 if (o->hasOverflowClip()) {
1863 RenderBox* containerBox = toRenderBox(o);
1864 containerBox->applyCachedClipAndScrollOffsetForPaintInvalidation(rect);
1865 if (rect.isEmpty())
1866 return;
1867 }
1868
1869 if (containerSkipped) {
1870 // If the paintInvalidationContainer is below o, then we need to map the rect into paintInvalidationContainer's coordinates.
1871 LayoutSize containerOffset = paintInvalidationContainer->offsetFromAnces torContainer(o);
1872 rect.move(-containerOffset);
1873 // If the paintInvalidationContainer is fixed, then the rect is already in its coordinates so doesn't need viewport-adjusting.
1874 if (paintInvalidationContainer->style()->position() != FixedPosition && o->isRenderView())
1875 toRenderView(o)->adjustViewportConstrainedOffset(rect, RenderView::v iewportConstrainedPosition(position));
1876 return;
1877 }
1878
1879 if (o->isRenderView())
1880 toRenderView(o)->mapRectToPaintInvalidationBacking(paintInvalidationCont ainer, rect, RenderView::viewportConstrainedPosition(position), paintInvalidatio nState);
1881 else
1882 o->mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, p aintInvalidationState);
1883 }
1884
1885 void RenderBox::inflatePaintInvalidationRectForReflectionAndFilter(LayoutRect& p aintInvalidationRect) const
1886 {
1887 if (hasReflection())
1888 paintInvalidationRect.unite(reflectedRect(paintInvalidationRect));
1889
1890 if (style()->hasFilter())
1891 paintInvalidationRect.expand(style()->filterOutsets());
1892 }
1893
1894 void RenderBox::invalidatePaintForOverhangingFloats(bool)
1895 {
1896 }
1897
1898 void RenderBox::updateLogicalWidth()
1899 {
1900 LogicalExtentComputedValues computedValues;
1901 computeLogicalWidth(computedValues);
1902
1903 setLogicalWidth(computedValues.m_extent);
1904 setLogicalLeft(computedValues.m_position);
1905 setMarginStart(computedValues.m_margins.m_start);
1906 setMarginEnd(computedValues.m_margins.m_end);
1907 }
1908
1909 static float getMaxWidthListMarker(const RenderBox* renderer)
1910 {
1911 #if ENABLE(ASSERT)
1912 ASSERT(renderer);
1913 Node* parentNode = renderer->generatingNode();
1914 ASSERT(parentNode);
1915 ASSERT(isHTMLOListElement(parentNode) || isHTMLUListElement(parentNode));
1916 ASSERT(renderer->style()->textAutosizingMultiplier() != 1);
1917 #endif
1918 float maxWidth = 0;
1919 for (LayoutObject* child = renderer->slowFirstChild(); child; child = child- >nextSibling()) {
1920 if (!child->isListItem())
1921 continue;
1922
1923 RenderBox* listItem = toRenderBox(child);
1924 for (LayoutObject* itemChild = listItem->slowFirstChild(); itemChild; it emChild = itemChild->nextSibling()) {
1925 if (!itemChild->isListMarker())
1926 continue;
1927 RenderBox* itemMarker = toRenderBox(itemChild);
1928 // Make sure to compute the autosized width.
1929 if (itemMarker->needsLayout())
1930 itemMarker->layout();
1931 maxWidth = std::max<float>(maxWidth, toLayoutListMarker(itemMarker)- >logicalWidth().toFloat());
1932 break;
1933 }
1934 }
1935 return maxWidth;
1936 }
1937
1938 void RenderBox::computeLogicalWidth(LogicalExtentComputedValues& computedValues) const
1939 {
1940 computedValues.m_extent = logicalWidth();
1941 computedValues.m_position = logicalLeft();
1942 computedValues.m_margins.m_start = marginStart();
1943 computedValues.m_margins.m_end = marginEnd();
1944
1945 if (isOutOfFlowPositioned()) {
1946 computePositionedLogicalWidth(computedValues);
1947 return;
1948 }
1949
1950 // If layout is limited to a subtree, the subtree root's logical width does not change.
1951 if (node() && view()->frameView() && view()->frameView()->layoutRoot(true) = = this)
1952 return;
1953
1954 // The parent box is flexing us, so it has increased or decreased our
1955 // width. Use the width from the style context.
1956 // FIXME: Account for writing-mode in flexible boxes.
1957 // https://bugs.webkit.org/show_bug.cgi?id=46418
1958 if (hasOverrideWidth() && parent()->isFlexibleBoxIncludingDeprecated()) {
1959 computedValues.m_extent = overrideLogicalContentWidth() + borderAndPaddi ngLogicalWidth();
1960 return;
1961 }
1962
1963 // FIXME: Account for writing-mode in flexible boxes.
1964 // https://bugs.webkit.org/show_bug.cgi?id=46418
1965 bool inVerticalBox = parent()->isDeprecatedFlexibleBox() && (parent()->style ()->boxOrient() == VERTICAL);
1966 bool stretching = (parent()->style()->boxAlign() == BSTRETCH);
1967 bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inVerticalBox || ! stretching);
1968
1969 const LayoutStyle& styleToUse = styleRef();
1970 Length logicalWidthLength = treatAsReplaced ? Length(computeReplacedLogicalW idth(), Fixed) : styleToUse.logicalWidth();
1971
1972 RenderBlock* cb = containingBlock();
1973 LayoutUnit containerLogicalWidth = std::max(LayoutUnit(), containingBlockLog icalWidthForContent());
1974 bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHo rizontalWritingMode();
1975
1976 if (isInline() && !isInlineBlockOrInlineTable()) {
1977 // just calculate margins
1978 computedValues.m_margins.m_start = minimumValueForLength(styleToUse.marg inStart(), containerLogicalWidth);
1979 computedValues.m_margins.m_end = minimumValueForLength(styleToUse.margin End(), containerLogicalWidth);
1980 if (treatAsReplaced)
1981 computedValues.m_extent = std::max<LayoutUnit>(floatValueForLength(l ogicalWidthLength, 0) + borderAndPaddingLogicalWidth(), minPreferredLogicalWidth ());
1982 return;
1983 }
1984
1985 // Width calculations
1986 if (treatAsReplaced)
1987 computedValues.m_extent = logicalWidthLength.value() + borderAndPaddingL ogicalWidth();
1988 else {
1989 LayoutUnit containerWidthInInlineDirection = containerLogicalWidth;
1990 if (hasPerpendicularContainingBlock)
1991 containerWidthInInlineDirection = perpendicularContainingBlockLogica lHeight();
1992 LayoutUnit preferredWidth = computeLogicalWidthUsing(MainOrPreferredSize , styleToUse.logicalWidth(), containerWidthInInlineDirection, cb);
1993 computedValues.m_extent = constrainLogicalWidthByMinMax(preferredWidth, containerWidthInInlineDirection, cb);
1994 }
1995
1996 // Margin calculations.
1997 computeMarginsForDirection(InlineDirection, cb, containerLogicalWidth, compu tedValues.m_extent, computedValues.m_margins.m_start,
1998 computedValues.m_margins.m_end, style()->marginStart(), style()->marginE nd());
1999
2000 if (!hasPerpendicularContainingBlock && containerLogicalWidth && containerLo gicalWidth != (computedValues.m_extent + computedValues.m_margins.m_start + comp utedValues.m_margins.m_end)
2001 && !isFloating() && !isInline() && !cb->isFlexibleBoxIncludingDeprecated () && !cb->isRenderGrid()) {
2002 LayoutUnit newMargin = containerLogicalWidth - computedValues.m_extent - cb->marginStartForChild(*this);
2003 bool hasInvertedDirection = cb->style()->isLeftToRightDirection() != sty le()->isLeftToRightDirection();
2004 if (hasInvertedDirection)
2005 computedValues.m_margins.m_start = newMargin;
2006 else
2007 computedValues.m_margins.m_end = newMargin;
2008 }
2009
2010 if (styleToUse.textAutosizingMultiplier() != 1 && styleToUse.marginStart().t ype() == Fixed) {
2011 Node* parentNode = generatingNode();
2012 if (parentNode && (isHTMLOListElement(*parentNode) || isHTMLUListElement (*parentNode))) {
2013 // Make sure the markers in a list are properly positioned (i.e. not chopped off) when autosized.
2014 const float adjustedMargin = (1 - 1.0 / styleToUse.textAutosizingMul tiplier()) * getMaxWidthListMarker(this);
2015 bool hasInvertedDirection = cb->style()->isLeftToRightDirection() != style()->isLeftToRightDirection();
2016 if (hasInvertedDirection)
2017 computedValues.m_margins.m_end += adjustedMargin;
2018 else
2019 computedValues.m_margins.m_start += adjustedMargin;
2020 }
2021 }
2022 }
2023
2024 LayoutUnit RenderBox::fillAvailableMeasure(LayoutUnit availableLogicalWidth) con st
2025 {
2026 LayoutUnit marginStart = 0;
2027 LayoutUnit marginEnd = 0;
2028 return fillAvailableMeasure(availableLogicalWidth, marginStart, marginEnd);
2029 }
2030
2031 LayoutUnit RenderBox::fillAvailableMeasure(LayoutUnit availableLogicalWidth, Lay outUnit& marginStart, LayoutUnit& marginEnd) const
2032 {
2033 marginStart = minimumValueForLength(style()->marginStart(), availableLogical Width);
2034 marginEnd = minimumValueForLength(style()->marginEnd(), availableLogicalWidt h);
2035 return availableLogicalWidth - marginStart - marginEnd;
2036 }
2037
2038 LayoutUnit RenderBox::computeIntrinsicLogicalWidthUsing(const Length& logicalWid thLength, LayoutUnit availableLogicalWidth, LayoutUnit borderAndPadding) const
2039 {
2040 if (logicalWidthLength.type() == FillAvailable)
2041 return fillAvailableMeasure(availableLogicalWidth);
2042
2043 LayoutUnit minLogicalWidth = 0;
2044 LayoutUnit maxLogicalWidth = 0;
2045 computeIntrinsicLogicalWidths(minLogicalWidth, maxLogicalWidth);
2046
2047 if (logicalWidthLength.type() == MinContent)
2048 return minLogicalWidth + borderAndPadding;
2049
2050 if (logicalWidthLength.type() == MaxContent)
2051 return maxLogicalWidth + borderAndPadding;
2052
2053 if (logicalWidthLength.type() == FitContent) {
2054 minLogicalWidth += borderAndPadding;
2055 maxLogicalWidth += borderAndPadding;
2056 return std::max(minLogicalWidth, std::min(maxLogicalWidth, fillAvailable Measure(availableLogicalWidth)));
2057 }
2058
2059 ASSERT_NOT_REACHED();
2060 return 0;
2061 }
2062
2063 LayoutUnit RenderBox::computeLogicalWidthUsing(SizeType widthType, const Length& logicalWidth, LayoutUnit availableLogicalWidth, const RenderBlock* cb) const
2064 {
2065 if (!logicalWidth.isIntrinsicOrAuto()) {
2066 // FIXME: If the containing block flow is perpendicular to our direction we need to use the available logical height instead.
2067 return adjustBorderBoxLogicalWidthForBoxSizing(valueForLength(logicalWid th, availableLogicalWidth));
2068 }
2069
2070 if (logicalWidth.isIntrinsic())
2071 return computeIntrinsicLogicalWidthUsing(logicalWidth, availableLogicalW idth, borderAndPaddingLogicalWidth());
2072
2073 LayoutUnit marginStart = 0;
2074 LayoutUnit marginEnd = 0;
2075 LayoutUnit logicalWidthResult = fillAvailableMeasure(availableLogicalWidth, marginStart, marginEnd);
2076
2077 if (shrinkToAvoidFloats() && cb->isRenderBlockFlow() && toRenderBlockFlow(cb )->containsFloats())
2078 logicalWidthResult = std::min(logicalWidthResult, shrinkLogicalWidthToAv oidFloats(marginStart, marginEnd, toRenderBlockFlow(cb)));
2079
2080 if (widthType == MainOrPreferredSize && sizesLogicalWidthToFitContent(logica lWidth))
2081 return std::max(minPreferredLogicalWidth(), std::min(maxPreferredLogical Width(), logicalWidthResult));
2082 return logicalWidthResult;
2083 }
2084
2085 static bool columnFlexItemHasStretchAlignment(const LayoutObject* flexitem)
2086 {
2087 LayoutObject* parent = flexitem->parent();
2088 // auto margins mean we don't stretch. Note that this function will only be used for
2089 // widths, so we don't have to check marginBefore/marginAfter.
2090 ASSERT(parent->style()->isColumnFlexDirection());
2091 if (flexitem->style()->marginStart().isAuto() || flexitem->style()->marginEn d().isAuto())
2092 return false;
2093 return flexitem->style()->alignSelf() == ItemPositionStretch || (flexitem->s tyle()->alignSelf() == ItemPositionAuto && parent->style()->alignItems() == Item PositionStretch);
2094 }
2095
2096 static bool isStretchingColumnFlexItem(const LayoutObject* flexitem)
2097 {
2098 LayoutObject* parent = flexitem->parent();
2099 if (parent->isDeprecatedFlexibleBox() && parent->style()->boxOrient() == VER TICAL && parent->style()->boxAlign() == BSTRETCH)
2100 return true;
2101
2102 // We don't stretch multiline flexboxes because they need to apply line spac ing (align-content) first.
2103 if (parent->isFlexibleBox() && parent->style()->flexWrap() == FlexNoWrap && parent->style()->isColumnFlexDirection() && columnFlexItemHasStretchAlignment(fl exitem))
2104 return true;
2105 return false;
2106 }
2107
2108 bool RenderBox::sizesLogicalWidthToFitContent(const Length& logicalWidth) const
2109 {
2110 if (isFloating() || isInlineBlockOrInlineTable())
2111 return true;
2112
2113 if (logicalWidth.type() == Intrinsic)
2114 return true;
2115
2116 // Flexible box items should shrink wrap, so we lay them out at their intrin sic widths.
2117 // In the case of columns that have a stretch alignment, we go ahead and lay out at the
2118 // stretched size to avoid an extra layout when applying alignment.
2119 if (parent()->isFlexibleBox()) {
2120 // For multiline columns, we need to apply align-content first, so we ca n't stretch now.
2121 if (!parent()->style()->isColumnFlexDirection() || parent()->style()->fl exWrap() != FlexNoWrap)
2122 return true;
2123 if (!columnFlexItemHasStretchAlignment(this))
2124 return true;
2125 }
2126
2127 // Flexible horizontal boxes lay out children at their intrinsic widths. Al so vertical boxes
2128 // that don't stretch their kids lay out their children at their intrinsic w idths.
2129 // FIXME: Think about writing-mode here.
2130 // https://bugs.webkit.org/show_bug.cgi?id=46473
2131 if (parent()->isDeprecatedFlexibleBox() && (parent()->style()->boxOrient() = = HORIZONTAL || parent()->style()->boxAlign() != BSTRETCH))
2132 return true;
2133
2134 // Button, input, select, textarea, and legend treat width value of 'auto' a s 'intrinsic' unless it's in a
2135 // stretching column flexbox.
2136 // FIXME: Think about writing-mode here.
2137 // https://bugs.webkit.org/show_bug.cgi?id=46473
2138 if (logicalWidth.isAuto() && !isStretchingColumnFlexItem(this) && autoWidthS houldFitContent())
2139 return true;
2140
2141 if (isHorizontalWritingMode() != containingBlock()->isHorizontalWritingMode( ))
2142 return true;
2143
2144 return false;
2145 }
2146
2147 bool RenderBox::autoWidthShouldFitContent() const
2148 {
2149 return node() && (isHTMLInputElement(*node()) || isHTMLSelectElement(*node() ) || isHTMLButtonElement(*node())
2150 || isHTMLTextAreaElement(*node()) || (isHTMLLegendElement(*node()) && !s tyle()->hasOutOfFlowPosition()));
2151 }
2152
2153 void RenderBox::computeMarginsForDirection(MarginDirection flowDirection, const RenderBlock* containingBlock, LayoutUnit containerWidth, LayoutUnit childWidth, LayoutUnit& marginStart, LayoutUnit& marginEnd, Length marginStartLength, Length marginEndLength) const
2154 {
2155 if (flowDirection == BlockDirection || isFloating() || isInline()) {
2156 if (isTableCell() && flowDirection == BlockDirection) {
2157 // FIXME: Not right if we allow cells to have different directionali ty than the table. If we do allow this, though,
2158 // we may just do it with an extra anonymous block inside the cell.
2159 marginStart = 0;
2160 marginEnd = 0;
2161 return;
2162 }
2163
2164 // Margins are calculated with respect to the logical width of
2165 // the containing block (8.3)
2166 // Inline blocks/tables and floats don't have their margins increased.
2167 marginStart = minimumValueForLength(marginStartLength, containerWidth);
2168 marginEnd = minimumValueForLength(marginEndLength, containerWidth);
2169 return;
2170 }
2171
2172 if (containingBlock->isFlexibleBox()) {
2173 // We need to let flexbox handle the margin adjustment - otherwise, flex box
2174 // will think we're wider than we actually are and calculate line sizes wrong.
2175 // See also http://dev.w3.org/csswg/css-flexbox/#auto-margins
2176 if (marginStartLength.isAuto())
2177 marginStartLength.setValue(0);
2178 if (marginEndLength.isAuto())
2179 marginEndLength.setValue(0);
2180 }
2181
2182 LayoutUnit marginStartWidth = minimumValueForLength(marginStartLength, conta inerWidth);
2183 LayoutUnit marginEndWidth = minimumValueForLength(marginEndLength, container Width);
2184
2185 LayoutUnit availableWidth = containerWidth;
2186 if (avoidsFloats() && containingBlock->isRenderBlockFlow() && toRenderBlockF low(containingBlock)->containsFloats()) {
2187 availableWidth = containingBlockAvailableLineWidth();
2188 if (shrinkToAvoidFloats() && availableWidth < containerWidth) {
2189 marginStart = std::max(LayoutUnit(), marginStartWidth);
2190 marginEnd = std::max(LayoutUnit(), marginEndWidth);
2191 }
2192 }
2193
2194 // CSS 2.1 (10.3.3): "If 'width' is not 'auto' and 'border-left-width' + 'pa dding-left' + 'width' + 'padding-right' + 'border-right-width'
2195 // (plus any of 'margin-left' or 'margin-right' that are not 'auto') is larg er than the width of the containing block, then any 'auto'
2196 // values for 'margin-left' or 'margin-right' are, for the following rules, treated as zero.
2197 LayoutUnit marginBoxWidth = childWidth + (!style()->width().isAuto() ? margi nStartWidth + marginEndWidth : LayoutUnit());
2198
2199 if (marginBoxWidth < availableWidth) {
2200 // CSS 2.1: "If both 'margin-left' and 'margin-right' are 'auto', their used values are equal. This horizontally centers the element
2201 // with respect to the edges of the containing block."
2202 const LayoutStyle& containingBlockStyle = containingBlock->styleRef();
2203 if ((marginStartLength.isAuto() && marginEndLength.isAuto())
2204 || (!marginStartLength.isAuto() && !marginEndLength.isAuto() && cont ainingBlockStyle.textAlign() == WEBKIT_CENTER)) {
2205 // Other browsers center the margin box for align=center elements so we match them here.
2206 LayoutUnit centeredMarginBoxStart = std::max(LayoutUnit(), (availabl eWidth - childWidth - marginStartWidth - marginEndWidth) / 2);
2207 marginStart = centeredMarginBoxStart + marginStartWidth;
2208 marginEnd = availableWidth - childWidth - marginStart + marginEndWid th;
2209 return;
2210 }
2211
2212 // Adjust margins for the align attribute
2213 if ((!containingBlockStyle.isLeftToRightDirection() && containingBlockSt yle.textAlign() == WEBKIT_LEFT)
2214 || (containingBlockStyle.isLeftToRightDirection() && containingBlock Style.textAlign() == WEBKIT_RIGHT)) {
2215 if (containingBlockStyle.isLeftToRightDirection() != styleRef().isLe ftToRightDirection()) {
2216 if (!marginStartLength.isAuto())
2217 marginEndLength = Length(Auto);
2218 } else {
2219 if (!marginEndLength.isAuto())
2220 marginStartLength = Length(Auto);
2221 }
2222 }
2223
2224 // CSS 2.1: "If there is exactly one value specified as 'auto', its used value follows from the equality."
2225 if (marginEndLength.isAuto()) {
2226 marginStart = marginStartWidth;
2227 marginEnd = availableWidth - childWidth - marginStart;
2228 return;
2229 }
2230
2231 if (marginStartLength.isAuto()) {
2232 marginEnd = marginEndWidth;
2233 marginStart = availableWidth - childWidth - marginEnd;
2234 return;
2235 }
2236 }
2237
2238 // Either no auto margins, or our margin box width is >= the container width , auto margins will just turn into 0.
2239 marginStart = marginStartWidth;
2240 marginEnd = marginEndWidth;
2241 }
2242
2243 void RenderBox::updateLogicalHeight()
2244 {
2245 m_intrinsicContentLogicalHeight = contentLogicalHeight();
2246
2247 LogicalExtentComputedValues computedValues;
2248 computeLogicalHeight(logicalHeight(), logicalTop(), computedValues);
2249
2250 setLogicalHeight(computedValues.m_extent);
2251 setLogicalTop(computedValues.m_position);
2252 setMarginBefore(computedValues.m_margins.m_before);
2253 setMarginAfter(computedValues.m_margins.m_after);
2254 }
2255
2256 void RenderBox::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logica lTop, LogicalExtentComputedValues& computedValues) const
2257 {
2258 computedValues.m_extent = logicalHeight;
2259 computedValues.m_position = logicalTop;
2260
2261 // Cell height is managed by the table and inline non-replaced elements do n ot support a height property.
2262 if (isTableCell() || (isInline() && !isReplaced()))
2263 return;
2264
2265 Length h;
2266 if (isOutOfFlowPositioned())
2267 computePositionedLogicalHeight(computedValues);
2268 else {
2269 RenderBlock* cb = containingBlock();
2270
2271 // If we are perpendicular to our containing block then we need to resol ve our block-start and block-end margins so that if they
2272 // are 'auto' we are centred or aligned within the inline flow containin g block: this is done by computing the margins as though they are inline.
2273 // Note that as this is the 'sizing phase' we are using our own writing mode rather than the containing block's. We use the containing block's
2274 // writing mode when figuring out the block-direction margins for positi oning in |computeAndSetBlockDirectionMargins| (i.e. margin collapsing etc.).
2275 // See http://www.w3.org/TR/2014/CR-css-writing-modes-3-20140320/#orthog onal-flows
2276 MarginDirection flowDirection = isHorizontalWritingMode() != cb->isHoriz ontalWritingMode() ? InlineDirection : BlockDirection;
2277
2278 // For tables, calculate margins only.
2279 if (isTable()) {
2280 computeMarginsForDirection(flowDirection, cb, containingBlockLogical WidthForContent(), computedValues.m_extent, computedValues.m_margins.m_before,
2281 computedValues.m_margins.m_after, style()->marginBefore(), style ()->marginAfter());
2282 return;
2283 }
2284
2285 // FIXME: Account for writing-mode in flexible boxes.
2286 // https://bugs.webkit.org/show_bug.cgi?id=46418
2287 bool inHorizontalBox = parent()->isDeprecatedFlexibleBox() && parent()-> style()->boxOrient() == HORIZONTAL;
2288 bool stretching = parent()->style()->boxAlign() == BSTRETCH;
2289 bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inHorizontalBo x || !stretching);
2290 bool checkMinMaxHeight = false;
2291
2292 // The parent box is flexing us, so it has increased or decreased our he ight. We have to
2293 // grab our cached flexible height.
2294 // FIXME: Account for writing-mode in flexible boxes.
2295 // https://bugs.webkit.org/show_bug.cgi?id=46418
2296 if (hasOverrideHeight() && (parent()->isFlexibleBoxIncludingDeprecated() || parent()->isRenderGrid()))
2297 h = Length(overrideLogicalContentHeight(), Fixed);
2298 else if (treatAsReplaced)
2299 h = Length(computeReplacedLogicalHeight(), Fixed);
2300 else {
2301 h = style()->logicalHeight();
2302 checkMinMaxHeight = true;
2303 }
2304
2305 // Block children of horizontal flexible boxes fill the height of the bo x.
2306 // FIXME: Account for writing-mode in flexible boxes.
2307 // https://bugs.webkit.org/show_bug.cgi?id=46418
2308 if (h.isAuto() && inHorizontalBox && toRenderDeprecatedFlexibleBox(paren t())->isStretchingChildren()) {
2309 h = Length(parentBox()->contentLogicalHeight() - marginBefore() - ma rginAfter() - borderAndPaddingLogicalHeight(), Fixed);
2310 checkMinMaxHeight = false;
2311 }
2312
2313 LayoutUnit heightResult;
2314 if (checkMinMaxHeight) {
2315 heightResult = computeLogicalHeightUsing(style()->logicalHeight(), c omputedValues.m_extent - borderAndPaddingLogicalHeight());
2316 if (heightResult == -1)
2317 heightResult = computedValues.m_extent;
2318 heightResult = constrainLogicalHeightByMinMax(heightResult, computed Values.m_extent - borderAndPaddingLogicalHeight());
2319 } else {
2320 // The only times we don't check min/max height are when a fixed len gth has
2321 // been given as an override. Just use that. The value has already been adjusted
2322 // for box-sizing.
2323 ASSERT(h.isFixed());
2324 heightResult = h.value() + borderAndPaddingLogicalHeight();
2325 }
2326
2327 computedValues.m_extent = heightResult;
2328 computeMarginsForDirection(flowDirection, cb, containingBlockLogicalWidt hForContent(), computedValues.m_extent, computedValues.m_margins.m_before,
2329 computedValues.m_margins.m_after, style()->marginBefore(), style()-> marginAfter());
2330 }
2331
2332 // WinIE quirk: The <html> block always fills the entire canvas in quirks mo de. The <body> always fills the
2333 // <html> block in quirks mode. Only apply this quirk if the block is norma l flow and no height
2334 // is specified. When we're printing, we also need this quirk if the body or root has a percentage
2335 // height since we don't set a height in RenderView when we're printing. So without this quirk, the
2336 // height has nothing to be a percentage of, and it ends up being 0. That is bad.
2337 bool paginatedContentNeedsBaseHeight = document().printing() && h.isPercent( )
2338 && (isDocumentElement() || (isBody() && document().documentElement()->re nderer()->style()->logicalHeight().isPercent())) && !isInline();
2339 if (stretchesToViewport() || paginatedContentNeedsBaseHeight) {
2340 LayoutUnit margins = collapsedMarginBefore() + collapsedMarginAfter();
2341 LayoutUnit visibleHeight = view()->viewLogicalHeightForPercentages();
2342 if (isDocumentElement())
2343 computedValues.m_extent = std::max(computedValues.m_extent, visibleH eight - margins);
2344 else {
2345 LayoutUnit marginsBordersPadding = margins + parentBox()->marginBefo re() + parentBox()->marginAfter() + parentBox()->borderAndPaddingLogicalHeight() ;
2346 computedValues.m_extent = std::max(computedValues.m_extent, visibleH eight - marginsBordersPadding);
2347 }
2348 }
2349 }
2350
2351 LayoutUnit RenderBox::computeLogicalHeightUsing(const Length& height, LayoutUnit intrinsicContentHeight) const
2352 {
2353 LayoutUnit logicalHeight = computeContentAndScrollbarLogicalHeightUsing(heig ht, intrinsicContentHeight);
2354 if (logicalHeight != -1)
2355 logicalHeight = adjustBorderBoxLogicalHeightForBoxSizing(logicalHeight);
2356 return logicalHeight;
2357 }
2358
2359 LayoutUnit RenderBox::computeContentLogicalHeight(const Length& height, LayoutUn it intrinsicContentHeight) const
2360 {
2361 LayoutUnit heightIncludingScrollbar = computeContentAndScrollbarLogicalHeigh tUsing(height, intrinsicContentHeight);
2362 if (heightIncludingScrollbar == -1)
2363 return -1;
2364 return std::max(LayoutUnit(), adjustContentBoxLogicalHeightForBoxSizing(heig htIncludingScrollbar) - scrollbarLogicalHeight());
2365 }
2366
2367 LayoutUnit RenderBox::computeIntrinsicLogicalContentHeightUsing(const Length& lo gicalHeightLength, LayoutUnit intrinsicContentHeight, LayoutUnit borderAndPaddin g) const
2368 {
2369 // FIXME(cbiesinger): The css-sizing spec is considering changing what min-c ontent/max-content should resolve to.
2370 // If that happens, this code will have to change.
2371 if (logicalHeightLength.isMinContent() || logicalHeightLength.isMaxContent() || logicalHeightLength.isFitContent()) {
2372 if (isReplaced())
2373 return intrinsicSize().height();
2374 if (m_intrinsicContentLogicalHeight != -1)
2375 return m_intrinsicContentLogicalHeight;
2376 return intrinsicContentHeight;
2377 }
2378 if (logicalHeightLength.isFillAvailable())
2379 return containingBlock()->availableLogicalHeight(ExcludeMarginBorderPadd ing) - borderAndPadding;
2380 ASSERT_NOT_REACHED();
2381 return 0;
2382 }
2383
2384 LayoutUnit RenderBox::computeContentAndScrollbarLogicalHeightUsing(const Length& height, LayoutUnit intrinsicContentHeight) const
2385 {
2386 // FIXME(cbiesinger): The css-sizing spec is considering changing what min-c ontent/max-content should resolve to.
2387 // If that happens, this code will have to change.
2388 if (height.isIntrinsic()) {
2389 if (intrinsicContentHeight == -1)
2390 return -1; // Intrinsic height isn't available.
2391 return computeIntrinsicLogicalContentHeightUsing(height, intrinsicConten tHeight, borderAndPaddingLogicalHeight());
2392 }
2393 if (height.isFixed())
2394 return height.value();
2395 if (height.isPercent())
2396 return computePercentageLogicalHeight(height);
2397 return -1;
2398 }
2399
2400 bool RenderBox::skipContainingBlockForPercentHeightCalculation(const RenderBox* containingBlock) const
2401 {
2402 // If the writing mode of the containing block is orthogonal to ours, it mea ns that we shouldn't
2403 // skip anything, since we're going to resolve the percentage height against a containing block *width*.
2404 if (isHorizontalWritingMode() != containingBlock->isHorizontalWritingMode())
2405 return false;
2406
2407 // Flow threads for multicol or paged overflow should be skipped. They are i nvisible to the DOM,
2408 // and percent heights of children should be resolved against the multicol o r paged container.
2409 if (containingBlock->isLayoutFlowThread())
2410 return true;
2411
2412 // For quirks mode and anonymous blocks, we skip auto-height containingBlock s when computing percentages.
2413 // For standards mode, we treat the percentage as auto if it has an auto-hei ght containing block.
2414 if (!document().inQuirksMode() && !containingBlock->isAnonymousBlock())
2415 return false;
2416
2417 return !containingBlock->isTableCell() && !containingBlock->isOutOfFlowPosit ioned() && containingBlock->style()->logicalHeight().isAuto();
2418 }
2419
2420 LayoutUnit RenderBox::computePercentageLogicalHeight(const Length& height) const
2421 {
2422 LayoutUnit availableHeight = -1;
2423
2424 bool skippedAutoHeightContainingBlock = false;
2425 RenderBlock* cb = containingBlock();
2426 const RenderBox* containingBlockChild = this;
2427 LayoutUnit rootMarginBorderPaddingHeight = 0;
2428 while (!cb->isRenderView() && skipContainingBlockForPercentHeightCalculation (cb)) {
2429 if (cb->isBody() || cb->isDocumentElement())
2430 rootMarginBorderPaddingHeight += cb->marginBefore() + cb->marginAfte r() + cb->borderAndPaddingLogicalHeight();
2431 skippedAutoHeightContainingBlock = true;
2432 containingBlockChild = cb;
2433 cb = cb->containingBlock();
2434 }
2435 cb->addPercentHeightDescendant(const_cast<RenderBox*>(this));
2436
2437 const LayoutStyle& cbstyle = cb->styleRef();
2438
2439 // A positioned element that specified both top/bottom or that specifies hei ght should be treated as though it has a height
2440 // explicitly specified that can be used for any percentage computations.
2441 bool isOutOfFlowPositionedWithSpecifiedHeight = cb->isOutOfFlowPositioned() && (!cbstyle.logicalHeight().isAuto() || (!cbstyle.logicalTop().isAuto() && !cbs tyle.logicalBottom().isAuto()));
2442
2443 bool includeBorderPadding = isTable();
2444
2445 if (isHorizontalWritingMode() != cb->isHorizontalWritingMode())
2446 availableHeight = containingBlockChild->containingBlockLogicalWidthForCo ntent();
2447 else if (hasOverrideContainingBlockLogicalHeight())
2448 availableHeight = overrideContainingBlockContentLogicalHeight();
2449 else if (cb->isTableCell()) {
2450 if (!skippedAutoHeightContainingBlock) {
2451 // Table cells violate what the CSS spec says to do with heights. Ba sically we
2452 // don't care if the cell specified a height or not. We just always make ourselves
2453 // be a percentage of the cell's current content height.
2454 if (!cb->hasOverrideHeight()) {
2455 // Normally we would let the cell size intrinsically, but scroll ing overflow has to be
2456 // treated differently, since WinIE lets scrolled overflow regio ns shrink as needed.
2457 // While we can't get all cases right, we can at least detect wh en the cell has a specified
2458 // height or when the table has a specified height. In these cas es we want to initially have
2459 // no size and allow the flexing of the table or the cell to its specified height to cause us
2460 // to grow to fill the space. This could end up being wrong in s ome cases, but it is
2461 // preferable to the alternative (sizing intrinsically and makin g the row end up too big).
2462 LayoutTableCell* cell = toLayoutTableCell(cb);
2463 if (scrollsOverflowY() && (!cell->style()->logicalHeight().isAut o() || !cell->table()->style()->logicalHeight().isAuto()))
2464 return LayoutUnit();
2465 return -1;
2466 }
2467 availableHeight = cb->overrideLogicalContentHeight();
2468 includeBorderPadding = true;
2469 }
2470 } else if (cbstyle.logicalHeight().isFixed()) {
2471 LayoutUnit contentBoxHeight = cb->adjustContentBoxLogicalHeightForBoxSiz ing(cbstyle.logicalHeight().value());
2472 availableHeight = std::max(LayoutUnit(), cb->constrainContentBoxLogicalH eightByMinMax(contentBoxHeight - cb->scrollbarLogicalHeight(), -1));
2473 } else if (cbstyle.logicalHeight().isPercent() && !isOutOfFlowPositionedWith SpecifiedHeight) {
2474 // We need to recur and compute the percentage height for our containing block.
2475 LayoutUnit heightWithScrollbar = cb->computePercentageLogicalHeight(cbst yle.logicalHeight());
2476 if (heightWithScrollbar != -1) {
2477 LayoutUnit contentBoxHeightWithScrollbar = cb->adjustContentBoxLogic alHeightForBoxSizing(heightWithScrollbar);
2478 // We need to adjust for min/max height because this method does not
2479 // handle the min/max of the current block, its caller does. So the
2480 // return value from the recursive call will not have been adjusted
2481 // yet.
2482 LayoutUnit contentBoxHeight = cb->constrainContentBoxLogicalHeightBy MinMax(contentBoxHeightWithScrollbar - cb->scrollbarLogicalHeight(), -1);
2483 availableHeight = std::max(LayoutUnit(), contentBoxHeight);
2484 }
2485 } else if (isOutOfFlowPositionedWithSpecifiedHeight) {
2486 // Don't allow this to affect the block' size() member variable, since t his
2487 // can get called while the block is still laying out its kids.
2488 LogicalExtentComputedValues computedValues;
2489 cb->computeLogicalHeight(cb->logicalHeight(), 0, computedValues);
2490 availableHeight = computedValues.m_extent - cb->borderAndPaddingLogicalH eight() - cb->scrollbarLogicalHeight();
2491 } else if (cb->isRenderView())
2492 availableHeight = view()->viewLogicalHeightForPercentages();
2493
2494 if (availableHeight == -1)
2495 return availableHeight;
2496
2497 availableHeight -= rootMarginBorderPaddingHeight;
2498
2499 if (isTable() && isOutOfFlowPositioned())
2500 availableHeight += cb->paddingLogicalHeight();
2501
2502 LayoutUnit result = valueForLength(height, availableHeight);
2503 if (includeBorderPadding) {
2504 // FIXME: Table cells should default to box-sizing: border-box so we can avoid this hack.
2505 // It is necessary to use the border-box to match WinIE's broken
2506 // box model. This is essential for sizing inside
2507 // table cells using percentage heights.
2508 result -= borderAndPaddingLogicalHeight();
2509 return std::max(LayoutUnit(), result);
2510 }
2511 return result;
2512 }
2513
2514 LayoutUnit RenderBox::computeReplacedLogicalWidth(ShouldComputePreferred shouldC omputePreferred) const
2515 {
2516 return computeReplacedLogicalWidthRespectingMinMaxWidth(computeReplacedLogic alWidthUsing(style()->logicalWidth()), shouldComputePreferred);
2517 }
2518
2519 LayoutUnit RenderBox::computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUni t logicalWidth, ShouldComputePreferred shouldComputePreferred) const
2520 {
2521 LayoutUnit minLogicalWidth = (shouldComputePreferred == ComputePreferred && style()->logicalMinWidth().isPercent()) || style()->logicalMinWidth().isMaxSizeN one() ? logicalWidth : computeReplacedLogicalWidthUsing(style()->logicalMinWidth ());
2522 LayoutUnit maxLogicalWidth = (shouldComputePreferred == ComputePreferred && style()->logicalMaxWidth().isPercent()) || style()->logicalMaxWidth().isMaxSizeN one() ? logicalWidth : computeReplacedLogicalWidthUsing(style()->logicalMaxWidth ());
2523 return std::max(minLogicalWidth, std::min(logicalWidth, maxLogicalWidth));
2524 }
2525
2526 LayoutUnit RenderBox::computeReplacedLogicalWidthUsing(const Length& logicalWidt h) const
2527 {
2528 switch (logicalWidth.type()) {
2529 case Fixed:
2530 return adjustContentBoxLogicalWidthForBoxSizing(logicalWidth.value() );
2531 case MinContent:
2532 case MaxContent: {
2533 // MinContent/MaxContent don't need the availableLogicalWidth argume nt.
2534 LayoutUnit availableLogicalWidth = 0;
2535 return computeIntrinsicLogicalWidthUsing(logicalWidth, availableLogi calWidth, borderAndPaddingLogicalWidth()) - borderAndPaddingLogicalWidth();
2536 }
2537 case FitContent:
2538 case FillAvailable:
2539 case Percent:
2540 case Calculated: {
2541 // FIXME: containingBlockLogicalWidthForContent() is wrong if the re placed element's writing-mode is perpendicular to the
2542 // containing block's writing-mode.
2543 // https://bugs.webkit.org/show_bug.cgi?id=46496
2544 const LayoutUnit cw = isOutOfFlowPositioned() ? containingBlockLogic alWidthForPositioned(toLayoutBoxModelObject(container())) : containingBlockLogic alWidthForContent();
2545 Length containerLogicalWidth = containingBlock()->style()->logicalWi dth();
2546 // FIXME: Handle cases when containing block width is calculated or viewport percent.
2547 // https://bugs.webkit.org/show_bug.cgi?id=91071
2548 if (logicalWidth.isIntrinsic())
2549 return computeIntrinsicLogicalWidthUsing(logicalWidth, cw, borde rAndPaddingLogicalWidth()) - borderAndPaddingLogicalWidth();
2550 if (cw > 0 || (!cw && (containerLogicalWidth.isFixed() || containerL ogicalWidth.isPercent())))
2551 return adjustContentBoxLogicalWidthForBoxSizing(minimumValueForL ength(logicalWidth, cw));
2552 return LayoutUnit();
2553 }
2554 case Intrinsic:
2555 case MinIntrinsic:
2556 case Auto:
2557 case MaxSizeNone:
2558 return intrinsicLogicalWidth();
2559 case ExtendToZoom:
2560 case DeviceWidth:
2561 case DeviceHeight:
2562 break;
2563 }
2564
2565 ASSERT_NOT_REACHED();
2566 return 0;
2567 }
2568
2569 LayoutUnit RenderBox::computeReplacedLogicalHeight() const
2570 {
2571 return computeReplacedLogicalHeightRespectingMinMaxHeight(computeReplacedLog icalHeightUsing(style()->logicalHeight()));
2572 }
2573
2574 bool RenderBox::logicalHeightComputesAsNone(SizeType sizeType) const
2575 {
2576 ASSERT(sizeType == MinSize || sizeType == MaxSize);
2577 Length logicalHeight = sizeType == MinSize ? style()->logicalMinHeight() : s tyle()->logicalMaxHeight();
2578 Length initialLogicalHeight = sizeType == MinSize ? LayoutStyle::initialMinS ize() : LayoutStyle::initialMaxSize();
2579
2580 if (logicalHeight == initialLogicalHeight)
2581 return true;
2582
2583 if (RenderBlock* cb = containingBlockForAutoHeightDetection(logicalHeight))
2584 return cb->hasAutoHeightOrContainingBlockWithAutoHeight();
2585 return false;
2586 }
2587
2588 LayoutUnit RenderBox::computeReplacedLogicalHeightRespectingMinMaxHeight(LayoutU nit logicalHeight) const
2589 {
2590 // If the height of the containing block is not specified explicitly (i.e., it depends on content height), and this element is not absolutely positioned,
2591 // the percentage value is treated as '0' (for 'min-height') or 'none' (for 'max-height').
2592 LayoutUnit minLogicalHeight;
2593 if (!logicalHeightComputesAsNone(MinSize))
2594 minLogicalHeight = computeReplacedLogicalHeightUsing(style()->logicalMin Height());
2595 LayoutUnit maxLogicalHeight = logicalHeight;
2596 if (!logicalHeightComputesAsNone(MaxSize))
2597 maxLogicalHeight = computeReplacedLogicalHeightUsing(style()->logicalMa xHeight());
2598 return std::max(minLogicalHeight, std::min(logicalHeight, maxLogicalHeight)) ;
2599 }
2600
2601 LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(const Length& logicalHei ght) const
2602 {
2603 switch (logicalHeight.type()) {
2604 case Fixed:
2605 return adjustContentBoxLogicalHeightForBoxSizing(logicalHeight.value ());
2606 case Percent:
2607 case Calculated:
2608 {
2609 LayoutObject* cb = isOutOfFlowPositioned() ? container() : containin gBlock();
2610 while (cb->isAnonymous())
2611 cb = cb->containingBlock();
2612 if (cb->isRenderBlock())
2613 toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderB ox*>(this));
2614
2615 if (cb->isOutOfFlowPositioned() && cb->style()->height().isAuto() && !(cb->style()->top().isAuto() || cb->style()->bottom().isAuto())) {
2616 ASSERT_WITH_SECURITY_IMPLICATION(cb->isRenderBlock());
2617 RenderBlock* block = toRenderBlock(cb);
2618 LogicalExtentComputedValues computedValues;
2619 block->computeLogicalHeight(block->logicalHeight(), 0, computedV alues);
2620 LayoutUnit newContentHeight = computedValues.m_extent - block->b orderAndPaddingLogicalHeight() - block->scrollbarLogicalHeight();
2621 LayoutUnit newHeight = block->adjustContentBoxLogicalHeightForBo xSizing(newContentHeight);
2622 return adjustContentBoxLogicalHeightForBoxSizing(valueForLength( logicalHeight, newHeight));
2623 }
2624
2625 // FIXME: availableLogicalHeight() is wrong if the replaced element' s writing-mode is perpendicular to the
2626 // containing block's writing-mode.
2627 // https://bugs.webkit.org/show_bug.cgi?id=46496
2628 LayoutUnit availableHeight;
2629 if (isOutOfFlowPositioned())
2630 availableHeight = containingBlockLogicalHeightForPositioned(toLa youtBoxModelObject(cb));
2631 else {
2632 availableHeight = containingBlockLogicalHeightForContent(Include MarginBorderPadding);
2633 // It is necessary to use the border-box to match WinIE's broken
2634 // box model. This is essential for sizing inside
2635 // table cells using percentage heights.
2636 // FIXME: This needs to be made writing-mode-aware. If the cell and image are perpendicular writing-modes, this isn't right.
2637 // https://bugs.webkit.org/show_bug.cgi?id=46997
2638 while (cb && !cb->isRenderView() && (cb->style()->logicalHeight( ).isAuto() || cb->style()->logicalHeight().isPercent())) {
2639 if (cb->isTableCell()) {
2640 // Don't let table cells squeeze percent-height replaced elements
2641 // <http://bugs.webkit.org/show_bug.cgi?id=15359>
2642 availableHeight = std::max(availableHeight, intrinsicLog icalHeight());
2643 return valueForLength(logicalHeight, availableHeight - b orderAndPaddingLogicalHeight());
2644 }
2645 toRenderBlock(cb)->addPercentHeightDescendant(const_cast<Ren derBox*>(this));
2646 cb = cb->containingBlock();
2647 }
2648 }
2649 return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logi calHeight, availableHeight));
2650 }
2651 case MinContent:
2652 case MaxContent:
2653 case FitContent:
2654 case FillAvailable:
2655 return adjustContentBoxLogicalHeightForBoxSizing(computeIntrinsicLog icalContentHeightUsing(logicalHeight, intrinsicLogicalHeight(), borderAndPadding Height()));
2656 default:
2657 return intrinsicLogicalHeight();
2658 }
2659 }
2660
2661 LayoutUnit RenderBox::availableLogicalHeight(AvailableLogicalHeightType heightTy pe) const
2662 {
2663 // http://www.w3.org/TR/CSS2/visudet.html#propdef-height - We are interested in the content height.
2664 return constrainContentBoxLogicalHeightByMinMax(availableLogicalHeightUsing( style()->logicalHeight(), heightType), -1);
2665 }
2666
2667 LayoutUnit RenderBox::availableLogicalHeightUsing(const Length& h, AvailableLogi calHeightType heightType) const
2668 {
2669 if (isRenderView())
2670 return isHorizontalWritingMode() ? toRenderView(this)->frameView()->unsc aledVisibleContentSize().height() : toRenderView(this)->frameView()->unscaledVis ibleContentSize().width();
2671
2672 // We need to stop here, since we don't want to increase the height of the t able
2673 // artificially. We're going to rely on this cell getting expanded to some new
2674 // height, and then when we lay out again we'll use the calculation below.
2675 if (isTableCell() && (h.isAuto() || h.isPercent())) {
2676 if (hasOverrideHeight())
2677 return overrideLogicalContentHeight();
2678 return logicalHeight() - borderAndPaddingLogicalHeight();
2679 }
2680
2681 if (h.isPercent() && isOutOfFlowPositioned()) {
2682 // FIXME: This is wrong if the containingBlock has a perpendicular writi ng mode.
2683 LayoutUnit availableHeight = containingBlockLogicalHeightForPositioned(c ontainingBlock());
2684 return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(h, avail ableHeight));
2685 }
2686
2687 LayoutUnit heightIncludingScrollbar = computeContentAndScrollbarLogicalHeigh tUsing(h, -1);
2688 if (heightIncludingScrollbar != -1)
2689 return std::max(LayoutUnit(), adjustContentBoxLogicalHeightForBoxSizing( heightIncludingScrollbar) - scrollbarLogicalHeight());
2690
2691 // FIXME: Check logicalTop/logicalBottom here to correctly handle vertical w riting-mode.
2692 // https://bugs.webkit.org/show_bug.cgi?id=46500
2693 if (isRenderBlock() && isOutOfFlowPositioned() && style()->height().isAuto() && !(style()->top().isAuto() || style()->bottom().isAuto())) {
2694 RenderBlock* block = const_cast<RenderBlock*>(toRenderBlock(this));
2695 LogicalExtentComputedValues computedValues;
2696 block->computeLogicalHeight(block->logicalHeight(), 0, computedValues);
2697 LayoutUnit newContentHeight = computedValues.m_extent - block->borderAnd PaddingLogicalHeight() - block->scrollbarLogicalHeight();
2698 return adjustContentBoxLogicalHeightForBoxSizing(newContentHeight);
2699 }
2700
2701 // FIXME: This is wrong if the containingBlock has a perpendicular writing m ode.
2702 LayoutUnit availableHeight = containingBlockLogicalHeightForContent(heightTy pe);
2703 if (heightType == ExcludeMarginBorderPadding) {
2704 // FIXME: Margin collapsing hasn't happened yet, so this incorrectly rem oves collapsed margins.
2705 availableHeight -= marginBefore() + marginAfter() + borderAndPaddingLogi calHeight();
2706 }
2707 return availableHeight;
2708 }
2709
2710 void RenderBox::computeAndSetBlockDirectionMargins(const RenderBlock* containing Block)
2711 {
2712 LayoutUnit marginBefore;
2713 LayoutUnit marginAfter;
2714 computeMarginsForDirection(BlockDirection, containingBlock, containingBlockL ogicalWidthForContent(), logicalHeight(), marginBefore, marginAfter,
2715 style()->marginBeforeUsing(containingBlock->style()),
2716 style()->marginAfterUsing(containingBlock->style()));
2717 // Note that in this 'positioning phase' of the layout we are using the cont aining block's writing mode rather than our own when calculating margins.
2718 // See http://www.w3.org/TR/2014/CR-css-writing-modes-3-20140320/#orthogonal -flows
2719 containingBlock->setMarginBeforeForChild(*this, marginBefore);
2720 containingBlock->setMarginAfterForChild(*this, marginAfter);
2721 }
2722
2723 LayoutUnit RenderBox::containingBlockLogicalWidthForPositioned(const LayoutBoxMo delObject* containingBlock, bool checkForPerpendicularWritingMode) const
2724 {
2725 if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWriting Mode() != isHorizontalWritingMode())
2726 return containingBlockLogicalHeightForPositioned(containingBlock, false) ;
2727
2728 // Use viewport as container for top-level fixed-position elements.
2729 if (style()->position() == FixedPosition && containingBlock->isRenderView()) {
2730 const RenderView* view = toRenderView(containingBlock);
2731 if (FrameView* frameView = view->frameView()) {
2732 LayoutRect viewportRect = frameView->viewportConstrainedVisibleConte ntRect();
2733 return containingBlock->isHorizontalWritingMode() ? viewportRect.wid th() : viewportRect.height();
2734 }
2735 }
2736
2737 if (hasOverrideContainingBlockLogicalWidth())
2738 return overrideContainingBlockContentLogicalWidth();
2739
2740 if (containingBlock->isBox())
2741 return toRenderBox(containingBlock)->clientLogicalWidth();
2742
2743 ASSERT(containingBlock->isRenderInline() && containingBlock->isRelPositioned ());
2744
2745 const RenderInline* flow = toRenderInline(containingBlock);
2746 InlineFlowBox* first = flow->firstLineBox();
2747 InlineFlowBox* last = flow->lastLineBox();
2748
2749 // If the containing block is empty, return a width of 0.
2750 if (!first || !last)
2751 return LayoutUnit();
2752
2753 LayoutUnit fromLeft;
2754 LayoutUnit fromRight;
2755 if (containingBlock->style()->isLeftToRightDirection()) {
2756 fromLeft = first->logicalLeft() + first->borderLogicalLeft();
2757 fromRight = last->logicalLeft() + last->logicalWidth() - last->borderLog icalRight();
2758 } else {
2759 fromRight = first->logicalLeft() + first->logicalWidth() - first->border LogicalRight();
2760 fromLeft = last->logicalLeft() + last->borderLogicalLeft();
2761 }
2762
2763 return std::max(LayoutUnit(), fromRight - fromLeft);
2764 }
2765
2766 LayoutUnit RenderBox::containingBlockLogicalHeightForPositioned(const LayoutBoxM odelObject* containingBlock, bool checkForPerpendicularWritingMode) const
2767 {
2768 if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWriting Mode() != isHorizontalWritingMode())
2769 return containingBlockLogicalWidthForPositioned(containingBlock, false);
2770
2771 // Use viewport as container for top-level fixed-position elements.
2772 if (style()->position() == FixedPosition && containingBlock->isRenderView()) {
2773 const RenderView* view = toRenderView(containingBlock);
2774 if (FrameView* frameView = view->frameView()) {
2775 LayoutRect viewportRect = frameView->viewportConstrainedVisibleConte ntRect();
2776 return containingBlock->isHorizontalWritingMode() ? viewportRect.hei ght() : viewportRect.width();
2777 }
2778 }
2779
2780 if (hasOverrideContainingBlockLogicalHeight())
2781 return overrideContainingBlockContentLogicalHeight();
2782
2783 if (containingBlock->isBox()) {
2784 const RenderBlock* cb = containingBlock->isRenderBlock() ?
2785 toRenderBlock(containingBlock) : containingBlock->containingBlock();
2786 return cb->clientLogicalHeight();
2787 }
2788
2789 ASSERT(containingBlock->isRenderInline() && containingBlock->isRelPositioned ());
2790
2791 const RenderInline* flow = toRenderInline(containingBlock);
2792 InlineFlowBox* first = flow->firstLineBox();
2793 InlineFlowBox* last = flow->lastLineBox();
2794
2795 // If the containing block is empty, return a height of 0.
2796 if (!first || !last)
2797 return LayoutUnit();
2798
2799 LayoutUnit heightResult;
2800 LayoutRect boundingBox = flow->linesBoundingBox();
2801 if (containingBlock->isHorizontalWritingMode())
2802 heightResult = boundingBox.height();
2803 else
2804 heightResult = boundingBox.width();
2805 heightResult -= (containingBlock->borderBefore() + containingBlock->borderAf ter());
2806 return heightResult;
2807 }
2808
2809 static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRigh t, const RenderBox* child, const LayoutBoxModelObject* containerBlock, LayoutUni t containerLogicalWidth)
2810 {
2811 if (!logicalLeft.isAuto() || !logicalRight.isAuto())
2812 return;
2813
2814 // FIXME: The static distance computation has not been patched for mixed wri ting modes yet.
2815 if (child->parent()->style()->direction() == LTR) {
2816 LayoutUnit staticPosition = child->layer()->staticInlinePosition() - con tainerBlock->borderLogicalLeft();
2817 for (LayoutObject* curr = child->parent(); curr && curr != containerBloc k; curr = curr->container()) {
2818 if (curr->isBox()) {
2819 staticPosition += toRenderBox(curr)->logicalLeft();
2820 if (toRenderBox(curr)->isRelPositioned())
2821 staticPosition += toRenderBox(curr)->relativePositionOffset( ).width();
2822 } else if (curr->isInline()) {
2823 if (curr->isRelPositioned()) {
2824 if (!curr->style()->logicalLeft().isAuto())
2825 staticPosition += valueForLength(curr->style()->logicalL eft(), curr->containingBlock()->availableWidth());
2826 else
2827 staticPosition -= valueForLength(curr->style()->logicalR ight(), curr->containingBlock()->availableWidth());
2828 }
2829 }
2830 }
2831 logicalLeft.setValue(Fixed, staticPosition);
2832 } else {
2833 RenderBox* enclosingBox = child->parent()->enclosingBox();
2834 LayoutUnit staticPosition = child->layer()->staticInlinePosition() + con tainerLogicalWidth + containerBlock->borderLogicalLeft();
2835 for (LayoutObject* curr = child->parent(); curr; curr = curr->container( )) {
2836 if (curr->isBox()) {
2837 if (curr != containerBlock) {
2838 staticPosition -= toRenderBox(curr)->logicalLeft();
2839 if (toRenderBox(curr)->isRelPositioned())
2840 staticPosition -= toRenderBox(curr)->relativePositionOff set().width();
2841 }
2842 if (curr == enclosingBox)
2843 staticPosition -= enclosingBox->logicalWidth();
2844 } else if (curr->isInline()) {
2845 if (curr->isRelPositioned()) {
2846 if (!curr->style()->logicalLeft().isAuto())
2847 staticPosition -= valueForLength(curr->style()->logicalL eft(), curr->containingBlock()->availableWidth());
2848 else
2849 staticPosition += valueForLength(curr->style()->logicalR ight(), curr->containingBlock()->availableWidth());
2850 }
2851 }
2852 if (curr == containerBlock)
2853 break;
2854 }
2855 logicalRight.setValue(Fixed, staticPosition);
2856 }
2857 }
2858
2859 void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& compu tedValues) const
2860 {
2861 if (isReplaced()) {
2862 computePositionedLogicalWidthReplaced(computedValues);
2863 return;
2864 }
2865
2866 // QUESTIONS
2867 // FIXME 1: Should we still deal with these the cases of 'left' or 'right' h aving
2868 // the type 'static' in determining whether to calculate the static distance ?
2869 // NOTE: 'static' is not a legal value for 'left' or 'right' as of CSS 2.1.
2870
2871 // FIXME 2: Can perhaps optimize out cases when max-width/min-width are grea ter
2872 // than or less than the computed width(). Be careful of box-sizing and
2873 // percentage issues.
2874
2875 // The following is based off of the W3C Working Draft from April 11, 2006 o f
2876 // CSS 2.1: Section 10.3.7 "Absolutely positioned, non-replaced elements"
2877 // <http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width>
2878 // (block-style-comments in this function and in computePositionedLogicalWid thUsing()
2879 // correspond to text from the spec)
2880
2881
2882 // We don't use containingBlock(), since we may be positioned by an enclosin g
2883 // relative positioned inline.
2884 const LayoutBoxModelObject* containerBlock = toLayoutBoxModelObject(containe r());
2885
2886 const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPosit ioned(containerBlock);
2887
2888 // Use the container block's direction except when calculating the static di stance
2889 // This conforms with the reference results for abspos-replaced-width-margin -000.htm
2890 // of the CSS 2.1 test suite
2891 TextDirection containerDirection = containerBlock->style()->direction();
2892
2893 bool isHorizontal = isHorizontalWritingMode();
2894 const LayoutUnit bordersPlusPadding = borderAndPaddingLogicalWidth();
2895 const Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : styl e()->marginTop();
2896 const Length marginLogicalRight = isHorizontal ? style()->marginRight() : st yle()->marginBottom();
2897
2898 Length logicalLeftLength = style()->logicalLeft();
2899 Length logicalRightLength = style()->logicalRight();
2900
2901 /*-------------------------------------------------------------------------- -*\
2902 * For the purposes of this section and the next, the term "static position"
2903 * (of an element) refers, roughly, to the position an element would have ha d
2904 * in the normal flow. More precisely:
2905 *
2906 * * The static position for 'left' is the distance from the left edge of th e
2907 * containing block to the left margin edge of a hypothetical box that wou ld
2908 * have been the first box of the element if its 'position' property had
2909 * been 'static' and 'float' had been 'none'. The value is negative if the
2910 * hypothetical box is to the left of the containing block.
2911 * * The static position for 'right' is the distance from the right edge of the
2912 * containing block to the right margin edge of the same hypothetical box as
2913 * above. The value is positive if the hypothetical box is to the left of the
2914 * containing block's edge.
2915 *
2916 * But rather than actually calculating the dimensions of that hypothetical box,
2917 * user agents are free to make a guess at its probable position.
2918 *
2919 * For the purposes of calculating the static position, the containing block of
2920 * fixed positioned elements is the initial containing block instead of the
2921 * viewport, and all scrollable boxes should be assumed to be scrolled to th eir
2922 * origin.
2923 \*-------------------------------------------------------------------------- -*/
2924
2925 // see FIXME 1
2926 // Calculate the static distance if needed.
2927 computeInlineStaticDistance(logicalLeftLength, logicalRightLength, this, con tainerBlock, containerLogicalWidth);
2928
2929 // Calculate constraint equation values for 'width' case.
2930 computePositionedLogicalWidthUsing(style()->logicalWidth(), containerBlock, containerDirection,
2931 containerLogicalWidth, bordersPlusPadding ,
2932 logicalLeftLength, logicalRightLength, ma rginLogicalLeft, marginLogicalRight,
2933 computedValues);
2934
2935 // Calculate constraint equation values for 'max-width' case.
2936 if (!style()->logicalMaxWidth().isMaxSizeNone()) {
2937 LogicalExtentComputedValues maxValues;
2938
2939 computePositionedLogicalWidthUsing(style()->logicalMaxWidth(), container Block, containerDirection,
2940 containerLogicalWidth, bordersPlusPad ding,
2941 logicalLeftLength, logicalRightLength , marginLogicalLeft, marginLogicalRight,
2942 maxValues);
2943
2944 if (computedValues.m_extent > maxValues.m_extent) {
2945 computedValues.m_extent = maxValues.m_extent;
2946 computedValues.m_position = maxValues.m_position;
2947 computedValues.m_margins.m_start = maxValues.m_margins.m_start;
2948 computedValues.m_margins.m_end = maxValues.m_margins.m_end;
2949 }
2950 }
2951
2952 // Calculate constraint equation values for 'min-width' case.
2953 if (!style()->logicalMinWidth().isZero() || style()->logicalMinWidth().isInt rinsic()) {
2954 LogicalExtentComputedValues minValues;
2955
2956 computePositionedLogicalWidthUsing(style()->logicalMinWidth(), container Block, containerDirection,
2957 containerLogicalWidth, bordersPlusPad ding,
2958 logicalLeftLength, logicalRightLength , marginLogicalLeft, marginLogicalRight,
2959 minValues);
2960
2961 if (computedValues.m_extent < minValues.m_extent) {
2962 computedValues.m_extent = minValues.m_extent;
2963 computedValues.m_position = minValues.m_position;
2964 computedValues.m_margins.m_start = minValues.m_margins.m_start;
2965 computedValues.m_margins.m_end = minValues.m_margins.m_end;
2966 }
2967 }
2968
2969 if (!style()->hasStaticInlinePosition(isHorizontal))
2970 computedValues.m_position += extraInlineOffset();
2971
2972 computedValues.m_extent += bordersPlusPadding;
2973 }
2974
2975 static void computeLogicalLeftPositionedOffset(LayoutUnit& logicalLeftPos, const RenderBox* child, LayoutUnit logicalWidthValue, const LayoutBoxModelObject* con tainerBlock, LayoutUnit containerLogicalWidth)
2976 {
2977 // Deal with differing writing modes here. Our offset needs to be in the co ntaining block's coordinate space. If the containing block is flipped
2978 // along this axis, then we need to flip the coordinate. This can only happ en if the containing block is both a flipped mode and perpendicular to us.
2979 if (containerBlock->isHorizontalWritingMode() != child->isHorizontalWritingM ode() && containerBlock->style()->isFlippedBlocksWritingMode()) {
2980 logicalLeftPos = containerLogicalWidth - logicalWidthValue - logicalLeft Pos;
2981 logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->bo rderRight() : containerBlock->borderBottom());
2982 } else {
2983 logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->bo rderLeft() : containerBlock->borderTop());
2984 }
2985 }
2986
2987 LayoutUnit RenderBox::shrinkToFitLogicalWidth(LayoutUnit availableLogicalWidth, LayoutUnit bordersPlusPadding) const
2988 {
2989 LayoutUnit preferredLogicalWidth = maxPreferredLogicalWidth() - bordersPlusP adding;
2990 LayoutUnit preferredMinLogicalWidth = minPreferredLogicalWidth() - bordersPl usPadding;
2991 return std::min(std::max(preferredMinLogicalWidth, availableLogicalWidth), p referredLogicalWidth);
2992 }
2993
2994 void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const La youtBoxModelObject* containerBlock, TextDirection containerDirection,
2995 LayoutUnit containerLogicalWi dth, LayoutUnit bordersPlusPadding,
2996 const Length& logicalLeft, co nst Length& logicalRight, const Length& marginLogicalLeft,
2997 const Length& marginLogicalRi ght, LogicalExtentComputedValues& computedValues) const
2998 {
2999 if (logicalWidth.isIntrinsic())
3000 logicalWidth = Length(computeIntrinsicLogicalWidthUsing(logicalWidth, co ntainerLogicalWidth, bordersPlusPadding) - bordersPlusPadding, Fixed);
3001
3002 // 'left' and 'right' cannot both be 'auto' because one would of been
3003 // converted to the static position already
3004 ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto()));
3005
3006 // minimumValueForLength will convert 'auto' to 0 so that it doesn't impact the available space computation below.
3007 LayoutUnit logicalLeftValue = minimumValueForLength(logicalLeft, containerLo gicalWidth);
3008 LayoutUnit logicalRightValue = minimumValueForLength(logicalRight, container LogicalWidth);
3009
3010 const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidth ForPositioned(containerBlock, false);
3011
3012 bool logicalWidthIsAuto = logicalWidth.isIntrinsicOrAuto();
3013 bool logicalLeftIsAuto = logicalLeft.isAuto();
3014 bool logicalRightIsAuto = logicalRight.isAuto();
3015 LayoutUnit& marginLogicalLeftValue = style()->isLeftToRightDirection() ? com putedValues.m_margins.m_start : computedValues.m_margins.m_end;
3016 LayoutUnit& marginLogicalRightValue = style()->isLeftToRightDirection() ? co mputedValues.m_margins.m_end : computedValues.m_margins.m_start;
3017 if (!logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) {
3018 /*---------------------------------------------------------------------- -*\
3019 * If none of the three is 'auto': If both 'margin-left' and 'margin-
3020 * right' are 'auto', solve the equation under the extra constraint that
3021 * the two margins get equal values, unless this would make them negativ e,
3022 * in which case when direction of the containing block is 'ltr' ('rtl') ,
3023 * set 'margin-left' ('margin-right') to zero and solve for 'margin-righ t'
3024 * ('margin-left'). If one of 'margin-left' or 'margin-right' is 'auto',
3025 * solve the equation for that value. If the values are over-constrained ,
3026 * ignore the value for 'left' (in case the 'direction' property of the
3027 * containing block is 'rtl') or 'right' (in case 'direction' is 'ltr')
3028 * and solve for that value.
3029 \*---------------------------------------------------------------------- -*/
3030 // NOTE: It is not necessary to solve for 'right' in the over constrain ed
3031 // case because the value is not used for any further calculations.
3032
3033 computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(value ForLength(logicalWidth, containerLogicalWidth));
3034
3035 const LayoutUnit availableSpace = containerLogicalWidth - (logicalLeftVa lue + computedValues.m_extent + logicalRightValue + bordersPlusPadding);
3036
3037 // Margins are now the only unknown
3038 if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) {
3039 // Both margins auto, solve for equality
3040 if (availableSpace >= 0) {
3041 marginLogicalLeftValue = availableSpace / 2; // split the differ ence
3042 marginLogicalRightValue = availableSpace - marginLogicalLeftValu e; // account for odd valued differences
3043 } else {
3044 // Use the containing block's direction rather than the parent b lock's
3045 // per CSS 2.1 reference test abspos-non-replaced-width-margin-0 00.
3046 if (containerDirection == LTR) {
3047 marginLogicalLeftValue = 0;
3048 marginLogicalRightValue = availableSpace; // will be negativ e
3049 } else {
3050 marginLogicalLeftValue = availableSpace; // will be negative
3051 marginLogicalRightValue = 0;
3052 }
3053 }
3054 } else if (marginLogicalLeft.isAuto()) {
3055 // Solve for left margin
3056 marginLogicalRightValue = valueForLength(marginLogicalRight, contain erRelativeLogicalWidth);
3057 marginLogicalLeftValue = availableSpace - marginLogicalRightValue;
3058 } else if (marginLogicalRight.isAuto()) {
3059 // Solve for right margin
3060 marginLogicalLeftValue = valueForLength(marginLogicalLeft, container RelativeLogicalWidth);
3061 marginLogicalRightValue = availableSpace - marginLogicalLeftValue;
3062 } else {
3063 // Over-constrained, solve for left if direction is RTL
3064 marginLogicalLeftValue = valueForLength(marginLogicalLeft, container RelativeLogicalWidth);
3065 marginLogicalRightValue = valueForLength(marginLogicalRight, contain erRelativeLogicalWidth);
3066
3067 // Use the containing block's direction rather than the parent block 's
3068 // per CSS 2.1 reference test abspos-non-replaced-width-margin-000.
3069 if (containerDirection == RTL)
3070 logicalLeftValue = (availableSpace + logicalLeftValue) - marginL ogicalLeftValue - marginLogicalRightValue;
3071 }
3072 } else {
3073 /*--------------------------------------------------------------------*\
3074 * Otherwise, set 'auto' values for 'margin-left' and 'margin-right'
3075 * to 0, and pick the one of the following six rules that applies.
3076 *
3077 * 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the
3078 * width is shrink-to-fit. Then solve for 'left'
3079 *
3080 * OMIT RULE 2 AS IT SHOULD NEVER BE HIT
3081 * ------------------------------------------------------------------
3082 * 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if
3083 * the 'direction' property of the containing block is 'ltr' set
3084 * 'left' to the static position, otherwise set 'right' to the
3085 * static position. Then solve for 'left' (if 'direction is 'rtl')
3086 * or 'right' (if 'direction' is 'ltr').
3087 * ------------------------------------------------------------------
3088 *
3089 * 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the
3090 * width is shrink-to-fit . Then solve for 'right'
3091 * 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve
3092 * for 'left'
3093 * 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve
3094 * for 'width'
3095 * 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve
3096 * for 'right'
3097 *
3098 * Calculation of the shrink-to-fit width is similar to calculating the
3099 * width of a table cell using the automatic table layout algorithm.
3100 * Roughly: calculate the preferred width by formatting the content
3101 * without breaking lines other than where explicit line breaks occur,
3102 * and also calculate the preferred minimum width, e.g., by trying all
3103 * possible line breaks. CSS 2.1 does not define the exact algorithm.
3104 * Thirdly, calculate the available width: this is found by solving
3105 * for 'width' after setting 'left' (in case 1) or 'right' (in case 3)
3106 * to 0.
3107 *
3108 * Then the shrink-to-fit width is:
3109 * min(max(preferred minimum width, available width), preferred width).
3110 \*--------------------------------------------------------------------*/
3111 // NOTE: For rules 3 and 6 it is not necessary to solve for 'right'
3112 // because the value is not used for any further calculations.
3113
3114 // Calculate margins, 'auto' margins are ignored.
3115 marginLogicalLeftValue = minimumValueForLength(marginLogicalLeft, contai nerRelativeLogicalWidth);
3116 marginLogicalRightValue = minimumValueForLength(marginLogicalRight, cont ainerRelativeLogicalWidth);
3117
3118 const LayoutUnit availableSpace = containerLogicalWidth - (marginLogical LeftValue + marginLogicalRightValue + logicalLeftValue + logicalRightValue + bor dersPlusPadding);
3119
3120 // FIXME: Is there a faster way to find the correct case?
3121 // Use rule/case that applies.
3122 if (logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) {
3123 // RULE 1: (use shrink-to-fit for width, and solve of left)
3124 computedValues.m_extent = shrinkToFitLogicalWidth(availableSpace, bo rdersPlusPadding);
3125 logicalLeftValue = availableSpace - computedValues.m_extent;
3126 } else if (!logicalLeftIsAuto && logicalWidthIsAuto && logicalRightIsAut o) {
3127 // RULE 3: (use shrink-to-fit for width, and no need solve of right)
3128 computedValues.m_extent = shrinkToFitLogicalWidth(availableSpace, bo rdersPlusPadding);
3129 } else if (logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAu to) {
3130 // RULE 4: (solve for left)
3131 computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(v alueForLength(logicalWidth, containerLogicalWidth));
3132 logicalLeftValue = availableSpace - computedValues.m_extent;
3133 } else if (!logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAu to) {
3134 // RULE 5: (solve for width)
3135 if (autoWidthShouldFitContent())
3136 computedValues.m_extent = shrinkToFitLogicalWidth(availableSpace , bordersPlusPadding);
3137 else
3138 computedValues.m_extent = std::max(LayoutUnit(), availableSpace) ;
3139 } else if (!logicalLeftIsAuto && !logicalWidthIsAuto && logicalRightIsAu to) {
3140 // RULE 6: (no need solve for right)
3141 computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(v alueForLength(logicalWidth, containerLogicalWidth));
3142 }
3143 }
3144
3145 // Use computed values to calculate the horizontal position.
3146
3147 // FIXME: This hack is needed to calculate the logical left position for a 'rtl' relatively
3148 // positioned, inline because right now, it is using the logical left positi on
3149 // of the first line box when really it should use the last line box. When
3150 // this is fixed elsewhere, this block should be removed.
3151 if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRi ghtDirection()) {
3152 const RenderInline* flow = toRenderInline(containerBlock);
3153 InlineFlowBox* firstLine = flow->firstLineBox();
3154 InlineFlowBox* lastLine = flow->lastLineBox();
3155 if (firstLine && lastLine && firstLine != lastLine) {
3156 computedValues.m_position = logicalLeftValue + marginLogicalLeftValu e + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logica lLeft());
3157 return;
3158 }
3159 }
3160
3161 if (containerBlock->isBox() && toRenderBox(containerBlock)->scrollsOverflowY () && containerBlock->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft() ) {
3162 logicalLeftValue = logicalLeftValue + toRenderBox(containerBlock)->verti calScrollbarWidth();
3163 }
3164
3165 computedValues.m_position = logicalLeftValue + marginLogicalLeftValue;
3166 computeLogicalLeftPositionedOffset(computedValues.m_position, this, computed Values.m_extent, containerBlock, containerLogicalWidth);
3167 }
3168
3169 static void computeBlockStaticDistance(Length& logicalTop, Length& logicalBottom , const RenderBox* child, const LayoutBoxModelObject* containerBlock)
3170 {
3171 if (!logicalTop.isAuto() || !logicalBottom.isAuto())
3172 return;
3173
3174 // FIXME: The static distance computation has not been patched for mixed wri ting modes.
3175 LayoutUnit staticLogicalTop = child->layer()->staticBlockPosition() - contai nerBlock->borderBefore();
3176 for (LayoutObject* curr = child->parent(); curr && curr != containerBlock; c urr = curr->container()) {
3177 if (curr->isBox() && !curr->isTableRow())
3178 staticLogicalTop += toRenderBox(curr)->logicalTop();
3179 }
3180 logicalTop.setValue(Fixed, staticLogicalTop);
3181 }
3182
3183 void RenderBox::computePositionedLogicalHeight(LogicalExtentComputedValues& comp utedValues) const
3184 {
3185 if (isReplaced()) {
3186 computePositionedLogicalHeightReplaced(computedValues);
3187 return;
3188 }
3189
3190 // The following is based off of the W3C Working Draft from April 11, 2006 o f
3191 // CSS 2.1: Section 10.6.4 "Absolutely positioned, non-replaced elements"
3192 // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-non-replace d-height>
3193 // (block-style-comments in this function and in computePositionedLogicalHei ghtUsing()
3194 // correspond to text from the spec)
3195
3196
3197 // We don't use containingBlock(), since we may be positioned by an enclosin g relpositioned inline.
3198 const LayoutBoxModelObject* containerBlock = toLayoutBoxModelObject(containe r());
3199
3200 const LayoutUnit containerLogicalHeight = containingBlockLogicalHeightForPos itioned(containerBlock);
3201
3202 const LayoutStyle& styleToUse = styleRef();
3203 const LayoutUnit bordersPlusPadding = borderAndPaddingLogicalHeight();
3204 const Length marginBefore = styleToUse.marginBefore();
3205 const Length marginAfter = styleToUse.marginAfter();
3206 Length logicalTopLength = styleToUse.logicalTop();
3207 Length logicalBottomLength = styleToUse.logicalBottom();
3208
3209 /*-------------------------------------------------------------------------- -*\
3210 * For the purposes of this section and the next, the term "static position"
3211 * (of an element) refers, roughly, to the position an element would have ha d
3212 * in the normal flow. More precisely, the static position for 'top' is the
3213 * distance from the top edge of the containing block to the top margin edge
3214 * of a hypothetical box that would have been the first box of the element i f
3215 * its 'position' property had been 'static' and 'float' had been 'none'. Th e
3216 * value is negative if the hypothetical box is above the containing block.
3217 *
3218 * But rather than actually calculating the dimensions of that hypothetical
3219 * box, user agents are free to make a guess at its probable position.
3220 *
3221 * For the purposes of calculating the static position, the containing block
3222 * of fixed positioned elements is the initial containing block instead of
3223 * the viewport.
3224 \*-------------------------------------------------------------------------- -*/
3225
3226 // see FIXME 1
3227 // Calculate the static distance if needed.
3228 computeBlockStaticDistance(logicalTopLength, logicalBottomLength, this, cont ainerBlock);
3229
3230 // Calculate constraint equation values for 'height' case.
3231 LayoutUnit logicalHeight = computedValues.m_extent;
3232 computePositionedLogicalHeightUsing(styleToUse.logicalHeight(), containerBlo ck, containerLogicalHeight, bordersPlusPadding, logicalHeight,
3233 logicalTopLength, logicalBottomLength, m arginBefore, marginAfter,
3234 computedValues);
3235
3236 // Avoid doing any work in the common case (where the values of min-height a nd max-height are their defaults).
3237 // see FIXME 2
3238
3239 // Calculate constraint equation values for 'max-height' case.
3240 if (!styleToUse.logicalMaxHeight().isMaxSizeNone()) {
3241 LogicalExtentComputedValues maxValues;
3242
3243 computePositionedLogicalHeightUsing(styleToUse.logicalMaxHeight(), conta inerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight,
3244 logicalTopLength, logicalBottomLengt h, marginBefore, marginAfter,
3245 maxValues);
3246
3247 if (computedValues.m_extent > maxValues.m_extent) {
3248 computedValues.m_extent = maxValues.m_extent;
3249 computedValues.m_position = maxValues.m_position;
3250 computedValues.m_margins.m_before = maxValues.m_margins.m_before;
3251 computedValues.m_margins.m_after = maxValues.m_margins.m_after;
3252 }
3253 }
3254
3255 // Calculate constraint equation values for 'min-height' case.
3256 if (!styleToUse.logicalMinHeight().isZero() || styleToUse.logicalMinHeight() .isIntrinsic()) {
3257 LogicalExtentComputedValues minValues;
3258
3259 computePositionedLogicalHeightUsing(styleToUse.logicalMinHeight(), conta inerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight,
3260 logicalTopLength, logicalBottomLengt h, marginBefore, marginAfter,
3261 minValues);
3262
3263 if (computedValues.m_extent < minValues.m_extent) {
3264 computedValues.m_extent = minValues.m_extent;
3265 computedValues.m_position = minValues.m_position;
3266 computedValues.m_margins.m_before = minValues.m_margins.m_before;
3267 computedValues.m_margins.m_after = minValues.m_margins.m_after;
3268 }
3269 }
3270
3271 if (!style()->hasStaticBlockPosition(isHorizontalWritingMode()))
3272 computedValues.m_position += extraBlockOffset();
3273
3274 // Set final height value.
3275 computedValues.m_extent += bordersPlusPadding;
3276 }
3277
3278 static void computeLogicalTopPositionedOffset(LayoutUnit& logicalTopPos, const R enderBox* child, LayoutUnit logicalHeightValue, const LayoutBoxModelObject* cont ainerBlock, LayoutUnit containerLogicalHeight)
3279 {
3280 // Deal with differing writing modes here. Our offset needs to be in the co ntaining block's coordinate space. If the containing block is flipped
3281 // along this axis, then we need to flip the coordinate. This can only happ en if the containing block is both a flipped mode and perpendicular to us.
3282 if ((child->style()->isFlippedBlocksWritingMode() && child->isHorizontalWrit ingMode() != containerBlock->isHorizontalWritingMode())
3283 || (child->style()->isFlippedBlocksWritingMode() != containerBlock->styl e()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() == contain erBlock->isHorizontalWritingMode()))
3284 logicalTopPos = containerLogicalHeight - logicalHeightValue - logicalTop Pos;
3285
3286 // Our offset is from the logical bottom edge in a flipped environment, e.g. , right for vertical-rl and bottom for horizontal-bt.
3287 if (containerBlock->style()->isFlippedBlocksWritingMode() && child->isHorizo ntalWritingMode() == containerBlock->isHorizontalWritingMode()) {
3288 if (child->isHorizontalWritingMode())
3289 logicalTopPos += containerBlock->borderBottom();
3290 else
3291 logicalTopPos += containerBlock->borderRight();
3292 } else {
3293 if (child->isHorizontalWritingMode())
3294 logicalTopPos += containerBlock->borderTop();
3295 else
3296 logicalTopPos += containerBlock->borderLeft();
3297 }
3298 }
3299
3300 void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength, const LayoutBoxModelObject* containerBlock,
3301 LayoutUnit containerLogicalH eight, LayoutUnit bordersPlusPadding, LayoutUnit logicalHeight,
3302 const Length& logicalTop, co nst Length& logicalBottom, const Length& marginBefore,
3303 const Length& marginAfter, L ogicalExtentComputedValues& computedValues) const
3304 {
3305 // 'top' and 'bottom' cannot both be 'auto' because 'top would of been
3306 // converted to the static position in computePositionedLogicalHeight()
3307 ASSERT(!(logicalTop.isAuto() && logicalBottom.isAuto()));
3308
3309 LayoutUnit logicalHeightValue;
3310 LayoutUnit contentLogicalHeight = logicalHeight - bordersPlusPadding;
3311
3312 const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidth ForPositioned(containerBlock, false);
3313
3314 LayoutUnit logicalTopValue = 0;
3315
3316 bool logicalHeightIsAuto = logicalHeightLength.isAuto();
3317 bool logicalTopIsAuto = logicalTop.isAuto();
3318 bool logicalBottomIsAuto = logicalBottom.isAuto();
3319
3320 LayoutUnit resolvedLogicalHeight;
3321 // Height is never unsolved for tables.
3322 if (isTable()) {
3323 resolvedLogicalHeight = contentLogicalHeight;
3324 logicalHeightIsAuto = false;
3325 } else {
3326 if (logicalHeightLength.isIntrinsic())
3327 resolvedLogicalHeight = computeIntrinsicLogicalContentHeightUsing(lo gicalHeightLength, contentLogicalHeight, bordersPlusPadding);
3328 else
3329 resolvedLogicalHeight = adjustContentBoxLogicalHeightForBoxSizing(va lueForLength(logicalHeightLength, containerLogicalHeight));
3330 }
3331
3332 if (!logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) {
3333 /*---------------------------------------------------------------------- -*\
3334 * If none of the three are 'auto': If both 'margin-top' and 'margin-
3335 * bottom' are 'auto', solve the equation under the extra constraint tha t
3336 * the two margins get equal values. If one of 'margin-top' or 'margin-
3337 * bottom' is 'auto', solve the equation for that value. If the values
3338 * are over-constrained, ignore the value for 'bottom' and solve for tha t
3339 * value.
3340 \*---------------------------------------------------------------------- -*/
3341 // NOTE: It is not necessary to solve for 'bottom' in the over constrai ned
3342 // case because the value is not used for any further calculations.
3343
3344 logicalHeightValue = resolvedLogicalHeight;
3345 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3346
3347 const LayoutUnit availableSpace = containerLogicalHeight - (logicalTopVa lue + logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight) + bordersPlusPadding);
3348
3349 // Margins are now the only unknown
3350 if (marginBefore.isAuto() && marginAfter.isAuto()) {
3351 // Both margins auto, solve for equality
3352 // NOTE: This may result in negative values.
3353 computedValues.m_margins.m_before = availableSpace / 2; // split the difference
3354 computedValues.m_margins.m_after = availableSpace - computedValues.m _margins.m_before; // account for odd valued differences
3355 } else if (marginBefore.isAuto()) {
3356 // Solve for top margin
3357 computedValues.m_margins.m_after = valueForLength(marginAfter, conta inerRelativeLogicalWidth);
3358 computedValues.m_margins.m_before = availableSpace - computedValues. m_margins.m_after;
3359 } else if (marginAfter.isAuto()) {
3360 // Solve for bottom margin
3361 computedValues.m_margins.m_before = valueForLength(marginBefore, con tainerRelativeLogicalWidth);
3362 computedValues.m_margins.m_after = availableSpace - computedValues.m _margins.m_before;
3363 } else {
3364 // Over-constrained, (no need solve for bottom)
3365 computedValues.m_margins.m_before = valueForLength(marginBefore, con tainerRelativeLogicalWidth);
3366 computedValues.m_margins.m_after = valueForLength(marginAfter, conta inerRelativeLogicalWidth);
3367 }
3368 } else {
3369 /*--------------------------------------------------------------------*\
3370 * Otherwise, set 'auto' values for 'margin-top' and 'margin-bottom'
3371 * to 0, and pick the one of the following six rules that applies.
3372 *
3373 * 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then
3374 * the height is based on the content, and solve for 'top'.
3375 *
3376 * OMIT RULE 2 AS IT SHOULD NEVER BE HIT
3377 * ------------------------------------------------------------------
3378 * 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then
3379 * set 'top' to the static position, and solve for 'bottom'.
3380 * ------------------------------------------------------------------
3381 *
3382 * 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then
3383 * the height is based on the content, and solve for 'bottom'.
3384 * 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', and
3385 * solve for 'top'.
3386 * 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', and
3387 * solve for 'height'.
3388 * 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', and
3389 * solve for 'bottom'.
3390 \*--------------------------------------------------------------------*/
3391 // NOTE: For rules 3 and 6 it is not necessary to solve for 'bottom'
3392 // because the value is not used for any further calculations.
3393
3394 // Calculate margins, 'auto' margins are ignored.
3395 computedValues.m_margins.m_before = minimumValueForLength(marginBefore, containerRelativeLogicalWidth);
3396 computedValues.m_margins.m_after = minimumValueForLength(marginAfter, co ntainerRelativeLogicalWidth);
3397
3398 const LayoutUnit availableSpace = containerLogicalHeight - (computedValu es.m_margins.m_before + computedValues.m_margins.m_after + bordersPlusPadding);
3399
3400 // Use rule/case that applies.
3401 if (logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) {
3402 // RULE 1: (height is content based, solve of top)
3403 logicalHeightValue = contentLogicalHeight;
3404 logicalTopValue = availableSpace - (logicalHeightValue + valueForLen gth(logicalBottom, containerLogicalHeight));
3405 } else if (!logicalTopIsAuto && logicalHeightIsAuto && logicalBottomIsAu to) {
3406 // RULE 3: (height is content based, no need solve of bottom)
3407 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight) ;
3408 logicalHeightValue = contentLogicalHeight;
3409 } else if (logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsA uto) {
3410 // RULE 4: (solve of top)
3411 logicalHeightValue = resolvedLogicalHeight;
3412 logicalTopValue = availableSpace - (logicalHeightValue + valueForLen gth(logicalBottom, containerLogicalHeight));
3413 } else if (!logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsA uto) {
3414 // RULE 5: (solve of height)
3415 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight) ;
3416 logicalHeightValue = std::max(LayoutUnit(), availableSpace - (logica lTopValue + valueForLength(logicalBottom, containerLogicalHeight)));
3417 } else if (!logicalTopIsAuto && !logicalHeightIsAuto && logicalBottomIsA uto) {
3418 // RULE 6: (no need solve of bottom)
3419 logicalHeightValue = resolvedLogicalHeight;
3420 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight) ;
3421 }
3422 }
3423 computedValues.m_extent = logicalHeightValue;
3424
3425 // Use computed values to calculate the vertical position.
3426 computedValues.m_position = logicalTopValue + computedValues.m_margins.m_bef ore;
3427 computeLogicalTopPositionedOffset(computedValues.m_position, this, logicalHe ightValue, containerBlock, containerLogicalHeight);
3428 }
3429
3430 void RenderBox::computePositionedLogicalWidthReplaced(LogicalExtentComputedValue s& computedValues) const
3431 {
3432 // The following is based off of the W3C Working Draft from April 11, 2006 o f
3433 // CSS 2.1: Section 10.3.8 "Absolutely positioned, replaced elements"
3434 // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-wi dth>
3435 // (block-style-comments in this function correspond to text from the spec a nd
3436 // the numbers correspond to numbers in spec)
3437
3438 // We don't use containingBlock(), since we may be positioned by an enclosin g
3439 // relative positioned inline.
3440 const LayoutBoxModelObject* containerBlock = toLayoutBoxModelObject(containe r());
3441
3442 const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPosit ioned(containerBlock);
3443 const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidth ForPositioned(containerBlock, false);
3444
3445 // To match WinIE, in quirks mode use the parent's 'direction' property
3446 // instead of the the container block's.
3447 TextDirection containerDirection = containerBlock->style()->direction();
3448
3449 // Variables to solve.
3450 bool isHorizontal = isHorizontalWritingMode();
3451 Length logicalLeft = style()->logicalLeft();
3452 Length logicalRight = style()->logicalRight();
3453 Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->m arginTop();
3454 Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()- >marginBottom();
3455 LayoutUnit& marginLogicalLeftAlias = style()->isLeftToRightDirection() ? com putedValues.m_margins.m_start : computedValues.m_margins.m_end;
3456 LayoutUnit& marginLogicalRightAlias = style()->isLeftToRightDirection() ? co mputedValues.m_margins.m_end : computedValues.m_margins.m_start;
3457
3458 /*-----------------------------------------------------------------------*\
3459 * 1. The used value of 'width' is determined as for inline replaced
3460 * elements.
3461 \*-----------------------------------------------------------------------*/
3462 // NOTE: This value of width is final in that the min/max width calculations
3463 // are dealt with in computeReplacedWidth(). This means that the steps to p roduce
3464 // correct max/min in the non-replaced version, are not necessary.
3465 computedValues.m_extent = computeReplacedLogicalWidth() + borderAndPaddingLo gicalWidth();
3466
3467 const LayoutUnit availableSpace = containerLogicalWidth - computedValues.m_e xtent;
3468
3469 /*-----------------------------------------------------------------------*\
3470 * 2. If both 'left' and 'right' have the value 'auto', then if 'direction'
3471 * of the containing block is 'ltr', set 'left' to the static position;
3472 * else if 'direction' is 'rtl', set 'right' to the static position.
3473 \*-----------------------------------------------------------------------*/
3474 // see FIXME 1
3475 computeInlineStaticDistance(logicalLeft, logicalRight, this, containerBlock, containerLogicalWidth);
3476
3477 /*-----------------------------------------------------------------------*\
3478 * 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left'
3479 * or 'margin-right' with '0'.
3480 \*-----------------------------------------------------------------------*/
3481 if (logicalLeft.isAuto() || logicalRight.isAuto()) {
3482 if (marginLogicalLeft.isAuto())
3483 marginLogicalLeft.setValue(Fixed, 0);
3484 if (marginLogicalRight.isAuto())
3485 marginLogicalRight.setValue(Fixed, 0);
3486 }
3487
3488 /*-----------------------------------------------------------------------*\
3489 * 4. If at this point both 'margin-left' and 'margin-right' are still
3490 * 'auto', solve the equation under the extra constraint that the two
3491 * margins must get equal values, unless this would make them negative,
3492 * in which case when the direction of the containing block is 'ltr'
3493 * ('rtl'), set 'margin-left' ('margin-right') to zero and solve for
3494 * 'margin-right' ('margin-left').
3495 \*-----------------------------------------------------------------------*/
3496 LayoutUnit logicalLeftValue = 0;
3497 LayoutUnit logicalRightValue = 0;
3498
3499 if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) {
3500 // 'left' and 'right' cannot be 'auto' due to step 3
3501 ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto()));
3502
3503 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3504 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth);
3505
3506 LayoutUnit difference = availableSpace - (logicalLeftValue + logicalRigh tValue);
3507 if (difference > 0) {
3508 marginLogicalLeftAlias = difference / 2; // split the difference
3509 marginLogicalRightAlias = difference - marginLogicalLeftAlias; // ac count for odd valued differences
3510 } else {
3511 // Use the containing block's direction rather than the parent block 's
3512 // per CSS 2.1 reference test abspos-replaced-width-margin-000.
3513 if (containerDirection == LTR) {
3514 marginLogicalLeftAlias = 0;
3515 marginLogicalRightAlias = difference; // will be negative
3516 } else {
3517 marginLogicalLeftAlias = difference; // will be negative
3518 marginLogicalRightAlias = 0;
3519 }
3520 }
3521
3522 /*-----------------------------------------------------------------------*\
3523 * 5. If at this point there is an 'auto' left, solve the equation for
3524 * that value.
3525 \*-----------------------------------------------------------------------*/
3526 } else if (logicalLeft.isAuto()) {
3527 marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRela tiveLogicalWidth);
3528 marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRe lativeLogicalWidth);
3529 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth);
3530
3531 // Solve for 'left'
3532 logicalLeftValue = availableSpace - (logicalRightValue + marginLogicalLe ftAlias + marginLogicalRightAlias);
3533 } else if (logicalRight.isAuto()) {
3534 marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRela tiveLogicalWidth);
3535 marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRe lativeLogicalWidth);
3536 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3537
3538 // Solve for 'right'
3539 logicalRightValue = availableSpace - (logicalLeftValue + marginLogicalLe ftAlias + marginLogicalRightAlias);
3540 } else if (marginLogicalLeft.isAuto()) {
3541 marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRe lativeLogicalWidth);
3542 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3543 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth);
3544
3545 // Solve for 'margin-left'
3546 marginLogicalLeftAlias = availableSpace - (logicalLeftValue + logicalRig htValue + marginLogicalRightAlias);
3547 } else if (marginLogicalRight.isAuto()) {
3548 marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRela tiveLogicalWidth);
3549 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3550 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth);
3551
3552 // Solve for 'margin-right'
3553 marginLogicalRightAlias = availableSpace - (logicalLeftValue + logicalRi ghtValue + marginLogicalLeftAlias);
3554 } else {
3555 // Nothing is 'auto', just calculate the values.
3556 marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRela tiveLogicalWidth);
3557 marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRe lativeLogicalWidth);
3558 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth);
3559 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3560 // If the containing block is right-to-left, then push the left position as far to the right as possible
3561 if (containerDirection == RTL) {
3562 int totalLogicalWidth = computedValues.m_extent + logicalLeftValue + logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias;
3563 logicalLeftValue = containerLogicalWidth - (totalLogicalWidth - logi calLeftValue);
3564 }
3565 }
3566
3567 /*-----------------------------------------------------------------------*\
3568 * 6. If at this point the values are over-constrained, ignore the value
3569 * for either 'left' (in case the 'direction' property of the
3570 * containing block is 'rtl') or 'right' (in case 'direction' is
3571 * 'ltr') and solve for that value.
3572 \*-----------------------------------------------------------------------*/
3573 // NOTE: Constraints imposed by the width of the containing block and its co ntent have already been accounted for above.
3574
3575 // FIXME: Deal with differing writing modes here. Our offset needs to be in the containing block's coordinate space, so that
3576 // can make the result here rather complicated to compute.
3577
3578 // Use computed values to calculate the horizontal position.
3579
3580 // FIXME: This hack is needed to calculate the logical left position for a ' rtl' relatively
3581 // positioned, inline containing block because right now, it is using the lo gical left position
3582 // of the first line box when really it should use the last line box. When
3583 // this is fixed elsewhere, this block should be removed.
3584 if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRi ghtDirection()) {
3585 const RenderInline* flow = toRenderInline(containerBlock);
3586 InlineFlowBox* firstLine = flow->firstLineBox();
3587 InlineFlowBox* lastLine = flow->lastLineBox();
3588 if (firstLine && lastLine && firstLine != lastLine) {
3589 computedValues.m_position = logicalLeftValue + marginLogicalLeftAlia s + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logica lLeft());
3590 return;
3591 }
3592 }
3593
3594 LayoutUnit logicalLeftPos = logicalLeftValue + marginLogicalLeftAlias;
3595 computeLogicalLeftPositionedOffset(logicalLeftPos, this, computedValues.m_ex tent, containerBlock, containerLogicalWidth);
3596 computedValues.m_position = logicalLeftPos;
3597 }
3598
3599 void RenderBox::computePositionedLogicalHeightReplaced(LogicalExtentComputedValu es& computedValues) const
3600 {
3601 // The following is based off of the W3C Working Draft from April 11, 2006 o f
3602 // CSS 2.1: Section 10.6.5 "Absolutely positioned, replaced elements"
3603 // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-he ight>
3604 // (block-style-comments in this function correspond to text from the spec a nd
3605 // the numbers correspond to numbers in spec)
3606
3607 // We don't use containingBlock(), since we may be positioned by an enclosin g relpositioned inline.
3608 const LayoutBoxModelObject* containerBlock = toLayoutBoxModelObject(containe r());
3609
3610 const LayoutUnit containerLogicalHeight = containingBlockLogicalHeightForPos itioned(containerBlock);
3611 const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidth ForPositioned(containerBlock, false);
3612
3613 // Variables to solve.
3614 Length marginBefore = style()->marginBefore();
3615 Length marginAfter = style()->marginAfter();
3616 LayoutUnit& marginBeforeAlias = computedValues.m_margins.m_before;
3617 LayoutUnit& marginAfterAlias = computedValues.m_margins.m_after;
3618
3619 Length logicalTop = style()->logicalTop();
3620 Length logicalBottom = style()->logicalBottom();
3621
3622 /*-----------------------------------------------------------------------*\
3623 * 1. The used value of 'height' is determined as for inline replaced
3624 * elements.
3625 \*-----------------------------------------------------------------------*/
3626 // NOTE: This value of height is final in that the min/max height calculatio ns
3627 // are dealt with in computeReplacedHeight(). This means that the steps to produce
3628 // correct max/min in the non-replaced version, are not necessary.
3629 computedValues.m_extent = computeReplacedLogicalHeight() + borderAndPaddingL ogicalHeight();
3630 const LayoutUnit availableSpace = containerLogicalHeight - computedValues.m_ extent;
3631
3632 /*-----------------------------------------------------------------------*\
3633 * 2. If both 'top' and 'bottom' have the value 'auto', replace 'top'
3634 * with the element's static position.
3635 \*-----------------------------------------------------------------------*/
3636 // see FIXME 1
3637 computeBlockStaticDistance(logicalTop, logicalBottom, this, containerBlock);
3638
3639 /*-----------------------------------------------------------------------*\
3640 * 3. If 'bottom' is 'auto', replace any 'auto' on 'margin-top' or
3641 * 'margin-bottom' with '0'.
3642 \*-----------------------------------------------------------------------*/
3643 // FIXME: The spec. says that this step should only be taken when bottom is
3644 // auto, but if only top is auto, this makes step 4 impossible.
3645 if (logicalTop.isAuto() || logicalBottom.isAuto()) {
3646 if (marginBefore.isAuto())
3647 marginBefore.setValue(Fixed, 0);
3648 if (marginAfter.isAuto())
3649 marginAfter.setValue(Fixed, 0);
3650 }
3651
3652 /*-----------------------------------------------------------------------*\
3653 * 4. If at this point both 'margin-top' and 'margin-bottom' are still
3654 * 'auto', solve the equation under the extra constraint that the two
3655 * margins must get equal values.
3656 \*-----------------------------------------------------------------------*/
3657 LayoutUnit logicalTopValue = 0;
3658 LayoutUnit logicalBottomValue = 0;
3659
3660 if (marginBefore.isAuto() && marginAfter.isAuto()) {
3661 // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combined.
3662 ASSERT(!(logicalTop.isAuto() || logicalBottom.isAuto()));
3663
3664 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3665 logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeigh t);
3666
3667 LayoutUnit difference = availableSpace - (logicalTopValue + logicalBotto mValue);
3668 // NOTE: This may result in negative values.
3669 marginBeforeAlias = difference / 2; // split the difference
3670 marginAfterAlias = difference - marginBeforeAlias; // account for odd va lued differences
3671
3672 /*-----------------------------------------------------------------------*\
3673 * 5. If at this point there is only one 'auto' left, solve the equation
3674 * for that value.
3675 \*-----------------------------------------------------------------------*/
3676 } else if (logicalTop.isAuto()) {
3677 marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogica lWidth);
3678 marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalW idth);
3679 logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeigh t);
3680
3681 // Solve for 'top'
3682 logicalTopValue = availableSpace - (logicalBottomValue + marginBeforeAli as + marginAfterAlias);
3683 } else if (logicalBottom.isAuto()) {
3684 marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogica lWidth);
3685 marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalW idth);
3686 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3687
3688 // Solve for 'bottom'
3689 // NOTE: It is not necessary to solve for 'bottom' because we don't ever
3690 // use the value.
3691 } else if (marginBefore.isAuto()) {
3692 marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalW idth);
3693 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3694 logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeigh t);
3695
3696 // Solve for 'margin-top'
3697 marginBeforeAlias = availableSpace - (logicalTopValue + logicalBottomVal ue + marginAfterAlias);
3698 } else if (marginAfter.isAuto()) {
3699 marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogica lWidth);
3700 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3701 logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeigh t);
3702
3703 // Solve for 'margin-bottom'
3704 marginAfterAlias = availableSpace - (logicalTopValue + logicalBottomValu e + marginBeforeAlias);
3705 } else {
3706 // Nothing is 'auto', just calculate the values.
3707 marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogica lWidth);
3708 marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalW idth);
3709 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3710 // NOTE: It is not necessary to solve for 'bottom' because we don't ever
3711 // use the value.
3712 }
3713
3714 /*-----------------------------------------------------------------------*\
3715 * 6. If at this point the values are over-constrained, ignore the value
3716 * for 'bottom' and solve for that value.
3717 \*-----------------------------------------------------------------------*/
3718 // NOTE: It is not necessary to do this step because we don't end up using
3719 // the value of 'bottom' regardless of whether the values are over-constrain ed
3720 // or not.
3721
3722 // Use computed values to calculate the vertical position.
3723 LayoutUnit logicalTopPos = logicalTopValue + marginBeforeAlias;
3724 computeLogicalTopPositionedOffset(logicalTopPos, this, computedValues.m_exte nt, containerBlock, containerLogicalHeight);
3725 computedValues.m_position = logicalTopPos;
3726 }
3727
3728 LayoutRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, LayoutUnit * extraWidthToEndOfLine)
3729 {
3730 // VisiblePositions at offsets inside containers either a) refer to the posi tions before/after
3731 // those containers (tables and select elements) or b) refer to the position inside an empty block.
3732 // They never refer to children.
3733 // FIXME: Paint the carets inside empty blocks differently than the carets b efore/after elements.
3734
3735 LayoutRect rect(location(), LayoutSize(caretWidth, size().height()));
3736 bool ltr = box ? box->isLeftToRightDirection() : style()->isLeftToRightDirec tion();
3737
3738 if ((!caretOffset) ^ ltr)
3739 rect.move(LayoutSize(size().width() - caretWidth, 0));
3740
3741 if (box) {
3742 RootInlineBox& rootBox = box->root();
3743 LayoutUnit top = rootBox.lineTop();
3744 rect.setY(top);
3745 rect.setHeight(rootBox.lineBottom() - top);
3746 }
3747
3748 // If height of box is smaller than font height, use the latter one,
3749 // otherwise the caret might become invisible.
3750 //
3751 // Also, if the box is not a replaced element, always use the font height.
3752 // This prevents the "big caret" bug described in:
3753 // <rdar://problem/3777804> Deleting all content in a document can result in giant tall-as-window insertion point
3754 //
3755 // FIXME: ignoring :first-line, missing good reason to take care of
3756 LayoutUnit fontHeight = style()->fontMetrics().height();
3757 if (fontHeight > rect.height() || (!isReplaced() && !isTable()))
3758 rect.setHeight(fontHeight);
3759
3760 if (extraWidthToEndOfLine)
3761 *extraWidthToEndOfLine = location().x() + size().width() - rect.maxX();
3762
3763 // Move to local coords
3764 rect.moveBy(-location());
3765
3766 // FIXME: Border/padding should be added for all elements but this workaroun d
3767 // is needed because we use offsets inside an "atomic" element to represent
3768 // positions before and after the element in deprecated editing offsets.
3769 if (node() && !(editingIgnoresContent(node()) || isRenderedTableElement(node ()))) {
3770 rect.setX(rect.x() + borderLeft() + paddingLeft());
3771 rect.setY(rect.y() + paddingTop() + borderTop());
3772 }
3773
3774 if (!isHorizontalWritingMode())
3775 return rect.transposedRect();
3776
3777 return rect;
3778 }
3779
3780 PositionWithAffinity RenderBox::positionForPoint(const LayoutPoint& point)
3781 {
3782 // no children...return this render object's element, if there is one, and o ffset 0
3783 LayoutObject* firstChild = slowFirstChild();
3784 if (!firstChild)
3785 return createPositionWithAffinity(nonPseudoNode() ? firstPositionInOrBef oreNode(nonPseudoNode()) : Position());
3786
3787 if (isTable() && nonPseudoNode()) {
3788 LayoutUnit right = size().width() - verticalScrollbarWidth();
3789 LayoutUnit bottom = size().height() - horizontalScrollbarHeight();
3790
3791 if (point.x() < 0 || point.x() > right || point.y() < 0 || point.y() > b ottom) {
3792 if (point.x() <= right / 2)
3793 return createPositionWithAffinity(firstPositionInOrBeforeNode(no nPseudoNode()));
3794 return createPositionWithAffinity(lastPositionInOrAfterNode(nonPseud oNode()));
3795 }
3796 }
3797
3798 // Pass off to the closest child.
3799 LayoutUnit minDist = LayoutUnit::max();
3800 RenderBox* closestRenderer = 0;
3801 LayoutPoint adjustedPoint = point;
3802 if (isTableRow())
3803 adjustedPoint.moveBy(location());
3804
3805 for (LayoutObject* layoutObject = firstChild; layoutObject; layoutObject = l ayoutObject->nextSibling()) {
3806 if ((!layoutObject->slowFirstChild() && !layoutObject->isInline() && !la youtObject->isRenderBlockFlow() )
3807 || layoutObject->style()->visibility() != VISIBLE)
3808 continue;
3809
3810 if (!layoutObject->isBox())
3811 continue;
3812
3813 RenderBox* renderer = toRenderBox(layoutObject);
3814
3815 LayoutUnit top = renderer->borderTop() + renderer->paddingTop() + (isTab leRow() ? LayoutUnit() : renderer->location().y());
3816 LayoutUnit bottom = top + renderer->contentHeight();
3817 LayoutUnit left = renderer->borderLeft() + renderer->paddingLeft() + (is TableRow() ? LayoutUnit() : renderer->location().x());
3818 LayoutUnit right = left + renderer->contentWidth();
3819
3820 if (point.x() <= right && point.x() >= left && point.y() <= top && point .y() >= bottom) {
3821 if (renderer->isTableRow())
3822 return renderer->positionForPoint(point + adjustedPoint - render er->locationOffset());
3823 return renderer->positionForPoint(point - renderer->locationOffset() );
3824 }
3825
3826 // Find the distance from (x, y) to the box. Split the space around the box into 8 pieces
3827 // and use a different compare depending on which piece (x, y) is in.
3828 LayoutPoint cmp;
3829 if (point.x() > right) {
3830 if (point.y() < top)
3831 cmp = LayoutPoint(right, top);
3832 else if (point.y() > bottom)
3833 cmp = LayoutPoint(right, bottom);
3834 else
3835 cmp = LayoutPoint(right, point.y());
3836 } else if (point.x() < left) {
3837 if (point.y() < top)
3838 cmp = LayoutPoint(left, top);
3839 else if (point.y() > bottom)
3840 cmp = LayoutPoint(left, bottom);
3841 else
3842 cmp = LayoutPoint(left, point.y());
3843 } else {
3844 if (point.y() < top)
3845 cmp = LayoutPoint(point.x(), top);
3846 else
3847 cmp = LayoutPoint(point.x(), bottom);
3848 }
3849
3850 LayoutSize difference = cmp - point;
3851
3852 LayoutUnit dist = difference.width() * difference.width() + difference.h eight() * difference.height();
3853 if (dist < minDist) {
3854 closestRenderer = renderer;
3855 minDist = dist;
3856 }
3857 }
3858
3859 if (closestRenderer)
3860 return closestRenderer->positionForPoint(adjustedPoint - closestRenderer ->locationOffset());
3861 return createPositionWithAffinity(firstPositionInOrBeforeNode(nonPseudoNode( )));
3862 }
3863
3864 bool RenderBox::shrinkToAvoidFloats() const
3865 {
3866 // Floating objects don't shrink. Objects that don't avoid floats don't shr ink.
3867 if (isInline() || !avoidsFloats() || isFloating())
3868 return false;
3869
3870 // Only auto width objects can possibly shrink to avoid floats.
3871 return style()->width().isAuto();
3872 }
3873
3874 static bool isReplacedElement(Node* node)
3875 {
3876 // Checkboxes and radioboxes are not isReplaced() nor do they have their own renderer in which to override avoidFloats().
3877 return node && node->isElementNode() && (toElement(node)->isFormControlEleme nt() || isHTMLImageElement(toElement(node)));
3878 }
3879
3880 bool RenderBox::avoidsFloats() const
3881 {
3882 return isReplaced() || isReplacedElement(node()) || hasOverflowClip() || isH R() || isLegend() || isWritingModeRoot() || isFlexItemIncludingDeprecated();
3883 }
3884
3885 bool RenderBox::hasNonCompositedScrollbars() const
3886 {
3887 if (Layer* layer = this->layer()) {
3888 if (LayerScrollableArea* scrollableArea = layer->scrollableArea()) {
3889 if (scrollableArea->hasHorizontalScrollbar() && !scrollableArea->lay erForHorizontalScrollbar())
3890 return true;
3891 if (scrollableArea->hasVerticalScrollbar() && !scrollableArea->layer ForVerticalScrollbar())
3892 return true;
3893 }
3894 }
3895 return false;
3896 }
3897
3898 PaintInvalidationReason RenderBox::paintInvalidationReason(const LayoutBoxModelO bject& paintInvalidationContainer,
3899 const LayoutRect& oldBounds, const LayoutPoint& oldLocation, const LayoutRec t& newBounds, const LayoutPoint& newLocation) const
3900 {
3901 PaintInvalidationReason invalidationReason = LayoutBoxModelObject::paintInva lidationReason(paintInvalidationContainer, oldBounds, oldLocation, newBounds, ne wLocation);
3902 if (isFullPaintInvalidationReason(invalidationReason))
3903 return invalidationReason;
3904
3905 // If the transform is not identity or translation, incremental invalidation is not applicable
3906 // because the difference between oldBounds and newBounds doesn't cover all area needing invalidation.
3907 // FIXME: Should also consider ancestor transforms since paintInvalidationCo ntainer. crbug.com/426111.
3908 if (invalidationReason == PaintInvalidationIncremental
3909 && paintInvalidationContainer != this
3910 && hasLayer() && layer()->transform() && !layer()->transform()->isIdenti tyOrTranslation())
3911 return PaintInvalidationBoundsChange;
3912
3913 if (!style()->hasBackground() && !style()->hasBoxDecorations()) {
3914 // We could let incremental invalidation cover non-composited scrollbars , but just
3915 // do a full invalidation because incremental invalidation will go away with slimming paint.
3916 if (invalidationReason == PaintInvalidationIncremental && hasNonComposit edScrollbars())
3917 return PaintInvalidationBorderBoxChange;
3918 return invalidationReason;
3919 }
3920
3921 LayoutSize oldBorderBoxSize = computePreviousBorderBoxSize(oldBounds.size()) ;
3922 LayoutSize newBorderBoxSize = size();
3923
3924 if (oldBorderBoxSize == newBorderBoxSize)
3925 return invalidationReason;
3926
3927 // See another hasNonCompositedScrollbars() callsite above.
3928 if (hasNonCompositedScrollbars())
3929 return PaintInvalidationBorderBoxChange;
3930
3931 if (style()->hasVisualOverflowingEffect() || style()->hasAppearance() || sty le()->hasFilter() || style()->resize() != RESIZE_NONE)
3932 return PaintInvalidationBorderBoxChange;
3933
3934 if (style()->hasBorderRadius()) {
3935 // If a border-radius exists and width/height is smaller than radius wid th/height,
3936 // we need to fully invalidate to cover the changed radius.
3937 FloatRoundedRect oldRoundedRect = style()->getRoundedBorderFor(LayoutRec t(LayoutPoint(0, 0), oldBorderBoxSize));
3938 FloatRoundedRect newRoundedRect = style()->getRoundedBorderFor(LayoutRec t(LayoutPoint(0, 0), newBorderBoxSize));
3939 if (oldRoundedRect.radii() != newRoundedRect.radii())
3940 return PaintInvalidationBorderBoxChange;
3941 }
3942
3943 if (oldBorderBoxSize.width() != newBorderBoxSize.width() && mustInvalidateBa ckgroundOrBorderPaintOnWidthChange())
3944 return PaintInvalidationBorderBoxChange;
3945 if (oldBorderBoxSize.height() != newBorderBoxSize.height() && mustInvalidate BackgroundOrBorderPaintOnHeightChange())
3946 return PaintInvalidationBorderBoxChange;
3947
3948 return PaintInvalidationIncremental;
3949 }
3950
3951 void RenderBox::incrementallyInvalidatePaint(const LayoutBoxModelObject& paintIn validationContainer, const LayoutRect& oldBounds, const LayoutRect& newBounds, c onst LayoutPoint& positionFromPaintInvalidationBacking)
3952 {
3953 LayoutObject::incrementallyInvalidatePaint(paintInvalidationContainer, oldBo unds, newBounds, positionFromPaintInvalidationBacking);
3954
3955 bool hasBoxDecorations = style()->hasBoxDecorations();
3956 if (!style()->hasBackground() && !hasBoxDecorations)
3957 return;
3958
3959 LayoutSize oldBorderBoxSize = computePreviousBorderBoxSize(oldBounds.size()) ;
3960 LayoutSize newBorderBoxSize = size();
3961
3962 // If border box size didn't change, RenderObject's incrementallyInvalidateP aint() is good.
3963 if (oldBorderBoxSize == newBorderBoxSize)
3964 return;
3965
3966 // If size of the paint invalidation rect equals to size of border box, Layo utObject::incrementallyInvalidatePaint()
3967 // is good for boxes having background without box decorations.
3968 ASSERT(oldBounds.location() == newBounds.location()); // Otherwise we won't do incremental invalidation.
3969 if (!hasBoxDecorations
3970 && positionFromPaintInvalidationBacking == newBounds.location()
3971 && oldBorderBoxSize == oldBounds.size()
3972 && newBorderBoxSize == newBounds.size())
3973 return;
3974
3975 // Invalidate the right delta part and the right border of the old or new bo x which has smaller width.
3976 LayoutUnit deltaWidth = absoluteValue(oldBorderBoxSize.width() - newBorderBo xSize.width());
3977 if (deltaWidth) {
3978 LayoutUnit smallerWidth = std::min(oldBorderBoxSize.width(), newBorderBo xSize.width());
3979 LayoutUnit borderTopRightRadiusWidth = valueForLength(style()->borderTop RightRadius().width(), smallerWidth);
3980 LayoutUnit borderBottomRightRadiusWidth = valueForLength(style()->border BottomRightRadius().width(), smallerWidth);
3981 LayoutUnit borderWidth = std::max<LayoutUnit>(borderRight(), std::max(bo rderTopRightRadiusWidth, borderBottomRightRadiusWidth));
3982 LayoutRect rightDeltaRect(positionFromPaintInvalidationBacking.x() + sma llerWidth - borderWidth,
3983 positionFromPaintInvalidationBacking.y(),
3984 deltaWidth + borderWidth,
3985 std::max(oldBorderBoxSize.height(), newBorderBoxSize.height()));
3986 invalidatePaintRectClippedByOldAndNewBounds(paintInvalidationContainer, rightDeltaRect, oldBounds, newBounds);
3987 }
3988
3989 // Invalidate the bottom delta part and the bottom border of the old or new box which has smaller height.
3990 LayoutUnit deltaHeight = absoluteValue(oldBorderBoxSize.height() - newBorder BoxSize.height());
3991 if (deltaHeight) {
3992 LayoutUnit smallerHeight = std::min(oldBorderBoxSize.height(), newBorder BoxSize.height());
3993 LayoutUnit borderBottomLeftRadiusHeight = valueForLength(style()->border BottomLeftRadius().height(), smallerHeight);
3994 LayoutUnit borderBottomRightRadiusHeight = valueForLength(style()->borde rBottomRightRadius().height(), smallerHeight);
3995 LayoutUnit borderHeight = std::max<LayoutUnit>(borderBottom(), std::max( borderBottomLeftRadiusHeight, borderBottomRightRadiusHeight));
3996 LayoutRect bottomDeltaRect(positionFromPaintInvalidationBacking.x(),
3997 positionFromPaintInvalidationBacking.y() + smallerHeight - borderHei ght,
3998 std::max(oldBorderBoxSize.width(), newBorderBoxSize.width()),
3999 deltaHeight + borderHeight);
4000 invalidatePaintRectClippedByOldAndNewBounds(paintInvalidationContainer, bottomDeltaRect, oldBounds, newBounds);
4001 }
4002 }
4003
4004 void RenderBox::invalidatePaintRectClippedByOldAndNewBounds(const LayoutBoxModel Object& paintInvalidationContainer, const LayoutRect& rect, const LayoutRect& ol dBounds, const LayoutRect& newBounds)
4005 {
4006 if (rect.isEmpty())
4007 return;
4008 LayoutRect rectClippedByOldBounds = intersection(rect, oldBounds);
4009 LayoutRect rectClippedByNewBounds = intersection(rect, newBounds);
4010 // Invalidate only once if the clipped rects equal.
4011 if (rectClippedByOldBounds == rectClippedByNewBounds) {
4012 invalidatePaintUsingContainer(&paintInvalidationContainer, rectClippedBy OldBounds, PaintInvalidationIncremental);
4013 return;
4014 }
4015 // Invalidate the bigger one if one contains another. Otherwise invalidate b oth.
4016 if (!rectClippedByNewBounds.contains(rectClippedByOldBounds))
4017 invalidatePaintUsingContainer(&paintInvalidationContainer, rectClippedBy OldBounds, PaintInvalidationIncremental);
4018 if (!rectClippedByOldBounds.contains(rectClippedByNewBounds))
4019 invalidatePaintUsingContainer(&paintInvalidationContainer, rectClippedBy NewBounds, PaintInvalidationIncremental);
4020 }
4021
4022 void RenderBox::markForPaginationRelayoutIfNeeded(SubtreeLayoutScope& layoutScop e)
4023 {
4024 ASSERT(!needsLayout());
4025 // If fragmentation height has changed, we need to lay out. No need to enter the renderer if it
4026 // is childless, though.
4027 if (view()->layoutState()->pageLogicalHeightChanged() && slowFirstChild())
4028 layoutScope.setChildNeedsLayout(this);
4029 }
4030
4031 void RenderBox::addVisualEffectOverflow()
4032 {
4033 if (!style()->hasVisualOverflowingEffect())
4034 return;
4035
4036 // Add in the final overflow with shadows, outsets and outline combined.
4037 LayoutRect visualEffectOverflow = borderBoxRect();
4038 visualEffectOverflow.expand(computeVisualEffectOverflowOutsets());
4039 addVisualOverflow(visualEffectOverflow);
4040 }
4041
4042 LayoutRectOutsets RenderBox::computeVisualEffectOverflowOutsets() const
4043 {
4044 ASSERT(style()->hasVisualOverflowingEffect());
4045
4046 LayoutUnit top;
4047 LayoutUnit right;
4048 LayoutUnit bottom;
4049 LayoutUnit left;
4050
4051 if (const ShadowList* boxShadow = style()->boxShadow()) {
4052 // FIXME: Use LayoutUnit edge outsets, and then simplify this.
4053 FloatRectOutsets outsets = boxShadow->rectOutsetsIncludingOriginal();
4054 top = outsets.top();
4055 right = outsets.right();
4056 bottom = outsets.bottom();
4057 left = outsets.left();
4058 }
4059
4060 if (style()->hasBorderImageOutsets()) {
4061 LayoutRectOutsets borderOutsets = style()->borderImageOutsets();
4062 top = std::max(top, borderOutsets.top());
4063 right = std::max(right, borderOutsets.right());
4064 bottom = std::max(bottom, borderOutsets.bottom());
4065 left = std::max(left, borderOutsets.left());
4066 }
4067
4068 if (style()->hasOutline()) {
4069 if (style()->outlineStyleIsAuto()) {
4070 // The result focus ring rects are in coordinates of this object's b order box.
4071 Vector<LayoutRect> focusRingRects;
4072 addFocusRingRects(focusRingRects, LayoutPoint());
4073 LayoutRect rect = unionRect(focusRingRects);
4074
4075 int outlineSize = GraphicsContext::focusRingOutsetExtent(style()->ou tlineOffset(), style()->outlineWidth());
4076 top = std::max(top, -rect.y() + outlineSize);
4077 right = std::max(right, rect.maxX() - size().width() + outlineSize);
4078 bottom = std::max(bottom, rect.maxY() - size().height() + outlineSiz e);
4079 left = std::max(left, -rect.x() + outlineSize);
4080 } else {
4081 LayoutUnit outlineSize = style()->outlineSize();
4082 top = std::max(top, outlineSize);
4083 right = std::max(right, outlineSize);
4084 bottom = std::max(bottom, outlineSize);
4085 left = std::max(left, outlineSize);
4086 }
4087 }
4088
4089 return LayoutRectOutsets(top, right, bottom, left);
4090 }
4091
4092 void RenderBox::addOverflowFromChild(RenderBox* child, const LayoutSize& delta)
4093 {
4094 // Never allow flow threads to propagate overflow up to a parent.
4095 if (child->isLayoutFlowThread())
4096 return;
4097
4098 // Only propagate layout overflow from the child if the child isn't clipping its overflow. If it is, then
4099 // its overflow is internal to it, and we don't care about it. layoutOverfl owRectForPropagation takes care of this
4100 // and just propagates the border box rect instead.
4101 LayoutRect childLayoutOverflowRect = child->layoutOverflowRectForPropagation (styleRef());
4102 childLayoutOverflowRect.move(delta);
4103 addLayoutOverflow(childLayoutOverflowRect);
4104
4105 // Add in visual overflow from the child. Even if the child clips its overf low, it may still
4106 // have visual overflow of its own set from box shadows or reflections. It is unnecessary to propagate this
4107 // overflow if we are clipping our own overflow.
4108 if (child->hasSelfPaintingLayer())
4109 return;
4110 LayoutRect childVisualOverflowRect = child->visualOverflowRectForPropagation (styleRef());
4111 childVisualOverflowRect.move(delta);
4112 addContentsVisualOverflow(childVisualOverflowRect);
4113 }
4114
4115 void RenderBox::addLayoutOverflow(const LayoutRect& rect)
4116 {
4117 LayoutRect clientBox = noOverflowRect();
4118 if (clientBox.contains(rect) || rect.isEmpty())
4119 return;
4120
4121 // For overflow clip objects, we don't want to propagate overflow into unrea chable areas.
4122 LayoutRect overflowRect(rect);
4123 if (hasOverflowClip() || isRenderView()) {
4124 // Overflow is in the block's coordinate space and thus is flipped for h orizontal-bt and vertical-rl
4125 // writing modes. At this stage that is actually a simplification, sinc e we can treat horizontal-tb/bt as the same
4126 // and vertical-lr/rl as the same.
4127 bool hasTopOverflow = !style()->isLeftToRightDirection() && !isHorizonta lWritingMode();
4128 bool hasLeftOverflow = !style()->isLeftToRightDirection() && isHorizonta lWritingMode();
4129 if (isFlexibleBox() && style()->isReverseFlexDirection()) {
4130 RenderFlexibleBox* flexibleBox = toRenderFlexibleBox(this);
4131 if (flexibleBox->isHorizontalFlow())
4132 hasLeftOverflow = true;
4133 else
4134 hasTopOverflow = true;
4135 }
4136
4137 if (!hasTopOverflow)
4138 overflowRect.shiftYEdgeTo(std::max(overflowRect.y(), clientBox.y())) ;
4139 else
4140 overflowRect.shiftMaxYEdgeTo(std::min(overflowRect.maxY(), clientBox .maxY()));
4141 if (!hasLeftOverflow)
4142 overflowRect.shiftXEdgeTo(std::max(overflowRect.x(), clientBox.x())) ;
4143 else
4144 overflowRect.shiftMaxXEdgeTo(std::min(overflowRect.maxX(), clientBox .maxX()));
4145
4146 // Now re-test with the adjusted rectangle and see if it has become unre achable or fully
4147 // contained.
4148 if (clientBox.contains(overflowRect) || overflowRect.isEmpty())
4149 return;
4150 }
4151
4152 if (!m_overflow)
4153 m_overflow = adoptPtr(new RenderOverflow(clientBox, borderBoxRect()));
4154
4155 m_overflow->addLayoutOverflow(overflowRect);
4156 }
4157
4158 void RenderBox::addVisualOverflow(const LayoutRect& rect)
4159 {
4160 LayoutRect borderBox = borderBoxRect();
4161 if (borderBox.contains(rect) || rect.isEmpty())
4162 return;
4163
4164 if (!m_overflow)
4165 m_overflow = adoptPtr(new RenderOverflow(noOverflowRect(), borderBox));
4166
4167 m_overflow->addVisualOverflow(rect);
4168 }
4169
4170 void RenderBox::addContentsVisualOverflow(const LayoutRect& rect)
4171 {
4172 if (!hasOverflowClip()) {
4173 addVisualOverflow(rect);
4174 return;
4175 }
4176
4177 if (!m_overflow)
4178 m_overflow = adoptPtr(new RenderOverflow(noOverflowRect(), borderBoxRect ()));
4179 m_overflow->addContentsVisualOverflow(rect);
4180 }
4181
4182 void RenderBox::clearLayoutOverflow()
4183 {
4184 if (!m_overflow)
4185 return;
4186
4187 if (!hasVisualOverflow() && contentsVisualOverflowRect().isEmpty()) {
4188 clearAllOverflows();
4189 return;
4190 }
4191
4192 m_overflow->setLayoutOverflow(noOverflowRect());
4193 }
4194
4195 bool RenderBox::logicalWidthIsResolvableFromBlock(const RenderBlock* containingB lock)
4196 {
4197 const RenderBlock* cb = containingBlock;
4198 while (!cb->isRenderView() && !cb->isOutOfFlowPositioned() && (cb->style()-> logicalWidth().isAuto() || cb->isAnonymousBlock()))
4199 cb = cb->containingBlock();
4200
4201 if (cb->style()->logicalWidth().isFixed())
4202 return true;
4203 if (cb->isRenderView())
4204 return true;
4205 if (cb->isOutOfFlowPositioned())
4206 return true;
4207 if (cb->style()->logicalWidth().isPercent())
4208 return logicalWidthIsResolvableFromBlock(cb->containingBlock());
4209
4210 return false;
4211 }
4212
4213 bool RenderBox::hasDefiniteLogicalWidth() const
4214 {
4215 const Length& logicalWidth = style()->logicalWidth();
4216 if (logicalWidth.isIntrinsic() || logicalWidth.isLegacyIntrinsic())
4217 return false;
4218 if (logicalWidth.isFixed())
4219 return true;
4220 // The size of the containing block of an absolutely positioned element is a lways definite with respect to that
4221 // element (http://dev.w3.org/csswg/css-sizing-3/#definite).
4222 if (isOutOfFlowPositioned())
4223 return true;
4224
4225 return RenderBox::logicalWidthIsResolvableFromBlock(containingBlock());
4226 }
4227
4228 inline static bool percentageLogicalHeightIsResolvable(const RenderBox* box)
4229 {
4230 return RenderBox::percentageLogicalHeightIsResolvableFromBlock(box->containi ngBlock(), box->isOutOfFlowPositioned());
4231 }
4232
4233 bool RenderBox::percentageLogicalHeightIsResolvableFromBlock(const RenderBlock* containingBlock, bool isOutOfFlowPositioned)
4234 {
4235 // In quirks mode, blocks with auto height are skipped, and we keep looking for an enclosing
4236 // block that may have a specified height and then use it. In strict mode, t his violates the
4237 // specification, which states that percentage heights just revert to auto i f the containing
4238 // block has an auto height. We still skip anonymous containing blocks in bo th modes, though, and look
4239 // only at explicit containers.
4240 const RenderBlock* cb = containingBlock;
4241 bool inQuirksMode = cb->document().inQuirksMode();
4242 while (!cb->isRenderView() && !cb->isBody() && !cb->isTableCell() && !cb->is OutOfFlowPositioned() && cb->style()->logicalHeight().isAuto()) {
4243 if (!inQuirksMode && !cb->isAnonymousBlock())
4244 break;
4245 cb = cb->containingBlock();
4246 }
4247
4248 // A positioned element that specified both top/bottom or that specifies hei ght should be treated as though it has a height
4249 // explicitly specified that can be used for any percentage computations.
4250 // FIXME: We can't just check top/bottom here.
4251 // https://bugs.webkit.org/show_bug.cgi?id=46500
4252 bool isOutOfFlowPositionedWithSpecifiedHeight = cb->isOutOfFlowPositioned() && (!cb->style()->logicalHeight().isAuto() || (!cb->style()->top().isAuto() && ! cb->style()->bottom().isAuto()));
4253
4254 // Table cells violate what the CSS spec says to do with heights. Basically we
4255 // don't care if the cell specified a height or not. We just always make ou rselves
4256 // be a percentage of the cell's current content height.
4257 if (cb->isTableCell())
4258 return true;
4259
4260 // Otherwise we only use our percentage height if our containing block had a specified
4261 // height.
4262 if (cb->style()->logicalHeight().isFixed())
4263 return true;
4264 if (cb->style()->logicalHeight().isPercent() && !isOutOfFlowPositionedWithSp ecifiedHeight)
4265 return percentageLogicalHeightIsResolvableFromBlock(cb->containingBlock( ), cb->isOutOfFlowPositioned());
4266 if (cb->isRenderView() || inQuirksMode || isOutOfFlowPositionedWithSpecified Height)
4267 return true;
4268 if (cb->isDocumentElement() && isOutOfFlowPositioned) {
4269 // Match the positioned objects behavior, which is that positioned objec ts will fill their viewport
4270 // always. Note we could only hit this case by recurring into computePe rcentageLogicalHeight on a positioned containing block.
4271 return true;
4272 }
4273
4274 return false;
4275 }
4276
4277 bool RenderBox::hasDefiniteLogicalHeight() const
4278 {
4279 const Length& logicalHeight = style()->logicalHeight();
4280 if (logicalHeight.isIntrinsicOrAuto())
4281 return false;
4282 if (logicalHeight.isFixed())
4283 return true;
4284 // The size of the containing block of an absolutely positioned element is a lways definite with respect to that
4285 // element (http://dev.w3.org/csswg/css-sizing-3/#definite).
4286 if (isOutOfFlowPositioned())
4287 return true;
4288
4289 return percentageLogicalHeightIsResolvable(this);
4290 }
4291
4292 bool RenderBox::hasUnsplittableScrollingOverflow() const
4293 {
4294 // We will paginate as long as we don't scroll overflow in the pagination di rection.
4295 bool isHorizontal = isHorizontalWritingMode();
4296 if ((isHorizontal && !scrollsOverflowY()) || (!isHorizontal && !scrollsOverf lowX()))
4297 return false;
4298
4299 // We do have overflow. We'll still be willing to paginate as long as the bl ock
4300 // has auto logical height, auto or undefined max-logical-height and a zero or auto min-logical-height.
4301 // Note this is just a heuristic, and it's still possible to have overflow u nder these
4302 // conditions, but it should work out to be good enough for common cases. Pa ginating overflow
4303 // with scrollbars present is not the end of the world and is what we used t o do in the old model anyway.
4304 return !style()->logicalHeight().isIntrinsicOrAuto()
4305 || (!style()->logicalMaxHeight().isIntrinsicOrAuto() && !style()->logica lMaxHeight().isMaxSizeNone() && (!style()->logicalMaxHeight().isPercent() || per centageLogicalHeightIsResolvable(this)))
4306 || (!style()->logicalMinHeight().isIntrinsicOrAuto() && style()->logical MinHeight().isPositive() && (!style()->logicalMinHeight().isPercent() || percent ageLogicalHeightIsResolvable(this)));
4307 }
4308
4309 bool RenderBox::isUnsplittableForPagination() const
4310 {
4311 return isReplaced() || hasUnsplittableScrollingOverflow() || (parent() && is WritingModeRoot());
4312 }
4313
4314 LayoutUnit RenderBox::lineHeight(bool /*firstLine*/, LineDirectionMode direction , LinePositionMode /*linePositionMode*/) const
4315 {
4316 if (isReplaced())
4317 return direction == HorizontalLine ? marginHeight() + size().height() : marginWidth() + size().width();
4318 return LayoutUnit();
4319 }
4320
4321 int RenderBox::baselinePosition(FontBaseline baselineType, bool /*firstLine*/, L ineDirectionMode direction, LinePositionMode linePositionMode) const
4322 {
4323 ASSERT(linePositionMode == PositionOnContainingLine);
4324 if (isReplaced()) {
4325 int result = direction == HorizontalLine ? marginHeight() + size().heigh t() : marginWidth() + size().width();
4326 if (baselineType == AlphabeticBaseline)
4327 return result;
4328 return result - result / 2;
4329 }
4330 return 0;
4331 }
4332
4333
4334 Layer* RenderBox::enclosingFloatPaintingLayer() const
4335 {
4336 const LayoutObject* curr = this;
4337 while (curr) {
4338 Layer* layer = curr->hasLayer() && curr->isBox() ? toRenderBox(curr)->la yer() : 0;
4339 if (layer && layer->isSelfPaintingLayer())
4340 return layer;
4341 curr = curr->parent();
4342 }
4343 return 0;
4344 }
4345
4346 LayoutRect RenderBox::logicalVisualOverflowRectForPropagation(const LayoutStyle& parentStyle) const
4347 {
4348 LayoutRect rect = visualOverflowRectForPropagation(parentStyle);
4349 if (!parentStyle.isHorizontalWritingMode())
4350 return rect.transposedRect();
4351 return rect;
4352 }
4353
4354 LayoutRect RenderBox::visualOverflowRectForPropagation(const LayoutStyle& parent Style) const
4355 {
4356 // If the writing modes of the child and parent match, then we don't have to
4357 // do anything fancy. Just return the result.
4358 LayoutRect rect = visualOverflowRect();
4359 if (parentStyle.writingMode() == style()->writingMode())
4360 return rect;
4361
4362 // We are putting ourselves into our parent's coordinate space. If there is a flipped block mismatch
4363 // in a particular axis, then we have to flip the rect along that axis.
4364 if (style()->writingMode() == RightToLeftWritingMode || parentStyle.writingM ode() == RightToLeftWritingMode)
4365 rect.setX(size().width() - rect.maxX());
4366 else if (style()->writingMode() == BottomToTopWritingMode || parentStyle.wri tingMode() == BottomToTopWritingMode)
4367 rect.setY(size().height() - rect.maxY());
4368
4369 return rect;
4370 }
4371
4372 LayoutRect RenderBox::logicalLayoutOverflowRectForPropagation(const LayoutStyle& parentStyle) const
4373 {
4374 LayoutRect rect = layoutOverflowRectForPropagation(parentStyle);
4375 if (!parentStyle.isHorizontalWritingMode())
4376 return rect.transposedRect();
4377 return rect;
4378 }
4379
4380 LayoutRect RenderBox::layoutOverflowRectForPropagation(const LayoutStyle& parent Style) const
4381 {
4382 // Only propagate interior layout overflow if we don't clip it.
4383 LayoutRect rect = borderBoxRect();
4384 // We want to include the margin, but only when it adds height. Quirky margi ns don't contribute height
4385 // nor do the margins of self-collapsing blocks.
4386 if (!styleRef().hasMarginAfterQuirk() && !isSelfCollapsingBlock())
4387 rect.expand(isHorizontalWritingMode() ? LayoutSize(LayoutUnit(), marginA fter()) : LayoutSize(marginAfter(), LayoutUnit()));
4388
4389 if (!hasOverflowClip())
4390 rect.unite(layoutOverflowRect());
4391
4392 bool hasTransform = hasLayer() && layer()->transform();
4393 if (isRelPositioned() || hasTransform) {
4394 // If we are relatively positioned or if we have a transform, then we ha ve to convert
4395 // this rectangle into physical coordinates, apply relative positioning and transforms
4396 // to it, and then convert it back.
4397 flipForWritingMode(rect);
4398
4399 if (hasTransform)
4400 rect = layer()->currentTransform().mapRect(rect);
4401
4402 if (isRelPositioned())
4403 rect.move(offsetForInFlowPosition());
4404
4405 // Now we need to flip back.
4406 flipForWritingMode(rect);
4407 }
4408
4409 // If the writing modes of the child and parent match, then we don't have to
4410 // do anything fancy. Just return the result.
4411 if (parentStyle.writingMode() == style()->writingMode())
4412 return rect;
4413
4414 // We are putting ourselves into our parent's coordinate space. If there is a flipped block mismatch
4415 // in a particular axis, then we have to flip the rect along that axis.
4416 if (style()->writingMode() == RightToLeftWritingMode || parentStyle.writingM ode() == RightToLeftWritingMode)
4417 rect.setX(size().width() - rect.maxX());
4418 else if (style()->writingMode() == BottomToTopWritingMode || parentStyle.wri tingMode() == BottomToTopWritingMode)
4419 rect.setY(size().height() - rect.maxY());
4420
4421 return rect;
4422 }
4423
4424 LayoutRect RenderBox::noOverflowRect() const
4425 {
4426 // Because of the special coordinate system used for overflow rectangles and many other
4427 // rectangles (not quite logical, not quite physical), we need to flip the b lock progression
4428 // coordinate in vertical-rl and horizontal-bt writing modes. In other words , the rectangle
4429 // returned is physical, except for the block direction progression coordina te (y in horizontal
4430 // writing modes, x in vertical writing modes), which is always "logical top ". Apart from the
4431 // flipping, this method does the same as clientBoxRect().
4432
4433 const int scrollBarWidth = verticalScrollbarWidth();
4434 const int scrollBarHeight = horizontalScrollbarHeight();
4435 LayoutUnit left = borderLeft() + (style()->shouldPlaceBlockDirectionScrollba rOnLogicalLeft() ? scrollBarWidth : 0);
4436 LayoutUnit top = borderTop();
4437 LayoutUnit right = borderRight();
4438 LayoutUnit bottom = borderBottom();
4439 LayoutRect rect(left, top, size().width() - left - right, size().height() - top - bottom);
4440 flipForWritingMode(rect);
4441 // Subtract space occupied by scrollbars. Order is important here: first fli p, then subtract
4442 // scrollbars. This may seem backwards and weird, since one would think that a horizontal
4443 // scrollbar at the physical bottom in horizontal-bt ought to be at the logi cal top (physical
4444 // bottom), between the logical top (physical bottom) border and the logical top (physical
4445 // bottom) padding. But this is how the rest of the code expects us to behav e. This is highly
4446 // related to https://bugs.webkit.org/show_bug.cgi?id=76129
4447 // FIXME: when the above mentioned bug is fixed, it should hopefully be poss ible to call
4448 // clientBoxRect() or paddingBoxRect() in this method, rather than fiddling with the edges on
4449 // our own.
4450 if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
4451 rect.contract(0, scrollBarHeight);
4452 else
4453 rect.contract(scrollBarWidth, scrollBarHeight);
4454 return rect;
4455 }
4456
4457 LayoutUnit RenderBox::offsetLeft() const
4458 {
4459 return adjustedPositionRelativeToOffsetParent(topLeftLocation()).x();
4460 }
4461
4462 LayoutUnit RenderBox::offsetTop() const
4463 {
4464 return adjustedPositionRelativeToOffsetParent(topLeftLocation()).y();
4465 }
4466
4467 LayoutPoint RenderBox::flipForWritingModeForChild(const RenderBox* child, const LayoutPoint& point) const
4468 {
4469 if (!style()->isFlippedBlocksWritingMode())
4470 return point;
4471
4472 // The child is going to add in its x() and y(), so we have to make sure it ends up in
4473 // the right place.
4474 if (isHorizontalWritingMode())
4475 return LayoutPoint(point.x(), point.y() + size().height() - child->size( ).height() - (2 * child->location().y()));
4476 return LayoutPoint(point.x() + size().width() - child->size().width() - (2 * child->location().x()), point.y());
4477 }
4478
4479 LayoutPoint RenderBox::flipForWritingModeIncludingColumns(const LayoutPoint& poi nt) const
4480 {
4481 if (!hasColumns() || !style()->isFlippedBlocksWritingMode())
4482 return flipForWritingMode(point);
4483 return toRenderBlock(this)->flipForWritingModeIncludingColumns(point);
4484 }
4485
4486 LayoutPoint RenderBox::topLeftLocation() const
4487 {
4488 RenderBlock* containerBlock = containingBlock();
4489 if (!containerBlock || containerBlock == this)
4490 return location();
4491 return containerBlock->flipForWritingModeForChild(this, location());
4492 }
4493
4494 bool RenderBox::hasRelativeLogicalHeight() const
4495 {
4496 return style()->logicalHeight().isPercent()
4497 || style()->logicalMinHeight().isPercent()
4498 || style()->logicalMaxHeight().isPercent();
4499 }
4500
4501 static void markBoxForRelayoutAfterSplit(RenderBox* box)
4502 {
4503 // FIXME: The table code should handle that automatically. If not,
4504 // we should fix it and remove the table part checks.
4505 if (box->isTable()) {
4506 // Because we may have added some sections with already computed column structures, we need to
4507 // sync the table structure with them now. This avoids crashes when addi ng new cells to the table.
4508 toLayoutTable(box)->forceSectionsRecalc();
4509 } else if (box->isTableSection()) {
4510 toLayoutTableSection(box)->setNeedsCellRecalc();
4511 }
4512
4513 box->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
4514 }
4515
4516 LayoutObject* RenderBox::splitAnonymousBoxesAroundChild(LayoutObject* beforeChil d)
4517 {
4518 bool didSplitParentAnonymousBoxes = false;
4519
4520 while (beforeChild->parent() != this) {
4521 RenderBox* boxToSplit = toRenderBox(beforeChild->parent());
4522 if (boxToSplit->slowFirstChild() != beforeChild && boxToSplit->isAnonymo us()) {
4523 didSplitParentAnonymousBoxes = true;
4524
4525 // We have to split the parent box into two boxes and move children
4526 // from |beforeChild| to end into the new post box.
4527 RenderBox* postBox = boxToSplit->createAnonymousBoxWithSameTypeAs(th is);
4528 postBox->setChildrenInline(boxToSplit->childrenInline());
4529 RenderBox* parentBox = toRenderBox(boxToSplit->parent());
4530 // We need to invalidate the |parentBox| before inserting the new no de
4531 // so that the table paint invalidation logic knows the structure is dirty.
4532 // See for example LayoutTableCell:clippedOverflowRectForPaintInvali dation.
4533 markBoxForRelayoutAfterSplit(parentBox);
4534 parentBox->virtualChildren()->insertChildNode(parentBox, postBox, bo xToSplit->nextSibling());
4535 boxToSplit->moveChildrenTo(postBox, beforeChild, 0, true);
4536
4537 markBoxForRelayoutAfterSplit(boxToSplit);
4538 markBoxForRelayoutAfterSplit(postBox);
4539
4540 beforeChild = postBox;
4541 } else
4542 beforeChild = boxToSplit;
4543 }
4544
4545 if (didSplitParentAnonymousBoxes)
4546 markBoxForRelayoutAfterSplit(this);
4547
4548 ASSERT(beforeChild->parent() == this);
4549 return beforeChild;
4550 }
4551
4552 LayoutUnit RenderBox::offsetFromLogicalTopOfFirstPage() const
4553 {
4554 LayoutState* layoutState = view()->layoutState();
4555 if (layoutState && !layoutState->isPaginated())
4556 return LayoutUnit();
4557
4558 if (!layoutState && !flowThreadContainingBlock())
4559 return LayoutUnit();
4560
4561 RenderBlock* containerBlock = containingBlock();
4562 return containerBlock->offsetFromLogicalTopOfFirstPage() + logicalTop();
4563 }
4564
4565 void RenderBox::savePreviousBorderBoxSizeIfNeeded()
4566 {
4567 // If m_rareData is already created, always save.
4568 if (!m_rareData) {
4569 LayoutSize paintInvalidationSize = previousPaintInvalidationRect().size( );
4570
4571 // Don't save old border box size if the paint rect is empty because we' ll
4572 // full invalidate once the paint rect becomes non-empty.
4573 if (paintInvalidationSize.isEmpty())
4574 return;
4575
4576 // Don't save old border box size if we can use size of the old paint re ct
4577 // as the old border box size in the next invalidation.
4578 if (paintInvalidationSize == size())
4579 return;
4580
4581 // We need the old border box size only when the box has background or b ox decorations.
4582 if (!style()->hasBackground() && !style()->hasBoxDecorations())
4583 return;
4584 }
4585
4586 ensureRareData().m_previousBorderBoxSize = size();
4587 }
4588
4589 LayoutSize RenderBox::computePreviousBorderBoxSize(const LayoutSize& previousBou ndsSize) const
4590 {
4591 // PreviousBorderBoxSize is only valid when there is background or box decor ations.
4592 ASSERT(style()->hasBackground() || style()->hasBoxDecorations());
4593
4594 if (m_rareData && m_rareData->m_previousBorderBoxSize.width() != -1)
4595 return m_rareData->m_previousBorderBoxSize;
4596
4597 // We didn't save the old border box size because it was the same as the siz e of oldBounds.
4598 return previousBoundsSize;
4599 }
4600
4601 void RenderBox::logicalExtentAfterUpdatingLogicalWidth(const LayoutUnit& newLogi calTop, RenderBox::LogicalExtentComputedValues& computedValues)
4602 {
4603 // FIXME: None of this is right for perpendicular writing-mode children.
4604 LayoutUnit oldLogicalWidth = logicalWidth();
4605 LayoutUnit oldLogicalLeft = logicalLeft();
4606 LayoutUnit oldMarginLeft = marginLeft();
4607 LayoutUnit oldMarginRight = marginRight();
4608 LayoutUnit oldLogicalTop = logicalTop();
4609
4610 setLogicalTop(newLogicalTop);
4611 updateLogicalWidth();
4612
4613 computedValues.m_extent = logicalWidth();
4614 computedValues.m_position = logicalLeft();
4615 computedValues.m_margins.m_start = marginStart();
4616 computedValues.m_margins.m_end = marginEnd();
4617
4618 setLogicalTop(oldLogicalTop);
4619 setLogicalWidth(oldLogicalWidth);
4620 setLogicalLeft(oldLogicalLeft);
4621 setMarginLeft(oldMarginLeft);
4622 setMarginRight(oldMarginRight);
4623 }
4624
4625 void RenderBox::invalidateDisplayItemClients(DisplayItemList* displayItemList) c onst
4626 {
4627 LayoutBoxModelObject::invalidateDisplayItemClients(displayItemList);
4628 if (LayerScrollableArea* area = scrollableArea())
4629 displayItemList->invalidate(area->displayItemClient());
4630 }
4631
4632 } // namespace blink
OLDNEW
« no previous file with comments | « Source/core/rendering/RenderBox.h ('k') | Source/core/rendering/RenderDeprecatedFlexibleBox.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698