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().toInt(); | |
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::updateAnonymousChildStyle(const LayoutObject& child, Comput
edStyle& childStyle) const |
| 221 { |
| 222 childStyle.setFlexShrink(1.0f); |
| 223 childStyle.setFlexGrow(1.0f); |
| 224 // min-width: 0; is needed for correct shrinking. |
| 225 childStyle.setMinWidth(Length(0, Fixed)); |
| 226 childStyle.setFlexDirection(style()->flexDirection()); |
| 227 childStyle.setJustifyContent(style()->justifyContent()); |
| 228 childStyle.setFlexWrap(style()->flexWrap()); |
| 229 childStyle.setAlignItems(style()->alignItems()); |
| 230 childStyle.setAlignContent(style()->alignContent()); |
| 231 // Let anonymous block to be the 1st for correct layout positioning. |
| 232 childStyle.setOrder(1); |
| 233 } |
| 234 |
| 235 void LayoutFieldset::addChild(LayoutObject* newChild, LayoutObject* beforeChild) |
| 236 { |
| 237 if (!m_innerBlock) |
| 238 createInnerBlock(); |
| 239 |
| 240 if (isHTMLLegendElement(newChild->node())) { |
| 241 // Let legend block to be the 2nd for correct layout positioning. |
| 242 newChild->mutableStyle()->setOrder(2); |
| 243 LayoutFlexibleBox::addChild(newChild, m_innerBlock); |
| 244 } else { |
| 245 if (beforeChild && isHTMLLegendElement(beforeChild->node())) { |
| 246 m_innerBlock->addChild(newChild); |
| 247 } else { |
| 248 m_innerBlock->addChild(newChild, beforeChild); |
| 249 } |
| 250 if (AXObjectCache* cache = document().existingAXObjectCache()) |
| 251 cache->childrenChanged(this); |
| 252 } |
| 253 } |
| 254 |
| 255 void LayoutFieldset::createInnerBlock() |
| 256 { |
| 257 if (m_innerBlock) { |
| 258 DCHECK(firstChild() == m_innerBlock); |
| 259 return; |
| 260 } |
| 261 m_innerBlock = createAnonymousBlock(style()->display()); |
| 262 LayoutFlexibleBox::addChild(m_innerBlock); |
| 263 } |
| 264 |
| 265 void LayoutFieldset::removeChild(LayoutObject* oldChild) |
| 266 { |
| 267 if (isHTMLLegendElement(oldChild->node())) { |
| 268 LayoutFlexibleBox::removeChild(oldChild); |
| 269 if (m_innerBlock) { |
| 270 resetInnerBlockPadding(isHorizontalWritingMode(), m_innerBlock); |
| 271 m_innerBlock->setNeedsLayout(LayoutInvalidationReason::FieldsetChang
ed, MarkOnlyThis); |
| 272 } |
| 273 setShouldDoFullPaintInvalidation(); |
| 274 } else if (oldChild == m_innerBlock) { |
| 275 LayoutFlexibleBox::removeChild(oldChild); |
| 276 m_innerBlock = nullptr; |
| 277 } else if (oldChild->parent() == this) { |
| 278 LayoutFlexibleBox::removeChild(oldChild); |
| 279 } else if (m_innerBlock) { |
| 280 m_innerBlock->removeChild(oldChild); |
| 281 } |
| 282 } |
| 283 |
156 } // namespace blink | 284 } // namespace blink |
OLD | NEW |