| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
| 4 * (C) 2000 Dirk Mueller (mueller@kde.org) | 4 * (C) 2000 Dirk Mueller (mueller@kde.org) |
| 5 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. | 5 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. |
| 6 * | 6 * |
| 7 * This library is free software; you can redistribute it and/or | 7 * This library is free software; you can redistribute it and/or |
| 8 * modify it under the terms of the GNU Library General Public | 8 * modify it under the terms of the GNU Library General Public |
| 9 * License as published by the Free Software Foundation; either | 9 * License as published by the Free Software Foundation; either |
| 10 * version 2 of the License, or (at your option) any later version. | 10 * version 2 of the License, or (at your option) any later version. |
| 11 * | 11 * |
| 12 * This library is distributed in the hope that it will be useful, | 12 * This library is distributed in the hope that it will be useful, |
| 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 15 * Library General Public License for more details. | 15 * Library General Public License for more details. |
| 16 * | 16 * |
| 17 * You should have received a copy of the GNU Library General Public License | 17 * You should have received a copy of the GNU Library General Public License |
| 18 * along with this library; see the file COPYING.LIB. If not, write to | 18 * along with this library; see the file COPYING.LIB. If not, write to |
| 19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| 20 * Boston, MA 02110-1301, USA. | 20 * Boston, MA 02110-1301, USA. |
| 21 * | 21 * |
| 22 */ | 22 */ |
| 23 | 23 |
| 24 #include "core/layout/LayoutFieldset.h" | 24 #include "core/layout/LayoutFieldset.h" |
| 25 | 25 |
| 26 #include "core/CSSPropertyNames.h" | 26 #include "core/CSSPropertyNames.h" |
| 27 #include "core/HTMLNames.h" | 27 #include "core/HTMLNames.h" |
| 28 #include "core/dom/AXObjectCache.h" |
| 28 #include "core/html/HTMLLegendElement.h" | 29 #include "core/html/HTMLLegendElement.h" |
| 29 #include "core/paint/FieldsetPainter.h" | 30 #include "core/paint/FieldsetPainter.h" |
| 30 | 31 |
| 31 using namespace std; | 32 using namespace std; |
| 32 | 33 |
| 33 namespace blink { | 34 namespace blink { |
| 34 | 35 |
| 35 using namespace HTMLNames; | 36 using namespace HTMLNames; |
| 36 | 37 |
| 38 namespace { |
| 39 |
| 40 void setInnerBlockPadding(bool isHorizontalWritingMode, const LayoutObject* inne
rBlock, const LayoutUnit& padding) |
| 41 { |
| 42 if (isHorizontalWritingMode) |
| 43 innerBlock->mutableStyleRef().setPaddingTop(Length(padding, Fixed)); |
| 44 else |
| 45 innerBlock->mutableStyleRef().setPaddingLeft(Length(padding, Fixed)); |
| 46 } |
| 47 |
| 48 void resetInnerBlockPadding(bool isHorizontalWritingMode, const LayoutObject* in
nerBlock) |
| 49 { |
| 50 if (isHorizontalWritingMode) |
| 51 innerBlock->mutableStyleRef().setPaddingTop(Length(0, Fixed)); |
| 52 else |
| 53 innerBlock->mutableStyleRef().setPaddingLeft(Length(0, Fixed)); |
| 54 } |
| 55 |
| 56 } // namespace |
| 57 |
| 37 LayoutFieldset::LayoutFieldset(Element* element) | 58 LayoutFieldset::LayoutFieldset(Element* element) |
| 38 : LayoutBlockFlow(element) | 59 : LayoutFlexibleBox(element) |
| 60 , m_innerBlock(nullptr) |
| 39 { | 61 { |
| 40 } | 62 } |
| 41 | 63 |
| 42 void LayoutFieldset::computePreferredLogicalWidths() | 64 int LayoutFieldset::baselinePosition(FontBaseline baseline, bool firstLine, Line
DirectionMode direction, LinePositionMode position) const |
| 43 { | 65 { |
| 44 LayoutBlockFlow::computePreferredLogicalWidths(); | 66 return LayoutBlock::baselinePosition(baseline, firstLine, direction, positio
n); |
| 45 if (LayoutBox* legend = findInFlowLegend()) { | 67 } |
| 46 int legendMinWidth = legend->minPreferredLogicalWidth(); | |
| 47 | 68 |
| 48 Length legendMarginLeft = legend->style()->marginLeft(); | 69 void LayoutFieldset::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth,
LayoutUnit& maxLogicalWidth) const |
| 49 Length legendMarginRight = legend->style()->marginRight(); | 70 { |
| 71 for (LayoutBox* child = firstChildBox(); child; child = child->nextSiblingBo
x()) { |
| 72 if (child->isOutOfFlowPositioned()) |
| 73 continue; |
| 50 | 74 |
| 51 if (legendMarginLeft.isFixed()) | 75 LayoutUnit margin = marginIntrinsicLogicalWidthForChild(*child); |
| 52 legendMinWidth += legendMarginLeft.value(); | |
| 53 | 76 |
| 54 if (legendMarginRight.isFixed()) | 77 LayoutUnit minPreferredLogicalWidth; |
| 55 legendMinWidth += legendMarginRight.value(); | 78 LayoutUnit maxPreferredLogicalWidth; |
| 79 computeChildPreferredLogicalWidths(*child, minPreferredLogicalWidth, max
PreferredLogicalWidth); |
| 80 DCHECK_GE(minPreferredLogicalWidth, LayoutUnit()); |
| 81 DCHECK_GE(maxPreferredLogicalWidth, LayoutUnit()); |
| 82 minPreferredLogicalWidth += margin; |
| 83 maxPreferredLogicalWidth += margin; |
| 84 minLogicalWidth = std::max(minPreferredLogicalWidth, minLogicalWidth); |
| 85 maxLogicalWidth = std::max(maxPreferredLogicalWidth, maxLogicalWidth); |
| 86 } |
| 56 | 87 |
| 57 m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, legendMinWi
dth + borderAndPaddingWidth()); | 88 maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth); |
| 89 |
| 90 // Due to negative margins, it is possible that we calculated a negative int
rinsic width. Make sure that we |
| 91 // never return a negative width. |
| 92 minLogicalWidth = std::max(LayoutUnit(), minLogicalWidth); |
| 93 maxLogicalWidth = std::max(LayoutUnit(), maxLogicalWidth); |
| 94 |
| 95 LayoutUnit scrollbarWidth(scrollbarLogicalWidth()); |
| 96 maxLogicalWidth += scrollbarWidth; |
| 97 minLogicalWidth += scrollbarWidth; |
| 98 } |
| 99 |
| 100 void LayoutFieldset::setLogicalLeftForChild(LayoutBox& child, LayoutUnit logical
Left) |
| 101 { |
| 102 if (isHorizontalWritingMode()) { |
| 103 child.setX(logicalLeft); |
| 104 } else { |
| 105 child.setY(logicalLeft); |
| 58 } | 106 } |
| 59 } | 107 } |
| 60 | 108 |
| 109 void LayoutFieldset::setLogicalTopForChild(LayoutBox& child, LayoutUnit logicalT
op) |
| 110 { |
| 111 if (isHorizontalWritingMode()) { |
| 112 child.setY(logicalTop); |
| 113 } else { |
| 114 child.setX(logicalTop); |
| 115 } |
| 116 } |
| 117 |
| 61 LayoutObject* LayoutFieldset::layoutSpecialExcludedChild(bool relayoutChildren,
SubtreeLayoutScope&) | 118 LayoutObject* LayoutFieldset::layoutSpecialExcludedChild(bool relayoutChildren,
SubtreeLayoutScope&) |
| 62 { | 119 { |
| 63 LayoutBox* legend = findInFlowLegend(); | 120 LayoutBox* legend = findInFlowLegend(); |
| 64 if (legend) { | 121 if (legend) { |
| 65 LayoutRect oldLegendFrameRect = legend->frameRect(); | 122 LayoutRect oldLegendFrameRect = legend->frameRect(); |
| 66 | 123 |
| 67 if (relayoutChildren) | 124 if (relayoutChildren) |
| 68 legend->setNeedsLayoutAndFullPaintInvalidation(LayoutInvalidationRea
son::FieldsetChanged); | 125 legend->setNeedsLayoutAndFullPaintInvalidation(LayoutInvalidationRea
son::FieldsetChanged); |
| 69 legend->layoutIfNeeded(); | 126 legend->layoutIfNeeded(); |
| 70 | 127 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 99 } | 156 } |
| 100 } | 157 } |
| 101 | 158 |
| 102 setLogicalLeftForChild(*legend, logicalLeft); | 159 setLogicalLeftForChild(*legend, logicalLeft); |
| 103 | 160 |
| 104 LayoutUnit fieldsetBorderBefore = LayoutUnit(borderBefore()); | 161 LayoutUnit fieldsetBorderBefore = LayoutUnit(borderBefore()); |
| 105 LayoutUnit legendLogicalHeight = logicalHeightForChild(*legend); | 162 LayoutUnit legendLogicalHeight = logicalHeightForChild(*legend); |
| 106 | 163 |
| 107 LayoutUnit legendLogicalTop; | 164 LayoutUnit legendLogicalTop; |
| 108 LayoutUnit collapsedLegendExtent; | 165 LayoutUnit collapsedLegendExtent; |
| 166 LayoutUnit innerBlockPadding; |
| 109 // FIXME: We need to account for the legend's margin before too. | 167 // FIXME: We need to account for the legend's margin before too. |
| 110 if (fieldsetBorderBefore > legendLogicalHeight) { | 168 if (fieldsetBorderBefore > legendLogicalHeight) { |
| 111 // The <legend> is smaller than the associated fieldset before borde
r | 169 // The <legend> is smaller than the associated fieldset before borde
r |
| 112 // so the latter determines positioning of the <legend>. The sizing
depends | 170 // so the latter determines positioning of the <legend>. The sizing
depends |
| 113 // on the legend's margins as we want to still follow the author's c
ues. | 171 // on the legend's margins as we want to still follow the author's c
ues. |
| 114 // Firefox completely ignores the margins in this case which seems w
rong. | 172 // Firefox completely ignores the margins in this case which seems w
rong. |
| 115 legendLogicalTop = (fieldsetBorderBefore - legendLogicalHeight) / 2; | 173 legendLogicalTop = (fieldsetBorderBefore - legendLogicalHeight) / 2; |
| 116 collapsedLegendExtent = max<LayoutUnit>(fieldsetBorderBefore, legend
LogicalTop + legendLogicalHeight + marginAfterForChild(*legend)); | 174 collapsedLegendExtent = max<LayoutUnit>(fieldsetBorderBefore, legend
LogicalTop + legendLogicalHeight + marginAfterForChild(*legend)); |
| 175 innerBlockPadding = marginAfterForChild(*legend) ? marginAfterForChi
ld(*legend) - legendLogicalTop : LayoutUnit(); |
| 117 } else { | 176 } else { |
| 118 collapsedLegendExtent = legendLogicalHeight + marginAfterForChild(*l
egend); | 177 collapsedLegendExtent = legendLogicalHeight + marginAfterForChild(*l
egend); |
| 178 innerBlockPadding = legendLogicalHeight - borderAfter() + marginAfte
rForChild(*legend); |
| 119 } | 179 } |
| 120 | 180 |
| 181 if (m_innerBlock) |
| 182 setInnerBlockPadding(isHorizontalWritingMode(), m_innerBlock, innerB
lockPadding); |
| 121 setLogicalTopForChild(*legend, legendLogicalTop); | 183 setLogicalTopForChild(*legend, legendLogicalTop); |
| 122 setLogicalHeight(paddingBefore() + collapsedLegendExtent); | 184 setLogicalHeight(paddingBefore() + collapsedLegendExtent); |
| 123 | 185 |
| 124 if (legend->frameRect() != oldLegendFrameRect) { | 186 if (legend->frameRect() != oldLegendFrameRect) { |
| 125 // We need to invalidate the fieldset border if the legend's frame c
hanged. | 187 // We need to invalidate the fieldset border if the legend's frame c
hanged. |
| 126 setShouldDoFullPaintInvalidation(); | 188 setShouldDoFullPaintInvalidation(); |
| 189 if (m_innerBlock) |
| 190 m_innerBlock->setNeedsLayout(LayoutInvalidationReason::FieldsetC
hanged, MarkOnlyThis); |
| 127 } | 191 } |
| 128 } | 192 } |
| 129 return legend; | 193 return legend; |
| 130 } | 194 } |
| 131 | 195 |
| 132 LayoutBox* LayoutFieldset::findInFlowLegend() const | 196 LayoutBox* LayoutFieldset::findInFlowLegend() const |
| 133 { | 197 { |
| 134 for (LayoutObject* legend = firstChild(); legend; legend = legend->nextSibli
ng()) { | 198 for (LayoutObject* legend = firstChild(); legend; legend = legend->nextSibli
ng()) { |
| 135 if (legend->isFloatingOrOutOfFlowPositioned()) | 199 if (legend->isFloatingOrOutOfFlowPositioned()) |
| 136 continue; | 200 continue; |
| 137 | 201 |
| 138 if (isHTMLLegendElement(legend->node())) { | 202 if (isHTMLLegendElement(legend->node())) { |
| 139 if (legend->isBox()) | 203 if (legend->isBox()) |
| 140 return toLayoutBox(legend); | 204 return toLayoutBox(legend); |
| 141 } | 205 } |
| 142 } | 206 } |
| 143 return nullptr; | 207 return nullptr; |
| 144 } | 208 } |
| 145 | 209 |
| 146 void LayoutFieldset::paintBoxDecorationBackground(const PaintInfo& paintInfo, co
nst LayoutPoint& paintOffset) const | 210 void LayoutFieldset::paintBoxDecorationBackground(const PaintInfo& paintInfo, co
nst LayoutPoint& paintOffset) const |
| 147 { | 211 { |
| 148 FieldsetPainter(*this).paintBoxDecorationBackground(paintInfo, paintOffset); | 212 FieldsetPainter(*this).paintBoxDecorationBackground(paintInfo, paintOffset); |
| 149 } | 213 } |
| 150 | 214 |
| 151 void LayoutFieldset::paintMask(const PaintInfo& paintInfo, const LayoutPoint& pa
intOffset) const | 215 void LayoutFieldset::paintMask(const PaintInfo& paintInfo, const LayoutPoint& pa
intOffset) const |
| 152 { | 216 { |
| 153 FieldsetPainter(*this).paintMask(paintInfo, paintOffset); | 217 FieldsetPainter(*this).paintMask(paintInfo, paintOffset); |
| 154 } | 218 } |
| 155 | 219 |
| 220 void LayoutFieldset::styleDidChange(StyleDifference diff, const ComputedStyle* o
ldStyle) |
| 221 { |
| 222 LayoutFlexibleBox::styleDidChange(diff, oldStyle); |
| 223 } |
| 224 |
| 225 void LayoutFieldset::updateAnonymousChildStyle(const LayoutObject& child, Comput
edStyle& childStyle) const |
| 226 { |
| 227 childStyle.setFlexShrink(1.0f); |
| 228 childStyle.setFlexGrow(1.0f); |
| 229 // min-width: 0; is needed for correct shrinking. |
| 230 childStyle.setMinWidth(Length(0, Fixed)); |
| 231 childStyle.setFlexDirection(style()->flexDirection()); |
| 232 childStyle.setJustifyContent(style()->justifyContent()); |
| 233 childStyle.setFlexWrap(style()->flexWrap()); |
| 234 childStyle.setAlignItems(style()->alignItems()); |
| 235 childStyle.setAlignContent(style()->alignContent()); |
| 236 // Let anonymous block to be the 1st for correct layout positioning. |
| 237 childStyle.setOrder(1); |
| 238 } |
| 239 |
| 240 void LayoutFieldset::addChild(LayoutObject* newChild, LayoutObject* beforeChild) |
| 241 { |
| 242 if (!m_innerBlock) |
| 243 createInnerBlock(); |
| 244 |
| 245 if (isHTMLLegendElement(newChild->node())) { |
| 246 // Let legend block to be the 2nd for correct layout positioning. |
| 247 newChild->mutableStyle()->setOrder(2); |
| 248 LayoutFlexibleBox::addChild(newChild, m_innerBlock); |
| 249 } else { |
| 250 m_innerBlock->addChild(newChild, beforeChild); |
| 251 if (AXObjectCache* cache = document().existingAXObjectCache()) |
| 252 cache->childrenChanged(this); |
| 253 } |
| 254 } |
| 255 |
| 256 void LayoutFieldset::createInnerBlock() |
| 257 { |
| 258 if (m_innerBlock) { |
| 259 DCHECK(firstChild() == m_innerBlock); |
| 260 return; |
| 261 } |
| 262 m_innerBlock = createAnonymousBlock(style()->display()); |
| 263 LayoutFlexibleBox::addChild(m_innerBlock); |
| 264 } |
| 265 |
| 266 void LayoutFieldset::removeChild(LayoutObject* oldChild) |
| 267 { |
| 268 if (isHTMLLegendElement(oldChild->node())) { |
| 269 LayoutFlexibleBox::removeChild(oldChild); |
| 270 if (m_innerBlock) |
| 271 resetInnerBlockPadding(isHorizontalWritingMode(), m_innerBlock); |
| 272 } else if (oldChild == m_innerBlock) { |
| 273 LayoutFlexibleBox::removeChild(oldChild); |
| 274 m_innerBlock = nullptr; |
| 275 } else if (oldChild->parent() == this) { |
| 276 LayoutFlexibleBox::removeChild(oldChild); |
| 277 } else if (m_innerBlock) { |
| 278 m_innerBlock->removeChild(oldChild); |
| 279 } |
| 280 } |
| 281 |
| 156 } // namespace blink | 282 } // namespace blink |
| OLD | NEW |