2009-03-20 Simon Fraser <simon.fraser@apple.com>

        Reviewed by Darin Adler

        https://bugs.webkit.org/show_bug.cgi?id=24733

        Fix hit testing on video controls after full page zoom by fixing wider issue
        with event->pageX(), pageY() with zooming. pageX and pageY are "fixed" to be
        invariant under zooming (for JavaScript), so we keep an actual page point around
        in MouseEvent::absoluteLocation() to avoid the need to factor in zooming everywhere.

        * dom/MouseRelatedEvent.cpp:
        (WebCore::MouseRelatedEvent::initCoordinates):
        (WebCore::MouseRelatedEvent::computePageLocation):
        * dom/MouseRelatedEvent.h:
        (WebCore::MouseRelatedEvent::absoluteLocation):
        (WebCore::MouseRelatedEvent::setAbsoluteLocation):
        Member var, and getter and setter for absoluteLocation.
        New method, computePageLocation(), to compute the actual page point,
        and call it when creating and initting mouse-related events.

        * dom/Node.cpp:
        (WebCore::Node::dispatchMouseEvent):
        (WebCore::Node::dispatchWheelEvent):
        Keep non-adjusted pageX and pageY around, and call setAbsoluteLocation()
        on the event to replace a potentially rounded point.

        * html/HTMLInputElement.cpp:
        (WebCore::HTMLInputElement::defaultEventHandler):
        Clean up slider handling code.

        * html/HTMLSelectElement.cpp:
        (WebCore::HTMLSelectElement::listBoxDefaultEventHandler):
        Add FIXME comment for use of offsetX/offsetY.

        * page/ContextMenuController.cpp:
        (WebCore::ContextMenuController::handleContextMenuEvent):
        Use absoluteLocation() when hit testing for context menus.

        * rendering/RenderFrameSet.cpp:
        (WebCore::RenderFrameSet::userResize):
        Use absoluteLocation() when resizing frames.

        * rendering/RenderMedia.cpp:
        (WebCore::RenderMedia::forwardEvent):
        Use absoluteLocation() when hit testing media controls.

        * rendering/RenderSlider.cpp:
        (WebCore::HTMLSliderThumbElement::defaultEventHandler):
        (WebCore::RenderSlider::mouseEventIsInThumb):
        Use absoluteLocation() when handling slider events.

        (WebCore::RenderSlider::forwardEvent):
        Factor some code out of HTMLInputElement::defaultEventHandler().

        * rendering/RenderTextControlSingleLine.cpp:
        (WebCore::RenderTextControlSingleLine::forwardEvent):
        Use absoluteLocation() when hit testing search field buttons, which fixees
        bugs in the search field with zooming.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@41899 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent e7e0dcab
2009-03-20 Simon Fraser <simon.fraser@apple.com>
Reviewed by Darin Adler
https://bugs.webkit.org/show_bug.cgi?id=24733
Fix hit testing on video controls after full page zoom by fixing wider issue
with event->pageX(), pageY() with zooming. pageX and pageY are "fixed" to be
invariant under zooming (for JavaScript), so we keep an actual page point around
in MouseEvent::absoluteLocation() to avoid the need to factor in zooming everywhere.
* dom/MouseRelatedEvent.cpp:
(WebCore::MouseRelatedEvent::initCoordinates):
(WebCore::MouseRelatedEvent::computePageLocation):
* dom/MouseRelatedEvent.h:
(WebCore::MouseRelatedEvent::absoluteLocation):
(WebCore::MouseRelatedEvent::setAbsoluteLocation):
Member var, and getter and setter for absoluteLocation.
New method, computePageLocation(), to compute the actual page point,
and call it when creating and initting mouse-related events.
* dom/Node.cpp:
(WebCore::Node::dispatchMouseEvent):
(WebCore::Node::dispatchWheelEvent):
Keep non-adjusted pageX and pageY around, and call setAbsoluteLocation()
on the event to replace a potentially rounded point.
* html/HTMLInputElement.cpp:
(WebCore::HTMLInputElement::defaultEventHandler):
Clean up slider handling code.
* html/HTMLSelectElement.cpp:
(WebCore::HTMLSelectElement::listBoxDefaultEventHandler):
Add FIXME comment for use of offsetX/offsetY.
* page/ContextMenuController.cpp:
(WebCore::ContextMenuController::handleContextMenuEvent):
Use absoluteLocation() when hit testing for context menus.
* rendering/RenderFrameSet.cpp:
(WebCore::RenderFrameSet::userResize):
Use absoluteLocation() when resizing frames.
* rendering/RenderMedia.cpp:
(WebCore::RenderMedia::forwardEvent):
Use absoluteLocation() when hit testing media controls.
* rendering/RenderSlider.cpp:
(WebCore::HTMLSliderThumbElement::defaultEventHandler):
(WebCore::RenderSlider::mouseEventIsInThumb):
Use absoluteLocation() when handling slider events.
(WebCore::RenderSlider::forwardEvent):
Factor some code out of HTMLInputElement::defaultEventHandler().
* rendering/RenderTextControlSingleLine.cpp:
(WebCore::RenderTextControlSingleLine::forwardEvent):
Use absoluteLocation() when hit testing search field buttons, which fixees
bugs in the search field with zooming.
2009-03-21 David Levin <levin@chromium.org>
Reviewed by Dimitri Glazkov.
......@@ -97,6 +97,8 @@ void MouseRelatedEvent::initCoordinates()
m_layerY = m_pageY;
m_offsetX = m_pageX;
m_offsetY = m_pageY;
computePageLocation();
}
void MouseRelatedEvent::initCoordinates(int clientX, int clientY)
......@@ -112,6 +114,14 @@ void MouseRelatedEvent::initCoordinates(int clientX, int clientY)
m_layerY = m_pageY;
m_offsetX = m_pageX;
m_offsetY = m_pageY;
computePageLocation();
}
void MouseRelatedEvent::computePageLocation()
{
float zoomFactor = (view() && view()->frame()) ? view()->frame()->pageZoomFactor() : 1.0f;
setAbsoluteLocation(roundedIntPoint(FloatPoint(pageX() * zoomFactor, pageY() * zoomFactor)));
}
void MouseRelatedEvent::receivedTarget()
......
......@@ -26,6 +26,7 @@
#ifndef MouseRelatedEvent_h
#define MouseRelatedEvent_h
#include "IntPoint.h"
#include "UIEventWithKeyState.h"
namespace WebCore {
......@@ -33,6 +34,8 @@ namespace WebCore {
// Internal only: Helper class for what's common between mouse and wheel events.
class MouseRelatedEvent : public UIEventWithKeyState {
public:
// Note that these values are adjusted to counter the effects of zoom, so that values
// exposed via DOM APIs are invariant under zooming.
int screenX() const { return m_screenX; }
int screenY() const { return m_screenY; }
int clientX() const { return m_clientX; }
......@@ -46,6 +49,11 @@ namespace WebCore {
virtual int pageY() const;
int x() const;
int y() const;
// Page point in "absolute" coordinates (i.e. post-zoomed, page-relative coords,
// usable with RenderObject::absoluteToLocal).
IntPoint absoluteLocation() const { return m_absoluteLocation; }
void setAbsoluteLocation(const IntPoint& p) { m_absoluteLocation = p; }
protected:
MouseRelatedEvent();
......@@ -56,6 +64,8 @@ namespace WebCore {
void initCoordinates();
void initCoordinates(int clientX, int clientY);
virtual void receivedTarget();
void computePageLocation();
// Expose these so MouseEvent::initMouseEvent can set them.
int m_screenX;
......@@ -70,6 +80,7 @@ namespace WebCore {
int m_layerY;
int m_offsetX;
int m_offsetY;
IntPoint m_absoluteLocation;
bool m_isSimulated;
};
......
......@@ -2652,21 +2652,24 @@ bool Node::dispatchMouseEvent(const AtomicString& eventType, int button, int det
// Attempting to dispatch with a non-EventTarget relatedTarget causes the relatedTarget to be silently ignored.
RefPtr<Node> relatedTarget = relatedTargetArg;
int adjustedPageX = pageX;
int adjustedPageY = pageY;
if (Frame* frame = document()->frame()) {
float pageZoom = frame->pageZoomFactor();
if (pageZoom != 1.0f) {
// Adjust our pageX and pageY to account for the page zoom.
pageX = lroundf(pageX / pageZoom);
pageY = lroundf(pageY / pageZoom);
adjustedPageX = lroundf(pageX / pageZoom);
adjustedPageY = lroundf(pageY / pageZoom);
}
}
RefPtr<Event> mouseEvent = MouseEvent::create(eventType,
RefPtr<MouseEvent> mouseEvent = MouseEvent::create(eventType,
true, cancelable, document()->defaultView(),
detail, screenX, screenY, pageX, pageY,
detail, screenX, screenY, adjustedPageX, adjustedPageY,
ctrlKey, altKey, shiftKey, metaKey, button,
relatedTarget, 0, isSimulated);
mouseEvent->setUnderlyingEvent(underlyingEvent.get());
mouseEvent->setAbsoluteLocation(IntPoint(pageX, pageY));
dispatchEvent(mouseEvent, ec);
bool defaultHandled = mouseEvent->defaultHandled();
......@@ -2705,10 +2708,24 @@ void Node::dispatchWheelEvent(PlatformWheelEvent& e)
return;
IntPoint pos = view->windowToContents(e.pos());
int adjustedPageX = pos.x();
int adjustedPageY = pos.y();
if (Frame* frame = document()->frame()) {
float pageZoom = frame->pageZoomFactor();
if (pageZoom != 1.0f) {
// Adjust our pageX and pageY to account for the page zoom.
adjustedPageX = lroundf(pos.x() / pageZoom);
adjustedPageY = lroundf(pos.y() / pageZoom);
}
}
RefPtr<WheelEvent> we = WheelEvent::create(e.wheelTicksX(), e.wheelTicksY(),
document()->defaultView(), e.globalX(), e.globalY(), pos.x(), pos.y(),
document()->defaultView(), e.globalX(), e.globalY(), adjustedPageX, adjustedPageY,
e.ctrlKey(), e.altKey(), e.shiftKey(), e.metaKey());
we->setAbsoluteLocation(IntPoint(pos.x(), pos.y()));
ExceptionCode ec = 0;
if (!dispatchEvent(we.release(), ec))
e.accept();
......
......@@ -1100,6 +1100,7 @@ void HTMLInputElement::defaultEventHandler(Event* evt)
m_yPos = 0;
} else {
// FIXME: This doesn't work correctly with transforms.
// FIXME: pageX/pageY need adjusting for pageZoomFactor(). Use actualPageLocation()?
IntPoint absOffset = roundedIntPoint(renderer()->localToAbsolute());
m_xPos = me->pageX() - absOffset.x();
m_yPos = me->pageY() - absOffset.y();
......@@ -1338,20 +1339,8 @@ void HTMLInputElement::defaultEventHandler(Event* evt)
if (isTextField() && renderer() && (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent() || evt->type() == eventNames().blurEvent || evt->type() == eventNames().focusEvent))
static_cast<RenderTextControlSingleLine*>(renderer())->forwardEvent(evt);
if (inputType() == RANGE && renderer()) {
RenderSlider* slider = static_cast<RenderSlider*>(renderer());
if (evt->isMouseEvent() && evt->type() == eventNames().mousedownEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) {
MouseEvent* mEvt = static_cast<MouseEvent*>(evt);
if (!slider->mouseEventIsInThumb(mEvt)) {
IntPoint eventOffset(mEvt->offsetX(), mEvt->offsetY());
if (mEvt->target() != this) // Does this ever happen now? Was originally added for <video> controls.
eventOffset = roundedIntPoint(renderer()->absoluteToLocal(FloatPoint(mEvt->pageX(), mEvt->pageY()), false, true));
slider->setValueForPosition(slider->positionForOffset(eventOffset));
}
}
if (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent())
slider->forwardEvent(evt);
}
if (inputType() == RANGE && renderer() && (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent()))
static_cast<RenderSlider*>(renderer())->forwardEvent(evt);
if (!callBaseClassEarly && !evt->defaultHandled())
HTMLFormControlElementWithState::defaultEventHandler(evt);
......
......@@ -678,6 +678,7 @@ void HTMLSelectElement::listBoxDefaultEventHandler(Event* evt)
// Convert to coords relative to the list box if needed.
MouseEvent* mouseEvent = static_cast<MouseEvent*>(evt);
// FIXME: need to adjust offsetX/offsetY for full page zoom
int offsetX = mouseEvent->offsetX();
int offsetY = mouseEvent->offsetY();
Node* target = evt->target()->toNode();
......
......@@ -83,15 +83,10 @@ void ContextMenuController::handleContextMenuEvent(Event* event)
if (!event->isMouseEvent())
return;
MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
IntPoint point = IntPoint(mouseEvent->pageX(), mouseEvent->pageY());
HitTestResult result(point);
HitTestResult result(mouseEvent->absoluteLocation());
if (Frame* frame = event->target()->toNode()->document()->frame()) {
float zoomFactor = frame->pageZoomFactor();
point.setX(static_cast<int>(point.x() * zoomFactor));
point.setY(static_cast<int>(point.y() * zoomFactor));
result = frame->eventHandler()->hitTestResultAtPoint(point, false);
}
if (Frame* frame = event->target()->toNode()->document()->frame())
result = frame->eventHandler()->hitTestResultAtPoint(mouseEvent->absoluteLocation(), false);
if (!result.innerNonSharedNode())
return;
......
......@@ -565,8 +565,8 @@ bool RenderFrameSet::userResize(MouseEvent* evt)
return false;
if (evt->type() == eventNames().mousedownEvent && evt->button() == LeftButton) {
FloatPoint pos = localToAbsolute();
startResizing(m_cols, evt->pageX() - pos.x());
startResizing(m_rows, evt->pageY() - pos.y());
startResizing(m_cols, evt->absoluteLocation().x() - pos.x());
startResizing(m_rows, evt->absoluteLocation().y() - pos.y());
if (m_cols.m_splitBeingResized != noSplit || m_rows.m_splitBeingResized != noSplit) {
setIsResizing(true);
return true;
......@@ -575,8 +575,8 @@ bool RenderFrameSet::userResize(MouseEvent* evt)
} else {
if (evt->type() == eventNames().mousemoveEvent || (evt->type() == eventNames().mouseupEvent && evt->button() == LeftButton)) {
FloatPoint pos = localToAbsolute();
continueResizing(m_cols, evt->pageX() - pos.x());
continueResizing(m_rows, evt->pageY() - pos.y());
continueResizing(m_cols, evt->absoluteLocation().x() - pos.x());
continueResizing(m_rows, evt->absoluteLocation().y() - pos.y());
if (evt->type() == eventNames().mouseupEvent && evt->button() == LeftButton) {
setIsResizing(false);
return true;
......
......@@ -403,7 +403,7 @@ void RenderMedia::forwardEvent(Event* event)
{
if (event->isMouseEvent() && m_controlsShadowRoot) {
MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
IntPoint point(mouseEvent->pageX(), mouseEvent->pageY());
IntPoint point(mouseEvent->absoluteLocation());
if (m_muteButton && m_muteButton->hitTest(point))
m_muteButton->defaultEventHandler(event);
......
......@@ -79,8 +79,9 @@ void HTMLSliderThumbElement::defaultEventHandler(Event* event)
if (document()->frame() && renderer() && renderer()->parent() &&
(slider = static_cast<RenderSlider*>(renderer()->parent())) &&
slider->mouseEventIsInThumb(mouseEvent)) {
// Cache the initial point where the mouse down occurred, in slider coordinates
m_initialClickPoint = slider->absoluteToLocal(FloatPoint(mouseEvent->pageX(), mouseEvent->pageY()), false, true);
m_initialClickPoint = slider->absoluteToLocal(mouseEvent->absoluteLocation(), false, true);
// Cache the initial position of the thumb.
m_initialPosition = slider->currentPosition();
m_inDragMode = true;
......@@ -103,7 +104,8 @@ void HTMLSliderThumbElement::defaultEventHandler(Event* event)
// Move the slider
MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
RenderSlider* slider = static_cast<RenderSlider*>(renderer()->parent());
FloatPoint curPoint = slider->absoluteToLocal(FloatPoint(mouseEvent->pageX(), mouseEvent->pageY()), false, true);
FloatPoint curPoint = slider->absoluteToLocal(mouseEvent->absoluteLocation(), false, true);
int newPosition = slider->positionForOffset(
IntPoint(m_initialPosition + curPoint.x() - m_initialClickPoint.x()
+ (renderBox()->width() / 2),
......@@ -264,15 +266,13 @@ bool RenderSlider::mouseEventIsInThumb(MouseEvent* evt)
#if ENABLE(VIDEO)
if (style()->appearance() == MediaSliderPart) {
MediaControlInputElement *sliderThumb = static_cast<MediaControlInputElement*>(m_thumb->renderer()->node());
IntPoint absPoint(evt->pageX(), evt->pageY());
return sliderThumb->hitTest(absPoint);
} else
#endif
{
FloatPoint localPoint = m_thumb->renderBox()->absoluteToLocal(FloatPoint(evt->pageX(), evt->pageY()), false, true);
IntRect thumbBounds = m_thumb->renderBox()->borderBoxRect();
return thumbBounds.contains(roundedIntPoint(localPoint));
return sliderThumb->hitTest(evt->absoluteLocation());
}
#endif
FloatPoint localPoint = m_thumb->renderBox()->absoluteToLocal(evt->absoluteLocation(), false, true);
IntRect thumbBounds = m_thumb->renderBox()->borderBoxRect();
return thumbBounds.contains(roundedIntPoint(localPoint));
}
void RenderSlider::setValueForPosition(int position)
......@@ -402,6 +402,16 @@ int RenderSlider::trackSize()
void RenderSlider::forwardEvent(Event* evt)
{
if (evt->isMouseEvent()) {
MouseEvent* mouseEvt = static_cast<MouseEvent*>(evt);
if (evt->type() == eventNames().mousedownEvent && mouseEvt->button() == LeftButton) {
if (!mouseEventIsInThumb(mouseEvt)) {
IntPoint eventOffset = roundedIntPoint(absoluteToLocal(mouseEvt->absoluteLocation(), false, true));
setValueForPosition(positionForOffset(eventOffset));
}
}
}
m_thumb->defaultEventHandler(evt);
}
......
......@@ -325,7 +325,7 @@ void RenderTextControlSingleLine::forwardEvent(Event* event)
return;
}
FloatPoint localPoint = innerTextRenderer->absoluteToLocal(FloatPoint(static_cast<MouseEvent*>(event)->pageX(), static_cast<MouseEvent*>(event)->pageY()), false, true);
FloatPoint localPoint = innerTextRenderer->absoluteToLocal(static_cast<MouseEvent*>(event)->absoluteLocation(), false, true);
if (m_resultsButton && localPoint.x() < innerTextRenderer->borderBoxRect().x())
m_resultsButton->defaultEventHandler(event);
else if (m_cancelButton && localPoint.x() > innerTextRenderer->borderBoxRect().right())
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment