Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / rendering / RenderFieldset.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2000 Dirk Mueller (mueller@kde.org)
5  * Copyright (C) 2004, 2005, 2006 Apple Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
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
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  */
23
24 #include "config.h"
25 #include "RenderFieldset.h"
26
27 #include "CSSPropertyNames.h"
28 #include "GraphicsContext.h"
29 #include "HTMLFieldSetElement.h"
30 #include "HTMLNames.h"
31 #include "PaintInfo.h"
32
33 namespace WebCore {
34
35 using namespace HTMLNames;
36
37 RenderFieldset::RenderFieldset(HTMLFieldSetElement& element, Ref<RenderStyle>&& style)
38     : RenderBlockFlow(element, WTFMove(style))
39 {
40 }
41
42 void RenderFieldset::computePreferredLogicalWidths()
43 {
44     RenderBlockFlow::computePreferredLogicalWidths();
45     if (RenderBox* legend = findLegend()) {
46         int legendMinWidth = legend->minPreferredLogicalWidth();
47
48         Length legendMarginLeft = legend->style().marginLeft();
49         Length legendMarginRight = legend->style().marginLeft();
50
51         if (legendMarginLeft.isFixed())
52             legendMinWidth += legendMarginLeft.value();
53
54         if (legendMarginRight.isFixed())
55             legendMinWidth += legendMarginRight.value();
56
57         m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, legendMinWidth + horizontalBorderAndPaddingExtent());
58     }
59 }
60
61 RenderObject* RenderFieldset::layoutSpecialExcludedChild(bool relayoutChildren)
62 {
63     RenderBox* box = findLegend();
64     if (!box)
65         return nullptr;
66
67     RenderBox& legend = *box;
68     if (relayoutChildren)
69         legend.setNeedsLayout();
70     legend.layoutIfNeeded();
71
72     LayoutUnit logicalLeft;
73     if (style().isLeftToRightDirection()) {
74         switch (legend.style().textAlign()) {
75         case CENTER:
76             logicalLeft = (logicalWidth() - logicalWidthForChild(legend)) / 2;
77             break;
78         case RIGHT:
79             logicalLeft = logicalWidth() - borderEnd() - paddingEnd() - logicalWidthForChild(legend);
80             break;
81         default:
82             logicalLeft = borderStart() + paddingStart() + marginStartForChild(legend);
83             break;
84         }
85     } else {
86         switch (legend.style().textAlign()) {
87         case LEFT:
88             logicalLeft = borderStart() + paddingStart();
89             break;
90         case CENTER: {
91             // Make sure that the extra pixel goes to the end side in RTL (since it went to the end side
92             // in LTR).
93             LayoutUnit centeredWidth = logicalWidth() - logicalWidthForChild(legend);
94             logicalLeft = centeredWidth - centeredWidth / 2;
95             break;
96         }
97         default:
98             logicalLeft = logicalWidth() - borderStart() - paddingStart() - marginStartForChild(legend) - logicalWidthForChild(legend);
99             break;
100         }
101     }
102
103     setLogicalLeftForChild(legend, logicalLeft);
104
105     LayoutUnit fieldsetBorderBefore = borderBefore();
106     LayoutUnit legendLogicalHeight = logicalHeightForChild(legend);
107
108     LayoutUnit legendLogicalTop;
109     LayoutUnit collapsedLegendExtent;
110     // FIXME: We need to account for the legend's margin before too.
111     if (fieldsetBorderBefore > legendLogicalHeight) {
112         // The <legend> is smaller than the associated fieldset before border
113         // so the latter determines positioning of the <legend>. The sizing depends
114         // on the legend's margins as we want to still follow the author's cues.
115         // Firefox completely ignores the margins in this case which seems wrong.
116         legendLogicalTop = (fieldsetBorderBefore - legendLogicalHeight) / 2;
117         collapsedLegendExtent = std::max<LayoutUnit>(fieldsetBorderBefore, legendLogicalTop + legendLogicalHeight + marginAfterForChild(legend));
118     } else
119         collapsedLegendExtent = legendLogicalHeight + marginAfterForChild(legend);
120
121     setLogicalTopForChild(legend, legendLogicalTop);
122     setLogicalHeight(paddingBefore() + collapsedLegendExtent);
123
124     return &legend;
125 }
126
127 RenderBox* RenderFieldset::findLegend(FindLegendOption option) const
128 {
129     for (RenderObject* legend = firstChild(); legend; legend = legend->nextSibling()) {
130         if (option == IgnoreFloatingOrOutOfFlow && legend->isFloatingOrOutOfFlowPositioned())
131             continue;
132         
133         if (is<HTMLLegendElement>(legend->node()))
134             return downcast<RenderBox>(legend);
135     }
136     return nullptr;
137 }
138
139 void RenderFieldset::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
140 {
141     if (!paintInfo.shouldPaintWithinRoot(*this))
142         return;
143
144     LayoutRect paintRect(paintOffset, size());
145     RenderBox* legend = findLegend();
146     if (!legend)
147         return RenderBlockFlow::paintBoxDecorations(paintInfo, paintOffset);
148
149     // FIXME: We need to work with "rl" and "bt" block flow directions.  In those
150     // cases the legend is embedded in the right and bottom borders respectively.
151     // https://bugs.webkit.org/show_bug.cgi?id=47236
152     if (style().isHorizontalWritingMode()) {
153         LayoutUnit yOff = (legend->y() > 0) ? LayoutUnit() : (legend->height() - borderTop()) / 2;
154         paintRect.setHeight(paintRect.height() - yOff);
155         paintRect.setY(paintRect.y() + yOff);
156     } else {
157         LayoutUnit xOff = (legend->x() > 0) ? LayoutUnit() : (legend->width() - borderLeft()) / 2;
158         paintRect.setWidth(paintRect.width() - xOff);
159         paintRect.setX(paintRect.x() + xOff);
160     }
161
162     if (!boxShadowShouldBeAppliedToBackground(paintRect.location(), determineBackgroundBleedAvoidance(paintInfo.context())))
163         paintBoxShadow(paintInfo, paintRect, style(), Normal);
164     paintFillLayers(paintInfo, style().visitedDependentColor(CSSPropertyBackgroundColor), style().backgroundLayers(), paintRect);
165     paintBoxShadow(paintInfo, paintRect, style(), Inset);
166
167     if (!style().hasBorder())
168         return;
169     
170     // Create a clipping region around the legend and paint the border as normal
171     GraphicsContext& graphicsContext = paintInfo.context();
172     GraphicsContextStateSaver stateSaver(graphicsContext);
173
174     // FIXME: We need to work with "rl" and "bt" block flow directions.  In those
175     // cases the legend is embedded in the right and bottom borders respectively.
176     // https://bugs.webkit.org/show_bug.cgi?id=47236
177     LayoutRect clipRect;
178     if (style().isHorizontalWritingMode()) {
179         clipRect.setX(paintRect.x() + legend->x());
180         clipRect.setY(paintRect.y());
181         clipRect.setWidth(legend->width());
182         clipRect.setHeight(std::max<LayoutUnit>(style().borderTopWidth(), legend->height() - ((legend->height() - borderTop()) / 2)));
183     } else {
184         clipRect.setX(paintRect.x());
185         clipRect.setY(paintRect.y() + legend->y());
186         clipRect.setWidth(std::max<LayoutUnit>(style().borderLeftWidth(), legend->width()));
187         clipRect.setHeight(legend->height());
188     }
189     graphicsContext.clipOut(snapRectToDevicePixels(clipRect, document().deviceScaleFactor()));
190
191     paintBorder(paintInfo, paintRect, style());
192 }
193
194 void RenderFieldset::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
195 {
196     if (style().visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
197         return;
198
199     LayoutRect paintRect = LayoutRect(paintOffset, size());
200     RenderBox* legend = findLegend();
201     if (!legend)
202         return RenderBlockFlow::paintMask(paintInfo, paintOffset);
203
204     // FIXME: We need to work with "rl" and "bt" block flow directions.  In those
205     // cases the legend is embedded in the right and bottom borders respectively.
206     // https://bugs.webkit.org/show_bug.cgi?id=47236
207     if (style().isHorizontalWritingMode()) {
208         LayoutUnit yOff = (legend->y() > 0) ? LayoutUnit() : (legend->height() - borderTop()) / 2;
209         paintRect.expand(0, -yOff);
210         paintRect.move(0, yOff);
211     } else {
212         LayoutUnit xOff = (legend->x() > 0) ? LayoutUnit() : (legend->width() - borderLeft()) / 2;
213         paintRect.expand(-xOff, 0);
214         paintRect.move(xOff, 0);
215     }
216
217     paintMaskImages(paintInfo, paintRect);
218 }
219
220 } // namespace WebCore