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 "core/dom/Document.h"
     25 
     26 namespace WebCore {
     27 
     28 using namespace HTMLNames;
     29 
     30 RenderButton::RenderButton(Element* element)
     31     : RenderFlexibleBox(element)
     32     , m_inner(0)
     33 {
     34 }
     35 
     36 RenderButton::~RenderButton()
     37 {
     38 }
     39 
     40 void RenderButton::addChild(RenderObject* newChild, RenderObject* beforeChild)
     41 {
     42     if (!m_inner) {
     43         // Create an anonymous block.
     44         ASSERT(!firstChild());
     45         m_inner = createAnonymousBlock(style()->display());
     46         setupInnerStyle(m_inner->style());
     47         RenderFlexibleBox::addChild(m_inner);
     48     }
     49 
     50     m_inner->addChild(newChild, beforeChild);
     51 }
     52 
     53 void RenderButton::removeChild(RenderObject* oldChild)
     54 {
     55     // m_inner should be the only child, but checking for direct children who
     56     // are not m_inner prevents security problems when that assumption is
     57     // violated.
     58     if (oldChild == m_inner || !m_inner || oldChild->parent() == this) {
     59         ASSERT(oldChild == m_inner || !m_inner);
     60         RenderFlexibleBox::removeChild(oldChild);
     61         m_inner = 0;
     62     } else
     63         m_inner->removeChild(oldChild);
     64 }
     65 
     66 void RenderButton::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
     67 {
     68     if (m_inner) {
     69         // RenderBlock::setStyle is going to apply a new style to the inner block, which
     70         // will have the initial flex value, 0. The current value is 1, because we set
     71         // it right below. Here we change it back to 0 to avoid getting a spurious layout hint
     72         // because of the difference. Same goes for the other properties.
     73         // FIXME: Make this hack unnecessary.
     74         m_inner->style()->setFlexGrow(newStyle.initialFlexGrow());
     75         m_inner->style()->setMarginTop(newStyle.initialMargin());
     76         m_inner->style()->setMarginBottom(newStyle.initialMargin());
     77     }
     78     RenderBlock::styleWillChange(diff, newStyle);
     79 }
     80 
     81 void RenderButton::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
     82 {
     83     RenderBlock::styleDidChange(diff, oldStyle);
     84 
     85     if (m_inner) // RenderBlock handled updating the anonymous block's style.
     86         setupInnerStyle(m_inner->style());
     87 }
     88 
     89 void RenderButton::setupInnerStyle(RenderStyle* innerStyle)
     90 {
     91     ASSERT(innerStyle->refCount() == 1);
     92     // RenderBlock::createAnonymousBlock creates a new RenderStyle, so this is
     93     // safe to modify.
     94     innerStyle->setFlexGrow(1.0f);
     95     // Use margin:auto instead of align-items:center to get safe centering, i.e.
     96     // when the content overflows, treat it the same as align-items: flex-start.
     97     innerStyle->setMarginTop(Length());
     98     innerStyle->setMarginBottom(Length());
     99     innerStyle->setFlexDirection(style()->flexDirection());
    100     innerStyle->setJustifyContent(style()->justifyContent());
    101     innerStyle->setFlexWrap(style()->flexWrap());
    102     innerStyle->setAlignItems(style()->alignItems());
    103     innerStyle->setAlignContent(style()->alignContent());
    104 }
    105 
    106 bool RenderButton::canHaveGeneratedChildren() const
    107 {
    108     // Input elements can't have generated children, but button elements can. We'll
    109     // write the code assuming any other button types that might emerge in the future
    110     // can also have children.
    111     return !isHTMLInputElement(*node());
    112 }
    113 
    114 LayoutRect RenderButton::controlClipRect(const LayoutPoint& additionalOffset) const
    115 {
    116     // Clip to the padding box to at least give content the extra padding space.
    117     return LayoutRect(additionalOffset.x() + borderLeft(), additionalOffset.y() + borderTop(), width() - borderLeft() - borderRight(), height() - borderTop() - borderBottom());
    118 }
    119 
    120 int RenderButton::baselinePosition(FontBaseline baseline, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
    121 {
    122     ASSERT(linePositionMode == PositionOnContainingLine);
    123     // We want to call the RenderBlock version of firstLineBoxBaseline to
    124     // avoid RenderFlexibleBox synthesizing a baseline that we don't want.
    125     // We use this check as a proxy for "are there any line boxes in this button"
    126     if (!hasLineIfEmpty() && RenderBlock::firstLineBoxBaseline() == -1) {
    127         // To ensure that we have a consistent baseline when we have no children,
    128         // even when we have the anonymous RenderBlock child, we calculate the
    129         // baseline for the empty case manually here.
    130         if (direction == HorizontalLine)
    131             return marginTop() + borderTop() + paddingTop() + contentHeight();
    132 
    133         return marginRight() + borderRight() + paddingRight() + contentWidth();
    134     }
    135     return RenderFlexibleBox::baselinePosition(baseline, firstLine, direction, linePositionMode);
    136 }
    137 
    138 } // namespace WebCore
    139