Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
      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 "RenderSlider.h"
     23 
     24 #include "CSSPropertyNames.h"
     25 #include "CSSStyleSelector.h"
     26 #include "Document.h"
     27 #include "Event.h"
     28 #include "EventHandler.h"
     29 #include "EventNames.h"
     30 #include "Frame.h"
     31 #include "HTMLInputElement.h"
     32 #include "HTMLNames.h"
     33 #include "HTMLParserIdioms.h"
     34 #include "MediaControlElements.h"
     35 #include "MouseEvent.h"
     36 #include "Node.h"
     37 #include "RenderLayer.h"
     38 #include "RenderTheme.h"
     39 #include "RenderView.h"
     40 #include "ShadowElement.h"
     41 #include "SliderThumbElement.h"
     42 #include "StepRange.h"
     43 #include <wtf/MathExtras.h>
     44 
     45 using std::min;
     46 
     47 namespace WebCore {
     48 
     49 static const int defaultTrackLength = 129;
     50 
     51 // Returns a value between 0 and 1.
     52 static double sliderPosition(HTMLInputElement* element)
     53 {
     54     StepRange range(element);
     55     return range.proportionFromValue(range.valueFromElement(element));
     56 }
     57 
     58 RenderSlider::RenderSlider(HTMLInputElement* element)
     59     : RenderBlock(element)
     60 {
     61 }
     62 
     63 RenderSlider::~RenderSlider()
     64 {
     65 }
     66 
     67 int RenderSlider::baselinePosition(FontBaseline, bool /*firstLine*/, LineDirectionMode, LinePositionMode) const
     68 {
     69     // FIXME: Patch this function for writing-mode.
     70     return height() + marginTop();
     71 }
     72 
     73 void RenderSlider::computePreferredLogicalWidths()
     74 {
     75     m_minPreferredLogicalWidth = 0;
     76     m_maxPreferredLogicalWidth = 0;
     77 
     78     if (style()->width().isFixed() && style()->width().value() > 0)
     79         m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = computeContentBoxLogicalWidth(style()->width().value());
     80     else
     81         m_maxPreferredLogicalWidth = defaultTrackLength * style()->effectiveZoom();
     82 
     83     if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
     84         m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->minWidth().value()));
     85         m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->minWidth().value()));
     86     } else if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent()))
     87         m_minPreferredLogicalWidth = 0;
     88     else
     89         m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth;
     90 
     91     if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) {
     92         m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->maxWidth().value()));
     93         m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->maxWidth().value()));
     94     }
     95 
     96     int toAdd = borderAndPaddingWidth();
     97     m_minPreferredLogicalWidth += toAdd;
     98     m_maxPreferredLogicalWidth += toAdd;
     99 
    100     setPreferredLogicalWidthsDirty(false);
    101 }
    102 
    103 IntRect RenderSlider::thumbRect()
    104 {
    105     SliderThumbElement* thumbElement = shadowSliderThumb();
    106     if (!thumbElement)
    107         return IntRect();
    108 
    109     IntRect thumbRect;
    110     RenderBox* thumb = toRenderBox(thumbElement->renderer());
    111 
    112     thumbRect.setWidth(thumb->style()->width().calcMinValue(contentWidth()));
    113     thumbRect.setHeight(thumb->style()->height().calcMinValue(contentHeight()));
    114 
    115     double fraction = sliderPosition(static_cast<HTMLInputElement*>(node()));
    116     IntRect contentRect = contentBoxRect();
    117     if (style()->appearance() == SliderVerticalPart || style()->appearance() == MediaVolumeSliderPart) {
    118         thumbRect.setX(contentRect.x() + (contentRect.width() - thumbRect.width()) / 2);
    119         thumbRect.setY(contentRect.y() + static_cast<int>(nextafter((contentRect.height() - thumbRect.height()) + 1, 0) * (1 - fraction)));
    120     } else {
    121         thumbRect.setX(contentRect.x() + static_cast<int>(nextafter((contentRect.width() - thumbRect.width()) + 1, 0) * fraction));
    122         thumbRect.setY(contentRect.y() + (contentRect.height() - thumbRect.height()) / 2);
    123     }
    124 
    125     return thumbRect;
    126 }
    127 
    128 void RenderSlider::layout()
    129 {
    130     ASSERT(needsLayout());
    131 
    132     SliderThumbElement* thumbElement = shadowSliderThumb();
    133     RenderBox* thumb = thumbElement ? toRenderBox(thumbElement->renderer()) : 0;
    134 
    135     IntSize baseSize(borderAndPaddingWidth(), borderAndPaddingHeight());
    136 
    137     if (thumb) {
    138         // Allow the theme to set the size of the thumb.
    139         if (thumb->style()->hasAppearance()) {
    140             // FIXME: This should pass the style, not the renderer, to the theme.
    141             theme()->adjustSliderThumbSize(thumb);
    142         }
    143 
    144         baseSize.expand(thumb->style()->width().calcMinValue(0), thumb->style()->height().calcMinValue(0));
    145     }
    146 
    147     LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
    148 
    149     IntSize oldSize = size();
    150 
    151     setSize(baseSize);
    152     computeLogicalWidth();
    153     computeLogicalHeight();
    154     updateLayerTransform();
    155 
    156     if (thumb) {
    157         if (oldSize != size())
    158             thumb->setChildNeedsLayout(true, false);
    159 
    160         LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), style()->isFlippedBlocksWritingMode());
    161 
    162         IntRect oldThumbRect = thumb->frameRect();
    163 
    164         thumb->layoutIfNeeded();
    165 
    166         IntRect rect = thumbRect();
    167         thumb->setFrameRect(rect);
    168         if (thumb->checkForRepaintDuringLayout())
    169             thumb->repaintDuringLayoutIfMoved(oldThumbRect);
    170 
    171         statePusher.pop();
    172         addOverflowFromChild(thumb);
    173     }
    174 
    175     repainter.repaintAfterLayout();
    176 
    177     setNeedsLayout(false);
    178 }
    179 
    180 SliderThumbElement* RenderSlider::shadowSliderThumb() const
    181 {
    182     Node* shadow = static_cast<Element*>(node())->shadowRoot();
    183     return shadow ? toSliderThumbElement(shadow->firstChild()) : 0;
    184 }
    185 
    186 bool RenderSlider::inDragMode() const
    187 {
    188     SliderThumbElement* thumbElement = shadowSliderThumb();
    189     return thumbElement && thumbElement->inDragMode();
    190 }
    191 
    192 } // namespace WebCore
    193