|
1 /* |
|
2 * This file is part of the DOM implementation for KDE. |
|
3 * |
|
4 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
|
5 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
|
6 * (C) 2000 Dirk Mueller (mueller@kde.org) |
|
7 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. |
|
8 * |
|
9 * This library is free software; you can redistribute it and/or |
|
10 * modify it under the terms of the GNU Library General Public |
|
11 * License as published by the Free Software Foundation; either |
|
12 * version 2 of the License, or (at your option) any later version. |
|
13 * |
|
14 * This library is distributed in the hope that it will be useful, |
|
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
17 * Library General Public License for more details. |
|
18 * |
|
19 * You should have received a copy of the GNU Library General Public License |
|
20 * along with this library; see the file COPYING.LIB. If not, write to |
|
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
|
22 * Boston, MA 02110-1301, USA. |
|
23 * |
|
24 */ |
|
25 |
|
26 #include "config.h" |
|
27 #include "RenderFieldset.h" |
|
28 |
|
29 #include "HTMLGenericFormElement.h" |
|
30 #include "HTMLNames.h" |
|
31 |
|
32 using std::min; |
|
33 using std::max; |
|
34 |
|
35 namespace WebCore { |
|
36 |
|
37 using namespace HTMLNames; |
|
38 |
|
39 RenderFieldset::RenderFieldset(HTMLGenericFormElement* element) |
|
40 : RenderBlock(element) |
|
41 { |
|
42 } |
|
43 |
|
44 void RenderFieldset::calcPrefWidths() |
|
45 { |
|
46 RenderBlock::calcPrefWidths(); |
|
47 if (RenderObject* legend = findLegend()) { |
|
48 int legendMinWidth = legend->minPrefWidth(); |
|
49 |
|
50 Length legendMarginLeft = legend->style()->marginLeft(); |
|
51 Length legendMarginRight = legend->style()->marginLeft(); |
|
52 |
|
53 if (legendMarginLeft.isFixed()) |
|
54 legendMinWidth += legendMarginLeft.value(); |
|
55 |
|
56 if (legendMarginRight.isFixed()) |
|
57 legendMinWidth += legendMarginRight.value(); |
|
58 |
|
59 m_minPrefWidth = max(m_minPrefWidth, legendMinWidth + paddingLeft() + paddingRight() + borderLeft() + borderRight()); |
|
60 } |
|
61 } |
|
62 |
|
63 RenderObject* RenderFieldset::layoutLegend(bool relayoutChildren) |
|
64 { |
|
65 RenderObject* legend = findLegend(); |
|
66 if (legend) { |
|
67 if (relayoutChildren) |
|
68 legend->setNeedsLayout(true); |
|
69 legend->layoutIfNeeded(); |
|
70 |
|
71 int xPos; |
|
72 if (style()->direction() == RTL) { |
|
73 switch (legend->style()->textAlign()) { |
|
74 case LEFT: |
|
75 xPos = borderLeft() + paddingLeft(); |
|
76 break; |
|
77 case CENTER: |
|
78 xPos = (m_width - legend->width()) / 2; |
|
79 break; |
|
80 default: |
|
81 xPos = m_width - paddingRight() - borderRight() - legend->width() - legend->marginRight(); |
|
82 } |
|
83 } else { |
|
84 switch (legend->style()->textAlign()) { |
|
85 case RIGHT: |
|
86 xPos = m_width - paddingRight() - borderRight() - legend->width(); |
|
87 break; |
|
88 case CENTER: |
|
89 xPos = (m_width - legend->width()) / 2; |
|
90 break; |
|
91 default: |
|
92 xPos = borderLeft() + paddingLeft() + legend->marginLeft(); |
|
93 } |
|
94 } |
|
95 int b = borderTop(); |
|
96 int h = legend->height(); |
|
97 legend->setPos(xPos, max((b-h)/2, 0)); |
|
98 m_height = max(b,h) + paddingTop(); |
|
99 } |
|
100 return legend; |
|
101 } |
|
102 |
|
103 RenderObject* RenderFieldset::findLegend() const |
|
104 { |
|
105 for (RenderObject* legend = firstChild(); legend; legend = legend->nextSibling()) { |
|
106 if (!legend->isFloatingOrPositioned() && legend->element() && |
|
107 legend->element()->hasTagName(legendTag)) |
|
108 return legend; |
|
109 } |
|
110 return 0; |
|
111 } |
|
112 |
|
113 void RenderFieldset::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) |
|
114 { |
|
115 int w = width(); |
|
116 int h = height() + borderTopExtra() + borderBottomExtra(); |
|
117 RenderObject* legend = findLegend(); |
|
118 if (!legend) |
|
119 return RenderBlock::paintBoxDecorations(paintInfo, tx, ty); |
|
120 |
|
121 int yOff = (legend->yPos() > 0) ? 0 : (legend->height() - borderTop()) / 2; |
|
122 int legendBottom = ty + legend->yPos() + legend->height(); |
|
123 h -= yOff; |
|
124 ty += yOff - borderTopExtra(); |
|
125 |
|
126 int my = max(ty, paintInfo.rect.y()); |
|
127 int end = min(paintInfo.rect.bottom(), ty + h); |
|
128 int mh = end - my; |
|
129 |
|
130 paintBoxShadow(paintInfo.context, tx, ty, w, h, style()); |
|
131 |
|
132 paintBackground(paintInfo.context, style()->backgroundColor(), style()->backgroundLayers(), my, mh, tx, ty, w, h); |
|
133 |
|
134 if (style()->hasBorder()) |
|
135 paintBorderMinusLegend(paintInfo.context, tx, ty, w, h, style(), legend->xPos(), legend->width(), legendBottom); |
|
136 } |
|
137 |
|
138 void RenderFieldset::paintBorderMinusLegend(GraphicsContext* graphicsContext, int tx, int ty, int w, int h, |
|
139 const RenderStyle* style, int lx, int lw, int lb) |
|
140 { |
|
141 // FIXME: Implement border-radius |
|
142 const Color& tc = style->borderTopColor(); |
|
143 const Color& bc = style->borderBottomColor(); |
|
144 |
|
145 EBorderStyle ts = style->borderTopStyle(); |
|
146 EBorderStyle bs = style->borderBottomStyle(); |
|
147 EBorderStyle ls = style->borderLeftStyle(); |
|
148 EBorderStyle rs = style->borderRightStyle(); |
|
149 |
|
150 bool render_t = ts > BHIDDEN; |
|
151 bool render_l = ls > BHIDDEN; |
|
152 bool render_r = rs > BHIDDEN; |
|
153 bool render_b = bs > BHIDDEN; |
|
154 |
|
155 int borderLeftWidth = style->borderLeftWidth(); |
|
156 int borderRightWidth = style->borderRightWidth(); |
|
157 |
|
158 if (render_t) { |
|
159 if (lx >= borderLeftWidth) |
|
160 drawBorder(graphicsContext, tx, ty, tx + min(lx, w), ty + style->borderTopWidth(), BSTop, tc, style->color(), ts, |
|
161 (render_l && (ls == DOTTED || ls == DASHED || ls == DOUBLE) ? borderLeftWidth : 0), |
|
162 (lx >= w && render_r && (rs == DOTTED || rs == DASHED || rs == DOUBLE) ? borderRightWidth : 0)); |
|
163 if (lx + lw <= w - borderRightWidth) |
|
164 drawBorder(graphicsContext, tx + max(0, lx + lw), ty, tx + w, ty + style->borderTopWidth(), BSTop, tc, style->color(), ts, |
|
165 (lx + lw <= 0 && render_l && (ls == DOTTED || ls == DASHED || ls == DOUBLE) ? borderLeftWidth : 0), |
|
166 (render_r && (rs == DOTTED || rs == DASHED || rs == DOUBLE) ? borderRightWidth : 0)); |
|
167 } |
|
168 |
|
169 if (render_b) |
|
170 drawBorder(graphicsContext, tx, ty + h - style->borderBottomWidth(), tx + w, ty + h, BSBottom, bc, style->color(), bs, |
|
171 (render_l && (ls == DOTTED || ls == DASHED || ls == DOUBLE) ? style->borderLeftWidth() : 0), |
|
172 (render_r && (rs == DOTTED || rs == DASHED || rs == DOUBLE) ? style->borderRightWidth() : 0)); |
|
173 |
|
174 if (render_l) { |
|
175 const Color& lc = style->borderLeftColor(); |
|
176 int startY = ty; |
|
177 |
|
178 bool ignore_top = |
|
179 (tc == lc) && |
|
180 (ls >= OUTSET) && |
|
181 (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET); |
|
182 |
|
183 bool ignore_bottom = |
|
184 (bc == lc) && |
|
185 (ls >= OUTSET) && |
|
186 (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET); |
|
187 |
|
188 if (lx < borderLeftWidth && lx + lw > 0) { |
|
189 // The legend intersects the border. |
|
190 ignore_top = true; |
|
191 startY = lb; |
|
192 } |
|
193 |
|
194 drawBorder(graphicsContext, tx, startY, tx + borderLeftWidth, ty + h, BSLeft, lc, style->color(), ls, |
|
195 ignore_top ? 0 : style->borderTopWidth(), ignore_bottom ? 0 : style->borderBottomWidth()); |
|
196 } |
|
197 |
|
198 if (render_r) { |
|
199 const Color& rc = style->borderRightColor(); |
|
200 int startY = ty; |
|
201 |
|
202 bool ignore_top = |
|
203 (tc == rc) && |
|
204 (rs >= DOTTED || rs == INSET) && |
|
205 (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET); |
|
206 |
|
207 bool ignore_bottom = |
|
208 (bc == rc) && |
|
209 (rs >= DOTTED || rs == INSET) && |
|
210 (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET); |
|
211 |
|
212 if (lx < w && lx + lw > w - borderRightWidth) { |
|
213 // The legend intersects the border. |
|
214 ignore_top = true; |
|
215 startY = lb; |
|
216 } |
|
217 |
|
218 drawBorder(graphicsContext, tx + w - borderRightWidth, startY, tx + w, ty + h, BSRight, rc, style->color(), rs, |
|
219 ignore_top ? 0 : style->borderTopWidth(), ignore_bottom ? 0 : style->borderBottomWidth()); |
|
220 } |
|
221 } |
|
222 |
|
223 void RenderFieldset::setStyle(RenderStyle* newStyle) |
|
224 { |
|
225 RenderBlock::setStyle(newStyle); |
|
226 |
|
227 // WinIE renders fieldsets with display:inline like they're inline-blocks. For us, |
|
228 // an inline-block is just a block element with replaced set to true and inline set |
|
229 // to true. Ensure that if we ended up being inline that we set our replaced flag |
|
230 // so that we're treated like an inline-block. |
|
231 if (isInline()) |
|
232 setReplaced(true); |
|
233 } |
|
234 |
|
235 } // namespace WebCore |