1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2000 Dirk Mueller (mueller (at) 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 43 RenderFieldset::RenderFieldset(Node* element) 44 : RenderBlock(element) 45 { 46 } 47 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 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 116 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 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 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