Index: third_party/WebKit/Source/core/layout/LayoutFieldset.cpp |
diff --git a/third_party/WebKit/Source/core/layout/LayoutFieldset.cpp b/third_party/WebKit/Source/core/layout/LayoutFieldset.cpp |
index 1af7515adb104d99aa17dda22498d3289939bd56..9ef8dc2b46ff70a141f3c227213fb7d8eafe93ac 100644 |
--- a/third_party/WebKit/Source/core/layout/LayoutFieldset.cpp |
+++ b/third_party/WebKit/Source/core/layout/LayoutFieldset.cpp |
@@ -25,6 +25,7 @@ |
#include "core/CSSPropertyNames.h" |
#include "core/HTMLNames.h" |
+#include "core/dom/AXObjectCache.h" |
#include "core/html/HTMLLegendElement.h" |
#include "core/paint/FieldsetPainter.h" |
@@ -34,27 +35,83 @@ namespace blink { |
using namespace HTMLNames; |
+namespace { |
+ |
+void setInnerBlockPadding(bool isHorizontalWritingMode, const LayoutObject* innerBlock, const LayoutUnit& padding) |
+{ |
+ if (isHorizontalWritingMode) |
+ innerBlock->mutableStyleRef().setPaddingTop(Length(padding, Fixed)); |
+ else |
+ innerBlock->mutableStyleRef().setPaddingLeft(Length(padding, Fixed)); |
+} |
+ |
+void resetInnerBlockPadding(bool isHorizontalWritingMode, const LayoutObject* innerBlock) |
+{ |
+ if (isHorizontalWritingMode) |
+ innerBlock->mutableStyleRef().setPaddingTop(Length(0, Fixed)); |
+ else |
+ innerBlock->mutableStyleRef().setPaddingLeft(Length(0, Fixed)); |
+} |
+ |
+} // namespace |
+ |
LayoutFieldset::LayoutFieldset(Element* element) |
- : LayoutBlockFlow(element) |
+ : LayoutFlexibleBox(element) |
+ , m_innerBlock(nullptr) |
+{ |
+} |
+ |
+int LayoutFieldset::baselinePosition(FontBaseline baseline, bool firstLine, LineDirectionMode direction, LinePositionMode position) const |
{ |
+ return LayoutBlock::baselinePosition(baseline, firstLine, direction, position); |
} |
-void LayoutFieldset::computePreferredLogicalWidths() |
+void LayoutFieldset::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const |
{ |
- LayoutBlockFlow::computePreferredLogicalWidths(); |
- if (LayoutBox* legend = findInFlowLegend()) { |
- int legendMinWidth = legend->minPreferredLogicalWidth(); |
+ for (LayoutBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { |
+ if (child->isOutOfFlowPositioned()) |
+ continue; |
+ |
+ LayoutUnit margin = marginIntrinsicLogicalWidthForChild(*child); |
+ |
+ LayoutUnit minPreferredLogicalWidth; |
+ LayoutUnit maxPreferredLogicalWidth; |
+ computeChildPreferredLogicalWidths(*child, minPreferredLogicalWidth, maxPreferredLogicalWidth); |
+ DCHECK_GE(minPreferredLogicalWidth, LayoutUnit()); |
+ DCHECK_GE(maxPreferredLogicalWidth, LayoutUnit()); |
+ minPreferredLogicalWidth += margin; |
+ maxPreferredLogicalWidth += margin; |
+ minLogicalWidth = std::max(minPreferredLogicalWidth, minLogicalWidth); |
+ maxLogicalWidth = std::max(maxPreferredLogicalWidth, maxLogicalWidth); |
+ } |
- Length legendMarginLeft = legend->style()->marginLeft(); |
- Length legendMarginRight = legend->style()->marginRight(); |
+ maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth); |
- if (legendMarginLeft.isFixed()) |
- legendMinWidth += legendMarginLeft.value(); |
+ // Due to negative margins, it is possible that we calculated a negative intrinsic width. Make sure that we |
+ // never return a negative width. |
+ minLogicalWidth = std::max(LayoutUnit(), minLogicalWidth); |
+ maxLogicalWidth = std::max(LayoutUnit(), maxLogicalWidth); |
- if (legendMarginRight.isFixed()) |
- legendMinWidth += legendMarginRight.value(); |
+ LayoutUnit scrollbarWidth(scrollbarLogicalWidth()); |
+ maxLogicalWidth += scrollbarWidth; |
+ minLogicalWidth += scrollbarWidth; |
+} |
+ |
+void LayoutFieldset::setLogicalLeftForChild(LayoutBox& child, LayoutUnit logicalLeft) |
+{ |
+ if (isHorizontalWritingMode()) { |
+ child.setX(logicalLeft); |
+ } else { |
+ child.setY(logicalLeft); |
+ } |
+} |
- m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, legendMinWidth + borderAndPaddingWidth()); |
+void LayoutFieldset::setLogicalTopForChild(LayoutBox& child, LayoutUnit logicalTop) |
+{ |
+ if (isHorizontalWritingMode()) { |
+ child.setY(logicalTop); |
+ } else { |
+ child.setX(logicalTop); |
} |
} |
@@ -106,6 +163,7 @@ LayoutObject* LayoutFieldset::layoutSpecialExcludedChild(bool relayoutChildren, |
LayoutUnit legendLogicalTop; |
LayoutUnit collapsedLegendExtent; |
+ LayoutUnit innerBlockPadding; |
// FIXME: We need to account for the legend's margin before too. |
if (fieldsetBorderBefore > legendLogicalHeight) { |
// The <legend> is smaller than the associated fieldset before border |
@@ -114,16 +172,22 @@ LayoutObject* LayoutFieldset::layoutSpecialExcludedChild(bool relayoutChildren, |
// Firefox completely ignores the margins in this case which seems wrong. |
legendLogicalTop = (fieldsetBorderBefore - legendLogicalHeight) / 2; |
collapsedLegendExtent = max<LayoutUnit>(fieldsetBorderBefore, legendLogicalTop + legendLogicalHeight + marginAfterForChild(*legend)); |
+ innerBlockPadding = marginAfterForChild(*legend) ? marginAfterForChild(*legend) - legendLogicalTop : LayoutUnit(); |
} else { |
collapsedLegendExtent = legendLogicalHeight + marginAfterForChild(*legend); |
+ innerBlockPadding = legendLogicalHeight - borderAfter() + marginAfterForChild(*legend); |
} |
+ if (m_innerBlock) |
+ setInnerBlockPadding(isHorizontalWritingMode(), m_innerBlock, innerBlockPadding); |
setLogicalTopForChild(*legend, legendLogicalTop); |
setLogicalHeight(paddingBefore() + collapsedLegendExtent); |
if (legend->frameRect() != oldLegendFrameRect) { |
// We need to invalidate the fieldset border if the legend's frame changed. |
setShouldDoFullPaintInvalidation(); |
+ if (m_innerBlock) |
+ m_innerBlock->setNeedsLayout(LayoutInvalidationReason::FieldsetChanged, MarkOnlyThis); |
} |
} |
return legend; |
@@ -153,4 +217,66 @@ void LayoutFieldset::paintMask(const PaintInfo& paintInfo, const LayoutPoint& pa |
FieldsetPainter(*this).paintMask(paintInfo, paintOffset); |
} |
+void LayoutFieldset::styleDidChange(StyleDifference diff, const ComputedStyle* oldStyle) |
+{ |
+ LayoutFlexibleBox::styleDidChange(diff, oldStyle); |
+} |
+ |
+void LayoutFieldset::updateAnonymousChildStyle(const LayoutObject& child, ComputedStyle& childStyle) const |
+{ |
+ childStyle.setFlexShrink(1.0f); |
+ childStyle.setFlexGrow(1.0f); |
+ // min-width: 0; is needed for correct shrinking. |
+ childStyle.setMinWidth(Length(0, Fixed)); |
+ childStyle.setFlexDirection(style()->flexDirection()); |
+ childStyle.setJustifyContent(style()->justifyContent()); |
+ childStyle.setFlexWrap(style()->flexWrap()); |
+ childStyle.setAlignItems(style()->alignItems()); |
+ childStyle.setAlignContent(style()->alignContent()); |
+ // Let anonymous block to be the 1st for correct layout positioning. |
+ childStyle.setOrder(1); |
+} |
+ |
+void LayoutFieldset::addChild(LayoutObject* newChild, LayoutObject* beforeChild) |
+{ |
+ if (!m_innerBlock) |
+ createInnerBlock(); |
+ |
+ if (isHTMLLegendElement(newChild->node())) { |
+ // Let legend block to be the 2nd for correct layout positioning. |
+ newChild->mutableStyle()->setOrder(2); |
+ LayoutFlexibleBox::addChild(newChild, m_innerBlock); |
+ } else { |
+ m_innerBlock->addChild(newChild, beforeChild); |
+ if (AXObjectCache* cache = document().existingAXObjectCache()) |
+ cache->childrenChanged(this); |
+ } |
+} |
+ |
+void LayoutFieldset::createInnerBlock() |
+{ |
+ if (m_innerBlock) { |
+ DCHECK(firstChild() == m_innerBlock); |
+ return; |
+ } |
+ m_innerBlock = createAnonymousBlock(style()->display()); |
+ LayoutFlexibleBox::addChild(m_innerBlock); |
+} |
+ |
+void LayoutFieldset::removeChild(LayoutObject* oldChild) |
+{ |
+ if (isHTMLLegendElement(oldChild->node())) { |
+ LayoutFlexibleBox::removeChild(oldChild); |
+ if (m_innerBlock) |
+ resetInnerBlockPadding(isHorizontalWritingMode(), m_innerBlock); |
+ } else if (oldChild == m_innerBlock) { |
+ LayoutFlexibleBox::removeChild(oldChild); |
+ m_innerBlock = nullptr; |
+ } else if (oldChild->parent() == this) { |
+ LayoutFlexibleBox::removeChild(oldChild); |
+ } else if (m_innerBlock) { |
+ m_innerBlock->removeChild(oldChild); |
+ } |
+} |
+ |
} // namespace blink |