Home | History | Annotate | Download | only in rendering
      1 /**
      2  * Copyright (C) 2005 Apple Computer, Inc.
      3  *
      4  * This library is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU Library General Public
      6  * License as published by the Free Software Foundation; either
      7  * version 2 of the License, or (at your option) any later version.
      8  *
      9  * This library is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  * Library General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU Library General Public License
     15  * along with this library; see the file COPYING.LIB.  If not, write to
     16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     17  * Boston, MA 02110-1301, USA.
     18  *
     19  */
     20 
     21 #include "config.h"
     22 #include "core/rendering/RenderButton.h"
     23 
     24 #include "HTMLNames.h"
     25 #include "core/dom/Document.h"
     26 
     27 namespace WebCore {
     28 
     29 using namespace HTMLNames;
     30 
     31 RenderButton::RenderButton(Element* element)
     32     : RenderFlexibleBox(element)
     33     , m_inner(0)
     34 {
     35 }
     36 
     37 RenderButton::~RenderButton()
     38 {
     39 }
     40 
     41 void RenderButton::addChild(RenderObject* newChild, RenderObject* beforeChild)
     42 {
     43     if (!m_inner) {
     44         // Create an anonymous block.
     45         ASSERT(!firstChild());
     46         m_inner = createAnonymousBlock(style()->display());
     47         setupInnerStyle(m_inner->style());
     48         RenderFlexibleBox::addChild(m_inner);
     49     }
     50 
     51     m_inner->addChild(newChild, beforeChild);
     52 }
     53 
     54 void RenderButton::removeChild(RenderObject* oldChild)
     55 {
     56     // m_inner should be the only child, but checking for direct children who
     57     // are not m_inner prevents security problems when that assumption is
     58     // violated.
     59     if (oldChild == m_inner || !m_inner || oldChild->parent() == this) {
     60         ASSERT(oldChild == m_inner || !m_inner);
     61         RenderFlexibleBox::removeChild(oldChild);
     62         m_inner = 0;
     63     } else
     64         m_inner->removeChild(oldChild);
     65 }
     66 
     67 void RenderButton::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
     68 {
     69     if (m_inner) {
     70         // RenderBlock::setStyle is going to apply a new style to the inner block, which
     71         // will have the initial flex value, 0. The current value is 1, because we set
     72         // it right below. Here we change it back to 0 to avoid getting a spurious layout hint
     73         // because of the difference. Same goes for the other properties.
     74         // FIXME: Make this hack unnecessary.
     75         m_inner->style()->setFlexGrow(newStyle->initialFlexGrow());
     76         m_inner->style()->setMarginTop(newStyle->initialMargin());
     77         m_inner->style()->setMarginBottom(newStyle->initialMargin());
     78     }
     79     RenderBlock::styleWillChange(diff, newStyle);
     80 }
     81 
     82 void RenderButton::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
     83 {
     84     RenderBlock::styleDidChange(diff, oldStyle);
     85 
     86     if (m_inner) // RenderBlock handled updating the anonymous block's style.
     87         setupInnerStyle(m_inner->style());
     88 }
     89 
     90 void RenderButton::setupInnerStyle(RenderStyle* innerStyle)
     91 {
     92     ASSERT(innerStyle->refCount() == 1);
     93     // RenderBlock::createAnonymousBlock creates a new RenderStyle, so this is
     94     // safe to modify.
     95     innerStyle->setFlexGrow(1.0f);
     96     // Use margin:auto instead of align-items:center to get safe centering, i.e.
     97     // when the content overflows, treat it the same as align-items: flex-start.
     98     innerStyle->setMarginTop(Length());
     99     innerStyle->setMarginBottom(Length());
    100     innerStyle->setFlexDirection(style()->flexDirection());
    101 }
    102 
    103 bool RenderButton::canHaveGeneratedChildren() const
    104 {
    105     // Input elements can't have generated children, but button elements can. We'll
    106     // write the code assuming any other button types that might emerge in the future
    107     // can also have children.
    108     return !node()->hasTagName(inputTag);
    109 }
    110 
    111 LayoutRect RenderButton::controlClipRect(const LayoutPoint& additionalOffset) const
    112 {
    113     // Clip to the padding box to at least give content the extra padding space.
    114     return LayoutRect(additionalOffset.x() + borderLeft(), additionalOffset.y() + borderTop(), width() - borderLeft() - borderRight(), height() - borderTop() - borderBottom());
    115 }
    116 
    117 int RenderButton::baselinePosition(FontBaseline baseline, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
    118 {
    119     ASSERT(linePositionMode == PositionOnContainingLine);
    120     // We want to call the RenderBlock version of firstLineBoxBaseline to
    121     // avoid RenderFlexibleBox synthesizing a baseline that we don't want.
    122     // We use this check as a proxy for "are there any line boxes in this button"
    123     if (!hasLineIfEmpty() && RenderBlock::firstLineBoxBaseline() == -1) {
    124         // To ensure that we have a consistent baseline when we have no children,
    125         // even when we have the anonymous RenderBlock child, we calculate the
    126         // baseline for the empty case manually here.
    127         if (direction == HorizontalLine)
    128             return marginTop() + borderTop() + paddingTop() + contentHeight();
    129 
    130         return marginRight() + borderRight() + paddingRight() + contentWidth();
    131     }
    132     return RenderFlexibleBox::baselinePosition(baseline, firstLine, direction, linePositionMode);
    133 }
    134 
    135 } // namespace WebCore
    136