/* * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) * (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com) * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #include "core/layout/LayoutBox.h" #include "core/HTMLNames.h" #include "core/dom/Document.h" #include "core/editing/EditingUtilities.h" #include "core/frame/FrameHost.h" #include "core/frame/FrameView.h" #include "core/frame/LocalFrame.h" #include "core/frame/Settings.h" #include "core/html/HTMLElement.h" #include "core/html/HTMLFrameElementBase.h" #include "core/html/HTMLFrameOwnerElement.h" #include "core/input/EventHandler.h" #include "core/layout/HitTestResult.h" #include "core/layout/LayoutAnalyzer.h" #include "core/layout/LayoutDeprecatedFlexibleBox.h" #include "core/layout/LayoutFlexibleBox.h" #include "core/layout/LayoutGeometryMap.h" #include "core/layout/LayoutGrid.h" #include "core/layout/LayoutInline.h" #include "core/layout/LayoutListBox.h" #include "core/layout/LayoutListMarker.h" #include "core/layout/LayoutMultiColumnSpannerPlaceholder.h" #include "core/layout/LayoutPart.h" #include "core/layout/LayoutReplica.h" #include "core/layout/LayoutScrollbarPart.h" #include "core/layout/LayoutTableCell.h" #include "core/layout/LayoutView.h" #include "core/layout/api/LineLayoutBox.h" #include "core/layout/compositing/PaintLayerCompositor.h" #include "core/layout/shapes/ShapeOutsideInfo.h" #include "core/page/AutoscrollController.h" #include "core/page/Page.h" #include "core/paint/BackgroundImageGeometry.h" #include "core/paint/BoxPainter.h" #include "core/paint/PaintLayer.h" #include "core/style/ShadowList.h" #include "platform/LengthFunctions.h" #include "platform/geometry/DoubleRect.h" #include "platform/geometry/FloatQuad.h" #include "platform/geometry/FloatRoundedRect.h" #include "platform/geometry/TransformState.h" #include "platform/graphics/GraphicsContext.h" #include "platform/graphics/paint/PaintController.h" #include #include namespace blink { using namespace HTMLNames; // Used by flexible boxes when flexing this element and by table cells. typedef WTF::HashMap OverrideSizeMap; // Used by grid elements to properly size their grid items. // FIXME: Move these into LayoutBoxRareData. static OverrideSizeMap* gOverrideContainingBlockLogicalHeightMap = nullptr; static OverrideSizeMap* gOverrideContainingBlockLogicalWidthMap = nullptr; static OverrideSizeMap* gExtraInlineOffsetMap = nullptr; static OverrideSizeMap* gExtraBlockOffsetMap = nullptr; // Size of border belt for autoscroll. When mouse pointer in border belt, // autoscroll is started. static const int autoscrollBeltSize = 20; static const unsigned backgroundObscurationTestMaxDepth = 4; struct SameSizeAsLayoutBox : public LayoutBoxModelObject { LayoutRect frameRect; LayoutUnit intrinsicContentLogicalHeight; LayoutRectOutsets marginBoxOutsets; LayoutUnit preferredLogicalWidth[2]; void* pointers[3]; }; static_assert(sizeof(LayoutBox) == sizeof(SameSizeAsLayoutBox), "LayoutBox should stay small"); LayoutBox::LayoutBox(ContainerNode* node) : LayoutBoxModelObject(node) , m_intrinsicContentLogicalHeight(-1) , m_minPreferredLogicalWidth(-1) , m_maxPreferredLogicalWidth(-1) , m_inlineBoxWrapper(nullptr) { setIsBox(); } PaintLayerType LayoutBox::layerTypeRequired() const { // hasAutoZIndex only returns true if the element is positioned or a flex-item since // position:static elements that are not flex-items get their z-index coerced to auto. if (isPositioned() || createsGroup() || hasClipPath() || hasTransformRelatedProperty() || style()->hasCompositorProxy() || hasHiddenBackface() || hasReflection() || style()->specifiesColumns() || !style()->hasAutoZIndex() || style()->shouldCompositeForCurrentAnimations()) return NormalPaintLayer; if (hasOverflowClip()) return OverflowClipPaintLayer; return NoPaintLayer; } void LayoutBox::willBeDestroyed() { clearOverrideSize(); clearContainingBlockOverrideSize(); clearExtraInlineAndBlockOffests(); if (isOutOfFlowPositioned()) LayoutBlock::removePositionedObject(this); removeFromPercentHeightContainer(); if (isOrthogonalWritingModeRoot() && !documentBeingDestroyed()) unmarkOrthogonalWritingModeRoot(); ShapeOutsideInfo::removeInfo(*this); LayoutBoxModelObject::willBeDestroyed(); } void LayoutBox::insertedIntoTree() { LayoutBoxModelObject::insertedIntoTree(); if (isOrthogonalWritingModeRoot()) markOrthogonalWritingModeRoot(); } void LayoutBox::willBeRemovedFromTree() { if (!documentBeingDestroyed() && isOrthogonalWritingModeRoot()) unmarkOrthogonalWritingModeRoot(); LayoutBoxModelObject::willBeRemovedFromTree(); } void LayoutBox::removeFloatingOrPositionedChildFromBlockLists() { ASSERT(isFloatingOrOutOfFlowPositioned()); if (documentBeingDestroyed()) return; if (isFloating()) { LayoutBlockFlow* parentBlockFlow = nullptr; for (LayoutObject* curr = parent(); curr && !curr->isLayoutView(); curr = curr->parent()) { if (curr->isLayoutBlockFlow()) { LayoutBlockFlow* currBlockFlow = toLayoutBlockFlow(curr); if (!parentBlockFlow || currBlockFlow->containsFloat(this)) parentBlockFlow = currBlockFlow; } } if (parentBlockFlow) { parentBlockFlow->markSiblingsWithFloatsForLayout(this); parentBlockFlow->markAllDescendantsWithFloatsForLayout(this, false); } } if (isOutOfFlowPositioned()) LayoutBlock::removePositionedObject(this); } void LayoutBox::styleWillChange(StyleDifference diff, const ComputedStyle& newStyle) { const ComputedStyle* oldStyle = style(); if (oldStyle) { LayoutFlowThread* flowThread = flowThreadContainingBlock(); if (flowThread && flowThread != this) flowThread->flowThreadDescendantStyleWillChange(this, diff, newStyle); // The background of the root element or the body element could propagate up to // the canvas. Just dirty the entire canvas when our style changes substantially. if ((diff.needsPaintInvalidation() || diff.needsLayout()) && node() && (isHTMLHtmlElement(*node()) || isHTMLBodyElement(*node()))) { view()->setShouldDoFullPaintInvalidation(); if (oldStyle->hasEntirelyFixedBackground() != newStyle.hasEntirelyFixedBackground()) view()->compositor()->setNeedsUpdateFixedBackground(); } // When a layout hint happens and an object's position style changes, we have to do a layout // to dirty the layout tree using the old position value now. if (diff.needsFullLayout() && parent() && oldStyle->position() != newStyle.position()) { if (!oldStyle->hasOutOfFlowPosition() && newStyle.hasOutOfFlowPosition()) { // We're about to go out of flow. Before that takes place, we need to mark the // current containing block chain for preferred widths recalculation. setNeedsLayoutAndPrefWidthsRecalc(LayoutInvalidationReason::StyleChange); } else { markContainerChainForLayout(); } if (oldStyle->position() == StaticPosition) setShouldDoFullPaintInvalidation(); else if (newStyle.hasOutOfFlowPosition()) parent()->setChildNeedsLayout(); if (isFloating() && !isOutOfFlowPositioned() && newStyle.hasOutOfFlowPosition()) removeFloatingOrPositionedChildFromBlockLists(); } // FIXME: This branch runs when !oldStyle, which means that layout was never called // so what's the point in invalidating the whole view that we never painted? } else if (isBody()) { view()->setShouldDoFullPaintInvalidation(); } LayoutBoxModelObject::styleWillChange(diff, newStyle); } void LayoutBox::styleDidChange(StyleDifference diff, const ComputedStyle* oldStyle) { // Horizontal writing mode definition is updated in LayoutBoxModelObject::updateFromStyle, // (as part of the LayoutBoxModelObject::styleDidChange call below). So, we can safely cache the horizontal // writing mode value before style change here. bool oldHorizontalWritingMode = isHorizontalWritingMode(); LayoutBoxModelObject::styleDidChange(diff, oldStyle); const ComputedStyle& newStyle = styleRef(); if (needsLayout() && oldStyle) removeFromPercentHeightContainer(); if (oldHorizontalWritingMode != isHorizontalWritingMode()) { if (oldStyle) { if (isOrthogonalWritingModeRoot()) markOrthogonalWritingModeRoot(); else unmarkOrthogonalWritingModeRoot(); } clearPercentHeightDescendants(); } // If our zoom factor changes and we have a defined scrollLeft/Top, we need to adjust that value into the // new zoomed coordinate space. if (hasOverflowClip() && oldStyle && oldStyle->effectiveZoom() != newStyle.effectiveZoom()) { PaintLayerScrollableArea* scrollableArea = this->getScrollableArea(); ASSERT(scrollableArea); if (int left = scrollableArea->scrollXOffset()) { left = (left / oldStyle->effectiveZoom()) * newStyle.effectiveZoom(); scrollableArea->scrollToXOffset(left); } if (int top = scrollableArea->scrollYOffset()) { top = (top / oldStyle->effectiveZoom()) * newStyle.effectiveZoom(); scrollableArea->scrollToYOffset(top); } } // Our opaqueness might have changed without triggering layout. if (diff.needsPaintInvalidation()) { LayoutObject* parentToInvalidate = parent(); for (unsigned i = 0; i < backgroundObscurationTestMaxDepth && parentToInvalidate; ++i) { parentToInvalidate->invalidateBackgroundObscurationStatus(); parentToInvalidate = parentToInvalidate->parent(); } } if (isDocumentElement() || isBody()) { document().view()->recalculateScrollbarOverlayStyle(document().view()->documentBackgroundColor()); document().view()->recalculateCustomScrollbarStyle(); if (LayoutView* layoutView = view()) { if (PaintLayerScrollableArea* scrollableArea = layoutView->getScrollableArea()) { if (scrollableArea->horizontalScrollbar() && scrollableArea->horizontalScrollbar()->isCustomScrollbar()) scrollableArea->horizontalScrollbar()->styleChanged(); if (scrollableArea->verticalScrollbar() && scrollableArea->verticalScrollbar()->isCustomScrollbar()) scrollableArea->verticalScrollbar()->styleChanged(); } } } updateShapeOutsideInfoAfterStyleChange(*style(), oldStyle); updateGridPositionAfterStyleChange(oldStyle); if (LayoutMultiColumnSpannerPlaceholder* placeholder = this->spannerPlaceholder()) placeholder->layoutObjectInFlowThreadStyleDidChange(oldStyle); updateBackgroundAttachmentFixedStatusAfterStyleChange(); if (oldStyle) { LayoutFlowThread* flowThread = flowThreadContainingBlock(); if (flowThread && flowThread != this) flowThread->flowThreadDescendantStyleDidChange(this, diff, *oldStyle); } ASSERT(!isInline() || isAtomicInlineLevel()); // Non-atomic inlines should be LayoutInline or LayoutText, not LayoutBox. } void LayoutBox::updateBackgroundAttachmentFixedStatusAfterStyleChange() { if (!frameView()) return; // On low-powered/mobile devices, preventing blitting on a scroll can cause noticeable delays // when scrolling a page with a fixed background image. As an optimization, assuming there are // no fixed positoned elements on the page, we can acclerate scrolling (via blitting) if we // ignore the CSS property "background-attachment: fixed". bool ignoreFixedBackgroundAttachment = RuntimeEnabledFeatures::fastMobileScrollingEnabled(); if (ignoreFixedBackgroundAttachment) return; // An object needs to be repainted on frame scroll when it has background-attachment:fixed. // LayoutView is responsible for painting root background, thus the root element (and the // body element if html element has no background) skips painting backgrounds. bool isBackgroundAttachmentFixedObject = !isDocumentElement() && !backgroundStolenForBeingBody() && styleRef().hasFixedBackgroundImage(); if (isLayoutView() && view()->compositor()->supportsFixedRootBackgroundCompositing()) { if (styleRef().hasEntirelyFixedBackground()) isBackgroundAttachmentFixedObject = false; } setIsBackgroundAttachmentFixedObject(isBackgroundAttachmentFixedObject); } void LayoutBox::updateShapeOutsideInfoAfterStyleChange(const ComputedStyle& style, const ComputedStyle* oldStyle) { const ShapeValue* shapeOutside = style.shapeOutside(); const ShapeValue* oldShapeOutside = oldStyle ? oldStyle->shapeOutside() : ComputedStyle::initialShapeOutside(); Length shapeMargin = style.shapeMargin(); Length oldShapeMargin = oldStyle ? oldStyle->shapeMargin() : ComputedStyle::initialShapeMargin(); float shapeImageThreshold = style.shapeImageThreshold(); float oldShapeImageThreshold = oldStyle ? oldStyle->shapeImageThreshold() : ComputedStyle::initialShapeImageThreshold(); // FIXME: A future optimization would do a deep comparison for equality. (bug 100811) if (shapeOutside == oldShapeOutside && shapeMargin == oldShapeMargin && shapeImageThreshold == oldShapeImageThreshold) return; if (!shapeOutside) ShapeOutsideInfo::removeInfo(*this); else ShapeOutsideInfo::ensureInfo(*this).markShapeAsDirty(); if (shapeOutside || shapeOutside != oldShapeOutside) markShapeOutsideDependentsForLayout(); } void LayoutBox::updateGridPositionAfterStyleChange(const ComputedStyle* oldStyle) { if (!oldStyle || !parent() || !parent()->isLayoutGrid()) return; if (oldStyle->gridColumnStart() == style()->gridColumnStart() && oldStyle->gridColumnEnd() == style()->gridColumnEnd() && oldStyle->gridRowStart() == style()->gridRowStart() && oldStyle->gridRowEnd() == style()->gridRowEnd() && oldStyle->order() == style()->order() && oldStyle->hasOutOfFlowPosition() == style()->hasOutOfFlowPosition()) return; // It should be possible to not dirty the grid in some cases (like moving an explicitly placed grid item). // For now, it's more simple to just always recompute the grid. toLayoutGrid(parent())->dirtyGrid(); } void LayoutBox::updateFromStyle() { LayoutBoxModelObject::updateFromStyle(); const ComputedStyle& styleToUse = styleRef(); setFloating(!isOutOfFlowPositioned() && styleToUse.isFloating()); setHasTransformRelatedProperty(styleToUse.hasTransformRelatedProperty()); setHasReflection(styleToUse.boxReflect()); } void LayoutBox::layout() { ASSERT(needsLayout()); LayoutAnalyzer::Scope analyzer(*this); LayoutObject* child = slowFirstChild(); if (!child) { clearNeedsLayout(); return; } LayoutState state(*this, locationOffset()); while (child) { child->layoutIfNeeded(); ASSERT(!child->needsLayout()); child = child->nextSibling(); } invalidateBackgroundObscurationStatus(); clearNeedsLayout(); } // More IE extensions. clientWidth and clientHeight represent the interior of an object // excluding border and scrollbar. LayoutUnit LayoutBox::clientWidth() const { return m_frameRect.width() - borderLeft() - borderRight() - verticalScrollbarWidth(); } LayoutUnit LayoutBox::clientHeight() const { return m_frameRect.height() - borderTop() - borderBottom() - horizontalScrollbarHeight(); } int LayoutBox::pixelSnappedClientWidth() const { return snapSizeToPixel(clientWidth(), location().x() + clientLeft()); } int LayoutBox::pixelSnappedClientHeight() const { return snapSizeToPixel(clientHeight(), location().y() + clientTop()); } int LayoutBox::pixelSnappedOffsetWidth() const { return snapSizeToPixel(offsetWidth(), location().x() + clientLeft()); } int LayoutBox::pixelSnappedOffsetHeight() const { return snapSizeToPixel(offsetHeight(), location().y() + clientTop()); } LayoutUnit LayoutBox::scrollWidth() const { if (hasOverflowClip()) return getScrollableArea()->scrollWidth(); // For objects with visible overflow, this matches IE. // FIXME: Need to work right with writing modes. if (style()->isLeftToRightDirection()) return std::max(clientWidth(), layoutOverflowRect().maxX() - borderLeft()); return clientWidth() - std::min(LayoutUnit(), layoutOverflowRect().x() - borderLeft()); } LayoutUnit LayoutBox::scrollHeight() const { if (hasOverflowClip()) return getScrollableArea()->scrollHeight(); // For objects with visible overflow, this matches IE. // FIXME: Need to work right with writing modes. return std::max(clientHeight(), layoutOverflowRect().maxY() - borderTop()); } LayoutUnit LayoutBox::scrollLeft() const { return hasOverflowClip() ? LayoutUnit(getScrollableArea()->scrollXOffset()) : LayoutUnit(); } LayoutUnit LayoutBox::scrollTop() const { return hasOverflowClip() ? LayoutUnit(getScrollableArea()->scrollYOffset()) : LayoutUnit(); } int LayoutBox::pixelSnappedScrollWidth() const { return snapSizeToPixel(scrollWidth(), location().x() + clientLeft()); } int LayoutBox::pixelSnappedScrollHeight() const { if (hasOverflowClip()) return snapSizeToPixel(getScrollableArea()->scrollHeight(), location().y() + clientTop()); // For objects with visible overflow, this matches IE. // FIXME: Need to work right with writing modes. return snapSizeToPixel(scrollHeight(), location().y() + clientTop()); } void LayoutBox::setScrollLeft(LayoutUnit newLeft) { // This doesn't hit in any tests, but since the equivalent code in setScrollTop // does, presumably this code does as well. DisableCompositingQueryAsserts disabler; if (hasOverflowClip()) getScrollableArea()->scrollToXOffset(newLeft, ScrollOffsetClamped, ScrollBehaviorAuto); } void LayoutBox::setScrollTop(LayoutUnit newTop) { // Hits in compositing/overflow/do-not-assert-on-invisible-composited-layers.html DisableCompositingQueryAsserts disabler; if (hasOverflowClip()) getScrollableArea()->scrollToYOffset(newTop, ScrollOffsetClamped, ScrollBehaviorAuto); } void LayoutBox::scrollToOffset(const DoubleSize& offset, ScrollBehavior scrollBehavior) { // This doesn't hit in any tests, but since the equivalent code in setScrollTop // does, presumably this code does as well. DisableCompositingQueryAsserts disabler; if (hasOverflowClip()) getScrollableArea()->scrollToOffset(offset, ScrollOffsetClamped, scrollBehavior); } // Returns true iff we are attempting an autoscroll inside an iframe with scrolling="no". static bool isDisallowedAutoscroll(HTMLFrameOwnerElement* ownerElement, FrameView* frameView) { if (ownerElement && isHTMLFrameElementBase(*ownerElement)) { HTMLFrameElementBase* frameElementBase = toHTMLFrameElementBase(ownerElement); if (Page* page = frameView->frame().page()) { return page->autoscrollController().autoscrollInProgress() && frameElementBase->scrollingMode() == ScrollbarAlwaysOff; } } return false; } void LayoutBox::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY, ScrollType scrollType, bool makeVisibleInVisualViewport) { ASSERT(scrollType == ProgrammaticScroll || scrollType == UserScroll); // Presumably the same issue as in setScrollTop. See crbug.com/343132. DisableCompositingQueryAsserts disabler; LayoutBox* parentBox = nullptr; LayoutRect newRect = rect; bool restrictedByLineClamp = false; if (parent()) { parentBox = parent()->enclosingBox(); restrictedByLineClamp = !parent()->style()->lineClamp().isNone(); } if (hasOverflowClip() && !restrictedByLineClamp) { // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property. // This will prevent us from revealing text hidden by the slider in Safari RSS. newRect = getScrollableArea()->scrollIntoView(rect, alignX, alignY, scrollType); } else if (!parentBox && canBeProgramaticallyScrolled()) { if (FrameView* frameView = this->frameView()) { HTMLFrameOwnerElement* ownerElement = document().ownerElement(); if (!isDisallowedAutoscroll(ownerElement, frameView)) { if (makeVisibleInVisualViewport) { frameView->getScrollableArea()->scrollIntoView(rect, alignX, alignY, scrollType); } else { frameView->layoutViewportScrollableArea()->scrollIntoView(rect, alignX, alignY, scrollType); } if (ownerElement && ownerElement->layoutObject()) { if (frameView->safeToPropagateScrollToParent()) { parentBox = ownerElement->layoutObject()->enclosingBox(); LayoutView* parentView = ownerElement->layoutObject()->view(); newRect = enclosingLayoutRect(view()->localToAncestorQuad(FloatRect(rect), parentView, UseTransforms | TraverseDocumentBoundaries).boundingBox()); } else { parentBox = nullptr; } } } } } // If we are fixed-position, it is useless to scroll the parent. if (hasLayer() && layer()->scrollsWithViewport()) return; if (frame()->page()->autoscrollController().autoscrollInProgress()) parentBox = enclosingScrollableBox(); if (parentBox) parentBox->scrollRectToVisible(newRect, alignX, alignY, scrollType, makeVisibleInVisualViewport); } void LayoutBox::absoluteRects(Vector& rects, const LayoutPoint& accumulatedOffset) const { rects.append(pixelSnappedIntRect(accumulatedOffset, size())); } void LayoutBox::absoluteQuads(Vector& quads, bool* wasFixed) const { quads.append(localToAbsoluteQuad(FloatRect(0, 0, m_frameRect.width().toFloat(), m_frameRect.height().toFloat()), 0 /* mode */, wasFixed)); } void LayoutBox::updateLayerTransformAfterLayout() { // Transform-origin depends on box size, so we need to update the layer transform after layout. if (hasLayer()) layer()->updateTransformationMatrix(); } LayoutUnit LayoutBox::constrainLogicalWidthByMinMax(LayoutUnit logicalWidth, LayoutUnit availableWidth, LayoutBlock* cb) const { const ComputedStyle& styleToUse = styleRef(); if (!styleToUse.logicalMaxWidth().isMaxSizeNone()) logicalWidth = std::min(logicalWidth, computeLogicalWidthUsing(MaxSize, styleToUse.logicalMaxWidth(), availableWidth, cb)); return std::max(logicalWidth, computeLogicalWidthUsing(MinSize, styleToUse.logicalMinWidth(), availableWidth, cb)); } LayoutUnit LayoutBox::constrainLogicalHeightByMinMax(LayoutUnit logicalHeight, LayoutUnit intrinsicContentHeight) const { const ComputedStyle& styleToUse = styleRef(); if (!styleToUse.logicalMaxHeight().isMaxSizeNone()) { LayoutUnit maxH = computeLogicalHeightUsing(MaxSize, styleToUse.logicalMaxHeight(), intrinsicContentHeight); if (maxH != -1) logicalHeight = std::min(logicalHeight, maxH); } return std::max(logicalHeight, computeLogicalHeightUsing(MinSize, styleToUse.logicalMinHeight(), intrinsicContentHeight)); } LayoutUnit LayoutBox::constrainContentBoxLogicalHeightByMinMax(LayoutUnit logicalHeight, LayoutUnit intrinsicContentHeight) const { // If the min/max height and logical height are both percentages we take advantage of already knowing the current resolved percentage height // to avoid recursing up through our containing blocks again to determine it. const ComputedStyle& styleToUse = styleRef(); if (!styleToUse.logicalMaxHeight().isMaxSizeNone()) { if (styleToUse.logicalMaxHeight().type() == Percent && styleToUse.logicalHeight().type() == Percent) { LayoutUnit availableLogicalHeight(logicalHeight / styleToUse.logicalHeight().value() * 100); logicalHeight = std::min(logicalHeight, valueForLength(styleToUse.logicalMaxHeight(), availableLogicalHeight)); } else { LayoutUnit maxHeight(computeContentLogicalHeight(MaxSize, styleToUse.logicalMaxHeight(), LayoutUnit(-1))); if (maxHeight != -1) logicalHeight = std::min(logicalHeight, maxHeight); } } if (styleToUse.logicalMinHeight().type() == Percent && styleToUse.logicalHeight().type() == Percent) { LayoutUnit availableLogicalHeight(logicalHeight / styleToUse.logicalHeight().value() * 100); logicalHeight = std::max(logicalHeight, valueForLength(styleToUse.logicalMinHeight(), availableLogicalHeight)); } else { logicalHeight = std::max(logicalHeight, computeContentLogicalHeight(MinSize, styleToUse.logicalMinHeight(), intrinsicContentHeight)); } return logicalHeight; } void LayoutBox::setLocationAndUpdateOverflowControlsIfNeeded(const LayoutPoint& location) { if (hasOverflowClip()) { IntSize oldPixelSnappedBorderRectSize = pixelSnappedBorderBoxRect().size(); setLocation(location); if (pixelSnappedBorderBoxRect().size() != oldPixelSnappedBorderRectSize) getScrollableArea()->updateAfterLayout(); return; } setLocation(location); } IntRect LayoutBox::absoluteContentBox() const { // This is wrong with transforms and flipped writing modes. IntRect rect = pixelSnappedIntRect(contentBoxRect()); FloatPoint absPos = localToAbsolute(); rect.move(absPos.x(), absPos.y()); return rect; } IntSize LayoutBox::absoluteContentBoxOffset() const { IntPoint offset = roundedIntPoint(contentBoxOffset()); FloatPoint absPos = localToAbsolute(); offset.move(absPos.x(), absPos.y()); return toIntSize(offset); } FloatQuad LayoutBox::absoluteContentQuad() const { LayoutRect rect = contentBoxRect(); return localToAbsoluteQuad(FloatRect(rect)); } void LayoutBox::addOutlineRects(Vector& rects, const LayoutPoint& additionalOffset, IncludeBlockVisualOverflowOrNot) const { rects.append(LayoutRect(additionalOffset, size())); } bool LayoutBox::canResize() const { // We need a special case for