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 Computer, 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 "HTMLNames.h"
30 #include "PaintInfo.h"
31
32 #if ENABLE(WML)
33 #include "WMLNames.h"
34 #endif
35
36 using std::min;
37 using std::max;
38
39 namespace WebCore {
40
41 using namespace HTMLNames;
42
RenderFieldset(Node * element)43 RenderFieldset::RenderFieldset(Node* element)
44 : RenderBlock(element)
45 {
46 }
47
computePreferredLogicalWidths()48 void RenderFieldset::computePreferredLogicalWidths()
49 {
50 RenderBlock::computePreferredLogicalWidths();
51 if (RenderBox* legend = findLegend()) {
52 int legendMinWidth = legend->minPreferredLogicalWidth();
53
54 Length legendMarginLeft = legend->style()->marginLeft();
55 Length legendMarginRight = legend->style()->marginLeft();
56
57 if (legendMarginLeft.isFixed())
58 legendMinWidth += legendMarginLeft.value();
59
60 if (legendMarginRight.isFixed())
61 legendMinWidth += legendMarginRight.value();
62
63 m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, legendMinWidth + borderAndPaddingWidth());
64 }
65 }
66
layoutSpecialExcludedChild(bool relayoutChildren)67 RenderObject* RenderFieldset::layoutSpecialExcludedChild(bool relayoutChildren)
68 {
69 RenderBox* legend = findLegend();
70 if (legend) {
71 if (relayoutChildren)
72 legend->setNeedsLayout(true);
73 legend->layoutIfNeeded();
74
75 int logicalLeft;
76 if (style()->isLeftToRightDirection()) {
77 switch (legend->style()->textAlign()) {
78 case CENTER:
79 logicalLeft = (logicalWidth() - logicalWidthForChild(legend)) / 2;
80 break;
81 case RIGHT:
82 logicalLeft = logicalWidth() - borderEnd() - paddingEnd() - logicalWidthForChild(legend);
83 break;
84 default:
85 logicalLeft = borderStart() + paddingStart() + marginStartForChild(legend);
86 break;
87 }
88 } else {
89 switch (legend->style()->textAlign()) {
90 case LEFT:
91 logicalLeft = borderStart() + paddingStart();
92 break;
93 case CENTER: {
94 // Make sure that the extra pixel goes to the end side in RTL (since it went to the end side
95 // in LTR).
96 int centeredWidth = logicalWidth() - logicalWidthForChild(legend);
97 logicalLeft = centeredWidth - centeredWidth / 2;
98 break;
99 }
100 default:
101 logicalLeft = logicalWidth() - borderStart() - paddingStart() - marginStartForChild(legend) - logicalWidthForChild(legend);
102 break;
103 }
104 }
105
106 setLogicalLeftForChild(legend, logicalLeft);
107
108 int b = borderBefore();
109 int h = logicalHeightForChild(legend);
110 setLogicalTopForChild(legend, max((b - h) / 2, 0));
111 setLogicalHeight(max(b, h) + paddingBefore());
112 }
113 return legend;
114 }
115
findLegend() const116 RenderBox* RenderFieldset::findLegend() const
117 {
118 for (RenderObject* legend = firstChild(); legend; legend = legend->nextSibling()) {
119 if (!legend->isFloatingOrPositioned() && legend->node() &&
120 (legend->node()->hasTagName(legendTag)
121 #if ENABLE(WML)
122 || legend->node()->hasTagName(WMLNames::insertedLegendTag)
123 #endif
124 )
125 )
126 return toRenderBox(legend);
127 }
128 return 0;
129 }
130
paintBoxDecorations(PaintInfo & paintInfo,int tx,int ty)131 void RenderFieldset::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
132 {
133 if (!paintInfo.shouldPaintWithinRoot(this))
134 return;
135
136 int w = width();
137 int h = height();
138 RenderBox* legend = findLegend();
139 if (!legend)
140 return RenderBlock::paintBoxDecorations(paintInfo, tx, ty);
141
142 // FIXME: We need to work with "rl" and "bt" block flow directions. In those
143 // cases the legend is embedded in the right and bottom borders respectively.
144 // https://bugs.webkit.org/show_bug.cgi?id=47236
145 if (style()->isHorizontalWritingMode()) {
146 int yOff = (legend->y() > 0) ? 0 : (legend->height() - borderTop()) / 2;
147 h -= yOff;
148 ty += yOff;
149 } else {
150 int xOff = (legend->x() > 0) ? 0 : (legend->width() - borderLeft()) / 2;
151 w -= xOff;
152 tx += xOff;
153 }
154
155 paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Normal);
156
157 paintFillLayers(paintInfo, style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), tx, ty, w, h);
158 paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Inset);
159
160 if (!style()->hasBorder())
161 return;
162
163 // Create a clipping region around the legend and paint the border as normal
164 GraphicsContext* graphicsContext = paintInfo.context;
165 graphicsContext->save();
166
167 // FIXME: We need to work with "rl" and "bt" block flow directions. In those
168 // cases the legend is embedded in the right and bottom borders respectively.
169 // https://bugs.webkit.org/show_bug.cgi?id=47236
170 if (style()->isHorizontalWritingMode()) {
171 int clipTop = ty;
172 int clipHeight = max(static_cast<int>(style()->borderTopWidth()), legend->height());
173 graphicsContext->clipOut(IntRect(tx + legend->x(), clipTop, legend->width(), clipHeight));
174 } else {
175 int clipLeft = tx;
176 int clipWidth = max(static_cast<int>(style()->borderLeftWidth()), legend->width());
177 graphicsContext->clipOut(IntRect(clipLeft, ty + legend->y(), clipWidth, legend->height()));
178 }
179
180 paintBorder(paintInfo.context, tx, ty, w, h, style(), true, true);
181
182 graphicsContext->restore();
183 }
184
paintMask(PaintInfo & paintInfo,int tx,int ty)185 void RenderFieldset::paintMask(PaintInfo& paintInfo, int tx, int ty)
186 {
187 if (style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
188 return;
189
190 int w = width();
191 int h = height();
192 RenderBox* legend = findLegend();
193 if (!legend)
194 return RenderBlock::paintMask(paintInfo, tx, ty);
195
196 // FIXME: We need to work with "rl" and "bt" block flow directions. In those
197 // cases the legend is embedded in the right and bottom borders respectively.
198 // https://bugs.webkit.org/show_bug.cgi?id=47236
199 if (style()->isHorizontalWritingMode()) {
200 int yOff = (legend->y() > 0) ? 0 : (legend->height() - borderTop()) / 2;
201 h -= yOff;
202 ty += yOff;
203 } else {
204 int xOff = (legend->x() > 0) ? 0 : (legend->width() - borderLeft()) / 2;
205 w -= xOff;
206 tx += xOff;
207 }
208
209 paintMaskImages(paintInfo, tx, ty, w, h);
210 }
211
212 } // namespace WebCore
213