Home | History | Annotate | Download | only in rendering
      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