/* * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2010 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "SliderThumbElement.h" #include "Event.h" #include "Frame.h" #include "HTMLInputElement.h" #include "HTMLParserIdioms.h" #include "MouseEvent.h" #include "RenderSlider.h" #include "RenderTheme.h" #include "StepRange.h" #include using namespace std; #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS) #include "TouchEvent.h" #endif namespace WebCore { // FIXME: Find a way to cascade appearance (see the layout method) and get rid of this class. class RenderSliderThumb : public RenderBlock { public: RenderSliderThumb(Node*); virtual void layout(); }; RenderSliderThumb::RenderSliderThumb(Node* node) : RenderBlock(node) { } void RenderSliderThumb::layout() { // FIXME: Hard-coding this cascade of appearance is bad, because it's something // that CSS usually does. We need to find a way to express this in CSS. RenderStyle* parentStyle = parent()->style(); if (parentStyle->appearance() == SliderVerticalPart) style()->setAppearance(SliderThumbVerticalPart); else if (parentStyle->appearance() == SliderHorizontalPart) style()->setAppearance(SliderThumbHorizontalPart); else if (parentStyle->appearance() == MediaSliderPart) style()->setAppearance(MediaSliderThumbPart); else if (parentStyle->appearance() == MediaVolumeSliderPart) style()->setAppearance(MediaVolumeSliderThumbPart); if (style()->hasAppearance()) { // FIXME: This should pass the style, not the renderer, to the theme. theme()->adjustSliderThumbSize(this); } RenderBlock::layout(); } RenderObject* SliderThumbElement::createRenderer(RenderArena* arena, RenderStyle*) { return new (arena) RenderSliderThumb(this); } void SliderThumbElement::dragFrom(const IntPoint& point) { setPosition(point); startDragging(); } void SliderThumbElement::setPosition(const IntPoint& point) { HTMLInputElement* input = static_cast(shadowHost()); ASSERT(input); if (!input->renderer() || !renderer()) return; IntPoint offset = roundedIntPoint(input->renderer()->absoluteToLocal(point, false, true)); RenderStyle* sliderStyle = input->renderer()->style(); bool isVertical = sliderStyle->appearance() == SliderVerticalPart || sliderStyle->appearance() == MediaVolumeSliderPart; int trackSize; int position; int currentPosition; if (isVertical) { trackSize = input->renderBox()->contentHeight() - renderBox()->height(); position = offset.y() - renderBox()->height() / 2; currentPosition = renderBox()->y() - input->renderBox()->contentBoxRect().y(); } else { trackSize = input->renderBox()->contentWidth() - renderBox()->width(); position = offset.x() - renderBox()->width() / 2; currentPosition = renderBox()->x() - input->renderBox()->contentBoxRect().x(); } position = max(0, min(position, trackSize)); if (position == currentPosition) return; StepRange range(input); double fraction = static_cast(position) / trackSize; if (isVertical) fraction = 1 - fraction; double value = range.clampValue(range.valueFromProportion(fraction)); // FIXME: This is no longer being set from renderer. Consider updating the method name. input->setValueFromRenderer(serializeForNumberType(value)); renderer()->setNeedsLayout(true); input->dispatchFormControlChangeEvent(); } void SliderThumbElement::startDragging() { if (Frame* frame = document()->frame()) { frame->eventHandler()->setCapturingMouseEventsNode(this); m_inDragMode = true; } } void SliderThumbElement::stopDragging() { if (!m_inDragMode) return; if (Frame* frame = document()->frame()) frame->eventHandler()->setCapturingMouseEventsNode(0); m_inDragMode = false; } void SliderThumbElement::defaultEventHandler(Event* event) { if (!event->isMouseEvent() #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS) && !event->isTouchEvent() #endif ) { HTMLDivElement::defaultEventHandler(event); return; } MouseEvent* mouseEvent = static_cast(event); bool isLeftButton = mouseEvent->button() == LeftButton; const AtomicString& eventType = event->type(); <<<<<<< HEAD if (eventType == eventNames().mousedownEvent && isLeftButton #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS) || eventType == eventNames().touchstartEvent #endif ) { if (document()->frame() && renderer()) { RenderSlider* slider = toRenderSlider(renderer()->parent()); if (slider) { if (slider->mouseEventIsInThumb(mouseEvent)) { // We selected the thumb, we want the cursor to always stay at // the same position relative to the thumb. m_offsetToThumb = slider->mouseEventOffsetToThumb(mouseEvent); } else { // We are outside the thumb, move the thumb to the point were // we clicked. We'll be exactly at the center of the thumb. m_offsetToThumb.setX(0); m_offsetToThumb.setY(0); } m_inDragMode = true; document()->frame()->eventHandler()->setCapturingMouseEventsNode(shadowHost()); event->setDefaultHandled(); return; } } } else if (eventType == eventNames().mouseupEvent && isLeftButton #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS) || eventType == eventNames().touchendEvent #endif ) { if (m_inDragMode) { if (Frame* frame = document()->frame()) frame->eventHandler()->setCapturingMouseEventsNode(0); m_inDragMode = false; event->setDefaultHandled(); return; } } else if (eventType == eventNames().mousemoveEvent #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS) || eventType == eventNames().touchmoveEvent #endif ) { if (m_inDragMode && renderer() && renderer()->parent()) { RenderSlider* slider = toRenderSlider(renderer()->parent()); if (slider) { FloatPoint curPoint = slider->absoluteToLocal(mouseEvent->absoluteLocation(), false, true); #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS) // Update the position when it is a touch event if (event->isTouchEvent()) { TouchEvent* touchEvent = static_cast(event); if (touchEvent && touchEvent->touches() && touchEvent->touches()->item(0)) { curPoint.setX(touchEvent->touches()->item(0)->pageX()); curPoint.setY(touchEvent->touches()->item(0)->pageY()); curPoint = slider->absoluteToLocal(curPoint, false, true); } } // Tell the webview that webkit will handle the following move events event->setDefaultPrevented(true); #endif IntPoint eventOffset(curPoint.x() + m_offsetToThumb.x(), curPoint.y() + m_offsetToThumb.y()); slider->setValueForPosition(slider->positionForOffset(eventOffset)); event->setDefaultHandled(); return; } } ======= if (eventType == eventNames().mousedownEvent && isLeftButton) { startDragging(); return; } else if (eventType == eventNames().mouseupEvent && isLeftButton) { stopDragging(); return; } else if (eventType == eventNames().mousemoveEvent) { if (m_inDragMode) setPosition(mouseEvent->absoluteLocation()); return; >>>>>>> WebKit.org at r76408 } HTMLDivElement::defaultEventHandler(event); } void SliderThumbElement::detach() { if (m_inDragMode) { if (Frame* frame = document()->frame()) frame->eventHandler()->setCapturingMouseEventsNode(0); } HTMLDivElement::detach(); } }