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