~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/3rdparty/webkit/WebCore/rendering/RenderSlider.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi
  • Date: 2009-11-02 18:30:08 UTC
  • mfrom: (1.2.2 upstream)
  • mto: (15.2.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 88.
  • Revision ID: james.westby@ubuntu.com-20091102183008-b6a4gcs128mvfb3m
Tags: upstream-4.6.0~beta1
ImportĀ upstreamĀ versionĀ 4.6.0~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/**
2
 
 *
3
 
 * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc.
 
1
/*
 
2
 * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
4
3
 *
5
4
 * This library is free software; you can redistribute it and/or
6
5
 * modify it under the terms of the GNU Library General Public
31
30
#include "HTMLInputElement.h"
32
31
#include "HTMLDivElement.h"
33
32
#include "HTMLNames.h"
 
33
#include "MediaControlElements.h"
34
34
#include "MouseEvent.h"
 
35
#include "RenderLayer.h"
35
36
#include "RenderTheme.h"
 
37
#include "RenderView.h"
36
38
#include <wtf/MathExtras.h>
37
39
 
38
40
using std::min;
41
43
 
42
44
using namespace HTMLNames;
43
45
 
44
 
const int defaultTrackLength = 129;
45
 
 
46
 
class HTMLSliderThumbElement : public HTMLDivElement {
 
46
static const int defaultTrackLength = 129;
 
47
 
 
48
// FIXME: The SliderRange class and functions are entirely based on the DOM,
 
49
// and could be put with HTMLInputElement (possibly with a new name) instead of here.
 
50
struct SliderRange {
 
51
    bool isIntegral;
 
52
    double minimum;
 
53
    double maximum;
 
54
 
 
55
    explicit SliderRange(HTMLInputElement*);
 
56
    double clampValue(double value);
 
57
 
 
58
    // Map value into 0-1 range
 
59
    double proportionFromValue(double value)
 
60
    {
 
61
        if (minimum == maximum)
 
62
            return 0;
 
63
 
 
64
        return (value - minimum) / (maximum - minimum);
 
65
    }
 
66
    
 
67
    // Map from 0-1 range to value
 
68
    double valueFromProportion(double proportion)
 
69
    {
 
70
        return minimum + proportion * (maximum - minimum);
 
71
    }
 
72
    
 
73
    double valueFromElement(HTMLInputElement*, bool* wasClamped = 0);
 
74
};
 
75
 
 
76
SliderRange::SliderRange(HTMLInputElement* element)
 
77
{
 
78
    // FIXME: What's the right way to handle an integral range with non-integral minimum and maximum?
 
79
    // Currently values are guaranteed to be integral but could be outside the range in that case.
 
80
 
 
81
    isIntegral = !equalIgnoringCase(element->getAttribute(precisionAttr), "float");
 
82
 
 
83
    // FIXME: This treats maximum strings that can't be parsed as 0, but perhaps 100 would be more appropriate.
 
84
    const AtomicString& maxString = element->getAttribute(maxAttr);
 
85
    maximum = maxString.isNull() ? 100.0 : maxString.toDouble();
 
86
 
 
87
    // If the maximum is smaller, use it as the minimum.
 
88
    minimum = min(element->getAttribute(minAttr).toDouble(), maximum);
 
89
}
 
90
 
 
91
double SliderRange::clampValue(double value)
 
92
{
 
93
    double clampedValue = max(minimum, min(value, maximum));
 
94
    return isIntegral ? round(clampedValue) : clampedValue;
 
95
}
 
96
 
 
97
double SliderRange::valueFromElement(HTMLInputElement* element, bool* wasClamped)
 
98
{
 
99
    String valueString = element->value();
 
100
    double oldValue = valueString.isNull() ? (minimum + maximum) / 2 : valueString.toDouble();
 
101
    double newValue = clampValue(oldValue);
 
102
 
 
103
    if (wasClamped)
 
104
        *wasClamped = valueString.isNull() || newValue != oldValue;
 
105
 
 
106
    return newValue;
 
107
}
 
108
 
 
109
// Returns a value between 0 and 1.
 
110
// As with SliderRange, this could be on HTMLInputElement instead of here.
 
111
static double sliderPosition(HTMLInputElement* element)
 
112
{
 
113
    SliderRange range(element);
 
114
    return range.proportionFromValue(range.valueFromElement(element));
 
115
}
 
116
 
 
117
class SliderThumbElement : public HTMLDivElement {
47
118
public:
48
 
    HTMLSliderThumbElement(Document*, Node* shadowParent = 0);
49
 
        
 
119
    SliderThumbElement(Document*, Node* shadowParent);
 
120
    
 
121
    bool inDragMode() const { return m_inDragMode; }
 
122
 
50
123
    virtual void defaultEventHandler(Event*);
 
124
    virtual void detach();
 
125
 
 
126
private:        
51
127
    virtual bool isShadowNode() const { return true; }
52
128
    virtual Node* shadowParentNode() { return m_shadowParent; }
53
 
    
54
 
    bool inDragMode() const { return m_inDragMode; }
55
 
private:
 
129
 
 
130
    FloatPoint m_offsetToThumb;
56
131
    Node* m_shadowParent;
57
 
    FloatPoint m_initialClickPoint;       // initial click point in RenderSlider-local coordinates
58
 
    int m_initialPosition;
59
132
    bool m_inDragMode;
60
133
};
61
134
 
62
 
HTMLSliderThumbElement::HTMLSliderThumbElement(Document* doc, Node* shadowParent)
63
 
    : HTMLDivElement(divTag, doc)
 
135
SliderThumbElement::SliderThumbElement(Document* document, Node* shadowParent)
 
136
    : HTMLDivElement(divTag, document)
64
137
    , m_shadowParent(shadowParent)
65
 
    , m_initialClickPoint(IntPoint())
66
 
    , m_initialPosition(0)
67
138
    , m_inDragMode(false)
68
139
{
69
140
}
70
141
 
71
 
void HTMLSliderThumbElement::defaultEventHandler(Event* event)
 
142
void SliderThumbElement::defaultEventHandler(Event* event)
72
143
{
 
144
    if (!event->isMouseEvent()) {
 
145
        HTMLDivElement::defaultEventHandler(event);
 
146
        return;
 
147
    }
 
148
 
 
149
    MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
 
150
    bool isLeftButton = mouseEvent->button() == LeftButton;
73
151
    const AtomicString& eventType = event->type();
74
 
    if (eventType == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
75
 
        MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
76
 
        RenderSlider* slider;
77
 
        if (document()->frame() && renderer() && renderer()->parent() &&
78
 
                (slider = static_cast<RenderSlider*>(renderer()->parent())) &&
79
 
                slider->mouseEventIsInThumb(mouseEvent)) {
80
 
            // Cache the initial point where the mouse down occurred, in slider coordinates
81
 
            m_initialClickPoint = slider->absoluteToLocal(FloatPoint(mouseEvent->pageX(), mouseEvent->pageY()), false, true);
82
 
            // Cache the initial position of the thumb.
83
 
            m_initialPosition = slider->currentPosition();
84
 
            m_inDragMode = true;
85
 
            
86
 
            document()->frame()->eventHandler()->setCapturingMouseEventsNode(m_shadowParent);
87
 
            
88
 
            event->setDefaultHandled();
89
 
            return;
 
152
 
 
153
    if (eventType == eventNames().mousedownEvent && isLeftButton) {
 
154
        if (document()->frame() && renderer()) {
 
155
            RenderSlider* slider = toRenderSlider(renderer()->parent());
 
156
            if (slider) {
 
157
                if (slider->mouseEventIsInThumb(mouseEvent)) {
 
158
                    // We selected the thumb, we want the cursor to always stay at
 
159
                    // the same position relative to the thumb.
 
160
                    m_offsetToThumb = slider->mouseEventOffsetToThumb(mouseEvent);
 
161
                } else {
 
162
                    // We are outside the thumb, move the thumb to the point were
 
163
                    // we clicked. We'll be exactly at the center of the thumb.
 
164
                    m_offsetToThumb.setX(0);
 
165
                    m_offsetToThumb.setY(0);
 
166
                }
 
167
 
 
168
                m_inDragMode = true;
 
169
                document()->frame()->eventHandler()->setCapturingMouseEventsNode(m_shadowParent);
 
170
                event->setDefaultHandled();
 
171
                return;
 
172
            }
90
173
        }
91
 
    } else if (eventType == eventNames().mouseupEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
 
174
    } else if (eventType == eventNames().mouseupEvent && isLeftButton) {
92
175
        if (m_inDragMode) {
93
176
            if (Frame* frame = document()->frame())
94
177
                frame->eventHandler()->setCapturingMouseEventsNode(0);      
96
179
            event->setDefaultHandled();
97
180
            return;
98
181
        }
99
 
    } else if (eventType == eventNames().mousemoveEvent && event->isMouseEvent()) {
 
182
    } else if (eventType == eventNames().mousemoveEvent) {
100
183
        if (m_inDragMode && renderer() && renderer()->parent()) {
101
 
            // Move the slider
102
 
            MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
103
 
            RenderSlider* slider = static_cast<RenderSlider*>(renderer()->parent());
104
 
            FloatPoint curPoint = slider->absoluteToLocal(FloatPoint(mouseEvent->pageX(), mouseEvent->pageY()), false, true);
105
 
            int newPosition = slider->positionForOffset(
106
 
                IntPoint(m_initialPosition + curPoint.x() - m_initialClickPoint.x()
107
 
                        + (renderer()->width() / 2), 
108
 
                    m_initialPosition + curPoint.y() - m_initialClickPoint.y()
109
 
                        + (renderer()->height() / 2)));
110
 
            if (slider->currentPosition() != newPosition) {
111
 
                slider->setCurrentPosition(newPosition);
112
 
                slider->valueChanged();
 
184
            RenderSlider* slider = toRenderSlider(renderer()->parent());
 
185
            if (slider) {
 
186
                FloatPoint curPoint = slider->absoluteToLocal(mouseEvent->absoluteLocation(), false, true);
 
187
                IntPoint eventOffset(curPoint.x() + m_offsetToThumb.x(), curPoint.y() + m_offsetToThumb.y());
 
188
                slider->setValueForPosition(slider->positionForOffset(eventOffset));
 
189
                event->setDefaultHandled();
 
190
                return;
113
191
            }
114
 
            event->setDefaultHandled();
115
 
            return;
116
192
        }
117
193
    }
118
194
 
119
195
    HTMLDivElement::defaultEventHandler(event);
120
196
}
121
197
 
 
198
void SliderThumbElement::detach()
 
199
{
 
200
    if (m_inDragMode) {
 
201
        if (Frame* frame = document()->frame())
 
202
            frame->eventHandler()->setCapturingMouseEventsNode(0);      
 
203
    }
 
204
    HTMLDivElement::detach();
 
205
}
 
206
 
122
207
RenderSlider::RenderSlider(HTMLInputElement* element)
123
208
    : RenderBlock(element)
124
 
    , m_thumb(0)
125
209
{
126
210
}
127
211
 
166
250
    setPrefWidthsDirty(false); 
167
251
}
168
252
 
169
 
void RenderSlider::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
 
253
void RenderSlider::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
170
254
{
171
255
    RenderBlock::styleDidChange(diff, oldStyle);
172
 
    
 
256
 
173
257
    if (m_thumb)
174
 
        m_thumb->renderer()->setStyle(createThumbStyle(style(), m_thumb->renderer()->style()));
175
 
        
 
258
        m_thumb->renderer()->setStyle(createThumbStyle(style()));
 
259
 
176
260
    setReplaced(isInline());
177
261
}
178
262
 
179
 
PassRefPtr<RenderStyle> RenderSlider::createThumbStyle(const RenderStyle* parentStyle, const RenderStyle* oldStyle)
 
263
PassRefPtr<RenderStyle> RenderSlider::createThumbStyle(const RenderStyle* parentStyle)
180
264
{
181
265
    RefPtr<RenderStyle> style;
182
 
    RenderStyle* pseudoStyle = getCachedPseudoStyle(RenderStyle::SLIDER_THUMB);
 
266
    RenderStyle* pseudoStyle = getCachedPseudoStyle(SLIDER_THUMB);
183
267
    if (pseudoStyle)
184
268
        // We may be sharing style with another slider, but we must not share the thumb style.
185
269
        style = RenderStyle::clone(pseudoStyle);
190
274
        style->inheritFrom(parentStyle);
191
275
 
192
276
    style->setDisplay(BLOCK);
193
 
    style->setPosition(RelativePosition);
194
 
    if (oldStyle) {
195
 
        style->setLeft(oldStyle->left());
196
 
        style->setTop(oldStyle->top());
197
 
    }
198
277
 
199
278
    if (parentStyle->appearance() == SliderVerticalPart)
200
 
       style->setAppearance(SliderThumbVerticalPart);
 
279
        style->setAppearance(SliderThumbVerticalPart);
201
280
    else if (parentStyle->appearance() == SliderHorizontalPart)
202
 
       style->setAppearance(SliderThumbHorizontalPart);
 
281
        style->setAppearance(SliderThumbHorizontalPart);
203
282
    else if (parentStyle->appearance() == MediaSliderPart)
204
283
        style->setAppearance(MediaSliderThumbPart);
 
284
    else if (parentStyle->appearance() == MediaVolumeSliderPart)
 
285
        style->setAppearance(MediaVolumeSliderThumbPart);
205
286
 
206
287
    return style.release();
207
288
}
208
289
 
 
290
IntRect RenderSlider::thumbRect()
 
291
{
 
292
    if (!m_thumb)
 
293
        return IntRect();
 
294
 
 
295
    IntRect thumbRect;
 
296
    RenderBox* thumb = toRenderBox(m_thumb->renderer());
 
297
 
 
298
    thumbRect.setWidth(thumb->style()->width().calcMinValue(contentWidth()));
 
299
    thumbRect.setHeight(thumb->style()->height().calcMinValue(contentHeight()));
 
300
 
 
301
    double fraction = sliderPosition(static_cast<HTMLInputElement*>(node()));
 
302
    IntRect contentRect = contentBoxRect();
 
303
    if (style()->appearance() == SliderVerticalPart || style()->appearance() == MediaVolumeSliderPart) {
 
304
        thumbRect.setX(contentRect.x() + (contentRect.width() - thumbRect.width()) / 2);
 
305
        thumbRect.setY(contentRect.y() + static_cast<int>(nextafter((contentRect.height() - thumbRect.height()) + 1, 0) * (1 - fraction)));
 
306
    } else {
 
307
        thumbRect.setX(contentRect.x() + static_cast<int>(nextafter((contentRect.width() - thumbRect.width()) + 1, 0) * fraction));
 
308
        thumbRect.setY(contentRect.y() + (contentRect.height() - thumbRect.height()) / 2);
 
309
    }
 
310
 
 
311
    return thumbRect;
 
312
}
 
313
 
209
314
void RenderSlider::layout()
210
 
{    
211
 
    bool relayoutChildren = false;
212
 
    
213
 
    if (m_thumb && m_thumb->renderer()) {
214
 
            
215
 
        int oldWidth = m_width;
216
 
        calcWidth();
217
 
        int oldHeight = m_height;
218
 
        calcHeight();
219
 
        
220
 
        if (oldWidth != m_width || oldHeight != m_height)
221
 
            relayoutChildren = true;  
222
 
 
223
 
        // Allow the theme to set the size of the thumb
224
 
        if (m_thumb->renderer()->style()->hasAppearance())
225
 
            theme()->adjustSliderThumbSize(m_thumb->renderer());
226
 
 
227
 
        if (style()->appearance() == SliderVerticalPart) {
228
 
            // FIXME: Handle percentage widths correctly. See http://bugs.webkit.org/show_bug.cgi?id=12104
229
 
            m_thumb->renderer()->style()->setLeft(Length(contentWidth() / 2 - m_thumb->renderer()->style()->width().value() / 2, Fixed));
230
 
        } else {
231
 
            // FIXME: Handle percentage heights correctly. See http://bugs.webkit.org/show_bug.cgi?id=12104
232
 
            m_thumb->renderer()->style()->setTop(Length(contentHeight() / 2 - m_thumb->renderer()->style()->height().value() / 2, Fixed));
 
315
{
 
316
    ASSERT(needsLayout());
 
317
 
 
318
    RenderBox* thumb = m_thumb ? toRenderBox(m_thumb->renderer()) : 0;
 
319
 
 
320
    IntSize baseSize(borderLeft() + paddingLeft() + paddingRight() + borderRight(),
 
321
        borderTop() + paddingTop() + paddingBottom() + borderBottom());
 
322
 
 
323
    if (thumb) {
 
324
        // Allow the theme to set the size of the thumb.
 
325
        if (thumb->style()->hasAppearance()) {
 
326
            // FIXME: This should pass the style, not the renderer, to the theme.
 
327
            theme()->adjustSliderThumbSize(thumb);
233
328
        }
234
329
 
235
 
        if (relayoutChildren)
236
 
            setPositionFromValue(true);
237
 
    }
238
 
 
239
 
    RenderBlock::layoutBlock(relayoutChildren);
 
330
        baseSize.expand(thumb->style()->width().calcMinValue(0), thumb->style()->height().calcMinValue(0));
 
331
    }
 
332
 
 
333
    LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
 
334
 
 
335
    IntSize oldSize = size();
 
336
 
 
337
    setSize(baseSize);
 
338
    calcWidth();
 
339
    calcHeight();
 
340
 
 
341
    if (thumb) {
 
342
        if (oldSize != size())
 
343
            thumb->setChildNeedsLayout(true, false);
 
344
 
 
345
        LayoutStateMaintainer statePusher(view(), this, size());
 
346
 
 
347
        IntRect oldThumbRect = thumb->frameRect();
 
348
 
 
349
        thumb->layoutIfNeeded();
 
350
 
 
351
        IntRect rect = thumbRect();
 
352
        thumb->setFrameRect(rect);
 
353
        if (thumb->checkForRepaintDuringLayout())
 
354
            thumb->repaintDuringLayoutIfMoved(oldThumbRect);
 
355
 
 
356
        statePusher.pop();
 
357
    }
 
358
 
 
359
    addOverflowFromChild(thumb);
 
360
 
 
361
    repainter.repaintAfterLayout();    
 
362
 
 
363
    setNeedsLayout(false);
240
364
}
241
365
 
242
366
void RenderSlider::updateFromElement()
243
367
{
 
368
    HTMLInputElement* element = static_cast<HTMLInputElement*>(node());
 
369
 
 
370
    // Send the value back to the element if the range changes it.
 
371
    SliderRange range(element);
 
372
    bool clamped;
 
373
    double value = range.valueFromElement(element, &clamped);
 
374
    if (clamped)
 
375
        element->setValueFromRenderer(String::number(value));
 
376
 
 
377
    // Layout will take care of the thumb's size and position.
244
378
    if (!m_thumb) {
245
 
        m_thumb = new HTMLSliderThumbElement(document(), node());
 
379
        m_thumb = new SliderThumbElement(document(), node());
246
380
        RefPtr<RenderStyle> thumbStyle = createThumbStyle(style());
247
381
        m_thumb->setRenderer(m_thumb->createRenderer(renderArena(), thumbStyle.get()));
248
382
        m_thumb->renderer()->setStyle(thumbStyle.release());
250
384
        m_thumb->setInDocument(true);
251
385
        addChild(m_thumb->renderer());
252
386
    }
253
 
    setPositionFromValue();
254
 
    setNeedsLayout(true, false);
 
387
    setNeedsLayout(true);
255
388
}
256
389
 
257
390
bool RenderSlider::mouseEventIsInThumb(MouseEvent* evt)
258
391
{
259
392
    if (!m_thumb || !m_thumb->renderer())
260
393
        return false;
261
 
 
262
 
    FloatPoint localPoint = m_thumb->renderer()->absoluteToLocal(FloatPoint(evt->pageX(), evt->pageY()), false, true);
263
 
    IntRect thumbBounds = m_thumb->renderer()->borderBox();
 
394
 
 
395
#if ENABLE(VIDEO)
 
396
    if (style()->appearance() == MediaSliderPart || style()->appearance() == MediaVolumeSliderPart) {
 
397
        MediaControlInputElement *sliderThumb = static_cast<MediaControlInputElement*>(m_thumb->renderer()->node());
 
398
        return sliderThumb->hitTest(evt->absoluteLocation());
 
399
    }
 
400
#endif
 
401
 
 
402
    FloatPoint localPoint = m_thumb->renderBox()->absoluteToLocal(evt->absoluteLocation(), false, true);
 
403
    IntRect thumbBounds = m_thumb->renderBox()->borderBoxRect();
264
404
    return thumbBounds.contains(roundedIntPoint(localPoint));
265
405
}
266
406
 
 
407
FloatPoint RenderSlider::mouseEventOffsetToThumb(MouseEvent* evt)
 
408
{
 
409
    ASSERT(m_thumb && m_thumb->renderer());
 
410
    FloatPoint localPoint = m_thumb->renderBox()->absoluteToLocal(evt->absoluteLocation(), false, true);
 
411
    IntRect thumbBounds = m_thumb->renderBox()->borderBoxRect();
 
412
    FloatPoint offset;
 
413
    offset.setX(thumbBounds.x() + thumbBounds.width() / 2 - localPoint.x());
 
414
    offset.setY(thumbBounds.y() + thumbBounds.height() / 2 - localPoint.y());
 
415
    return offset;
 
416
}
 
417
 
267
418
void RenderSlider::setValueForPosition(int position)
268
419
{
269
420
    if (!m_thumb || !m_thumb->renderer())
270
421
        return;
271
 
    
272
 
    const AtomicString& minStr = static_cast<HTMLInputElement*>(node())->getAttribute(minAttr);
273
 
    const AtomicString& maxStr = static_cast<HTMLInputElement*>(node())->getAttribute(maxAttr);
274
 
    const AtomicString& precision = static_cast<HTMLInputElement*>(node())->getAttribute(precisionAttr);
275
 
    
276
 
    double minVal = minStr.isNull() ? 0.0 : minStr.toDouble();
277
 
    double maxVal = maxStr.isNull() ? 100.0 : maxStr.toDouble();
278
 
    minVal = min(minVal, maxVal); // Make sure the range is sane.
279
 
    
280
 
    // Calculate the new value based on the position
281
 
    double factor = (double)position / (double)trackSize();
282
 
    if (style()->appearance() == SliderVerticalPart)
283
 
        factor = 1.0 - factor;
284
 
    double val = minVal + factor * (maxVal - minVal);
285
 
            
286
 
    val = max(minVal, min(val, maxVal)); // Make sure val is within min/max.
287
 
 
288
 
    // Force integer value if not float.
289
 
    if (!equalIgnoringCase(precision, "float"))
290
 
        val = lround(val);
291
 
 
292
 
    static_cast<HTMLInputElement*>(node())->setValueFromRenderer(String::number(val));
293
 
    
 
422
 
 
423
    HTMLInputElement* element = static_cast<HTMLInputElement*>(node());
 
424
 
 
425
    // Calculate the new value based on the position, and send it to the element.
 
426
    SliderRange range(element);
 
427
    double fraction = static_cast<double>(position) / trackSize();
 
428
    if (style()->appearance() == SliderVerticalPart || style()->appearance() == MediaVolumeSliderPart)
 
429
        fraction = 1 - fraction;
 
430
    double value = range.clampValue(range.valueFromProportion(fraction));
 
431
    element->setValueFromRenderer(String::number(value));
 
432
 
 
433
    // Also update the position if appropriate.
294
434
    if (position != currentPosition()) {
295
 
        setCurrentPosition(position);
296
 
        static_cast<HTMLInputElement*>(node())->onChange();
 
435
        setNeedsLayout(true);
 
436
 
 
437
        // FIXME: It seems like this could send extra change events if the same value is set
 
438
        // multiple times with no layout in between.
 
439
        element->dispatchFormControlChangeEvent();
297
440
    }
298
441
}
299
442
 
300
 
double RenderSlider::setPositionFromValue(bool inLayout)
301
 
{
302
 
    if (!m_thumb || !m_thumb->renderer())
303
 
        return 0;
304
 
    
305
 
    if (!inLayout)
306
 
        document()->updateLayout();
307
 
        
308
 
    String value = static_cast<HTMLInputElement*>(node())->value();
309
 
    const AtomicString& minStr = static_cast<HTMLInputElement*>(node())->getAttribute(minAttr);
310
 
    const AtomicString& maxStr = static_cast<HTMLInputElement*>(node())->getAttribute(maxAttr);
311
 
    const AtomicString& precision = static_cast<HTMLInputElement*>(node())->getAttribute(precisionAttr);
312
 
    
313
 
    double minVal = minStr.isNull() ? 0.0 : minStr.toDouble();
314
 
    double maxVal = maxStr.isNull() ? 100.0 : maxStr.toDouble();
315
 
    minVal = min(minVal, maxVal); // Make sure the range is sane.
316
 
    
317
 
    double oldVal = value.isNull() ? (maxVal + minVal)/2.0 : value.toDouble();
318
 
    double val = max(minVal, min(oldVal, maxVal)); // Make sure val is within min/max.
319
 
        
320
 
    // Force integer value if not float.
321
 
    if (!equalIgnoringCase(precision, "float"))
322
 
        val = lround(val);
323
 
 
324
 
    // Calculate the new position based on the value
325
 
    double factor = (val - minVal) / (maxVal - minVal);
326
 
    if (style()->appearance() == SliderVerticalPart)
327
 
        factor = 1.0 - factor;
328
 
 
329
 
    setCurrentPosition((int)(factor * trackSize()));
330
 
    
331
 
    if (value.isNull() || val != oldVal)
332
 
        static_cast<HTMLInputElement*>(node())->setValueFromRenderer(String::number(val));
333
 
    
334
 
    return val;
335
 
}
336
 
 
337
443
int RenderSlider::positionForOffset(const IntPoint& p)
338
444
{
339
445
    if (!m_thumb || !m_thumb->renderer())
340
446
        return 0;
341
 
   
 
447
 
342
448
    int position;
343
 
    if (style()->appearance() == SliderVerticalPart)
344
 
        position = p.y() - m_thumb->renderer()->height() / 2;
 
449
    if (style()->appearance() == SliderVerticalPart || style()->appearance() == MediaVolumeSliderPart)
 
450
        position = p.y() - m_thumb->renderBox()->height() / 2;
345
451
    else
346
 
        position = p.x() - m_thumb->renderer()->width() / 2;
 
452
        position = p.x() - m_thumb->renderBox()->width() / 2;
347
453
    
348
454
    return max(0, min(position, trackSize()));
349
455
}
350
456
 
351
 
void RenderSlider::valueChanged()
352
 
{
353
 
    setValueForPosition(currentPosition());
354
 
    static_cast<HTMLInputElement*>(node())->onChange();
355
 
}
356
 
 
357
457
int RenderSlider::currentPosition()
358
458
{
359
 
    if (!m_thumb || !m_thumb->renderer())
360
 
        return 0;
361
 
 
362
 
    if (style()->appearance() == SliderVerticalPart)
363
 
        return m_thumb->renderer()->style()->top().value();
364
 
    return m_thumb->renderer()->style()->left().value();
365
 
}
366
 
 
367
 
void RenderSlider::setCurrentPosition(int pos)
368
 
{
369
 
    if (!m_thumb || !m_thumb->renderer())
370
 
        return;
371
 
 
372
 
    if (style()->appearance() == SliderVerticalPart)
373
 
        m_thumb->renderer()->style()->setTop(Length(pos, Fixed));
374
 
    else
375
 
        m_thumb->renderer()->style()->setLeft(Length(pos, Fixed));
376
 
 
377
 
    m_thumb->renderer()->layer()->updateLayerPosition();
378
 
    repaint();
379
 
    m_thumb->renderer()->repaint();
 
459
    ASSERT(m_thumb);
 
460
    ASSERT(m_thumb->renderer());
 
461
 
 
462
    if (style()->appearance() == SliderVerticalPart || style()->appearance() == MediaVolumeSliderPart)
 
463
        return toRenderBox(m_thumb->renderer())->y() - contentBoxRect().y();
 
464
    return toRenderBox(m_thumb->renderer())->x() - contentBoxRect().x();
380
465
}
381
466
 
382
467
int RenderSlider::trackSize()
383
468
{
384
 
    if (!m_thumb || !m_thumb->renderer())
385
 
        return 0;
 
469
    ASSERT(m_thumb);
 
470
    ASSERT(m_thumb->renderer());
386
471
 
387
 
    if (style()->appearance() == SliderVerticalPart)
388
 
        return contentHeight() - m_thumb->renderer()->height();
389
 
    return contentWidth() - m_thumb->renderer()->width();
 
472
    if (style()->appearance() == SliderVerticalPart || style()->appearance() == MediaVolumeSliderPart)
 
473
        return contentHeight() - m_thumb->renderBox()->height();
 
474
    return contentWidth() - m_thumb->renderBox()->width();
390
475
}
391
476
 
392
 
void RenderSlider::forwardEvent(Event* evt)
 
477
void RenderSlider::forwardEvent(Event* event)
393
478
{
394
 
    m_thumb->defaultEventHandler(evt);
 
479
    if (event->isMouseEvent()) {
 
480
        MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
 
481
        if (event->type() == eventNames().mousedownEvent && mouseEvent->button() == LeftButton) {
 
482
            if (!mouseEventIsInThumb(mouseEvent)) {
 
483
                IntPoint eventOffset = roundedIntPoint(absoluteToLocal(mouseEvent->absoluteLocation(), false, true));
 
484
                setValueForPosition(positionForOffset(eventOffset));
 
485
            }
 
486
        }
 
487
    }
 
488
 
 
489
    m_thumb->defaultEventHandler(event);
395
490
}
396
491
 
397
492
bool RenderSlider::inDragMode() const
398
493
{
399
 
    return m_thumb->inDragMode();
 
494
    return m_thumb && m_thumb->inDragMode();
400
495
}
401
496
 
402
497
} // namespace WebCore