1/*
2 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
3 * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
4 * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
5 * Copyright (C) 2003, 2005, 2006, 2008 Apple Inc. All rights reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB.  If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23#include "config.h"
24#include "MouseRelatedEvent.h"
25
26#include "DOMWindow.h"
27#include "Document.h"
28#include "Frame.h"
29#include "FrameView.h"
30#include "RenderLayer.h"
31#include "RenderObject.h"
32
33namespace WebCore {
34
35MouseRelatedEvent::MouseRelatedEvent()
36    : m_screenX(0)
37    , m_screenY(0)
38    , m_clientX(0)
39    , m_clientY(0)
40    , m_pageX(0)
41    , m_pageY(0)
42    , m_layerX(0)
43    , m_layerY(0)
44    , m_offsetX(0)
45    , m_offsetY(0)
46    , m_isSimulated(false)
47{
48}
49
50static int contentsX(AbstractView* abstractView)
51{
52    if (!abstractView)
53        return 0;
54    Frame* frame = abstractView->frame();
55    if (!frame)
56        return 0;
57    FrameView* frameView = frame->view();
58    if (!frameView)
59        return 0;
60    return frameView->scrollX() / frame->pageZoomFactor();
61}
62
63static int contentsY(AbstractView* abstractView)
64{
65    if (!abstractView)
66        return 0;
67    Frame* frame = abstractView->frame();
68    if (!frame)
69        return 0;
70    FrameView* frameView = frame->view();
71    if (!frameView)
72        return 0;
73    return frameView->scrollY() / frame->pageZoomFactor();
74}
75
76MouseRelatedEvent::MouseRelatedEvent(const AtomicString& eventType, bool canBubble, bool cancelable, PassRefPtr<AbstractView> viewArg,
77                                     int detail, int screenX, int screenY, int pageX, int pageY,
78                                     bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, bool isSimulated)
79    : UIEventWithKeyState(eventType, canBubble, cancelable, viewArg, detail, ctrlKey, altKey, shiftKey, metaKey)
80    , m_screenX(screenX)
81    , m_screenY(screenY)
82    , m_clientX(pageX - contentsX(view()))
83    , m_clientY(pageY - contentsY(view()))
84    , m_pageX(pageX)
85    , m_pageY(pageY)
86    , m_isSimulated(isSimulated)
87{
88    initCoordinates();
89}
90
91void MouseRelatedEvent::initCoordinates()
92{
93    // Set up initial values for coordinates.
94    // Correct values can't be computed until we have at target, so receivedTarget
95    // does the "real" computation.
96    m_layerX = m_pageX;
97    m_layerY = m_pageY;
98    m_offsetX = m_pageX;
99    m_offsetY = m_pageY;
100
101    computePageLocation();
102}
103
104void MouseRelatedEvent::initCoordinates(int clientX, int clientY)
105{
106    // Set up initial values for coordinates.
107    // Correct values can't be computed until we have at target, so receivedTarget
108    // does the "real" computation.
109    m_clientX = clientX;
110    m_clientY = clientY;
111    m_pageX = clientX + contentsX(view());
112    m_pageY = clientY + contentsY(view());
113    m_layerX = m_pageX;
114    m_layerY = m_pageY;
115    m_offsetX = m_pageX;
116    m_offsetY = m_pageY;
117
118    computePageLocation();
119}
120
121void MouseRelatedEvent::computePageLocation()
122{
123    float zoomFactor = (view() && view()->frame()) ? view()->frame()->pageZoomFactor() : 1.0f;
124    setAbsoluteLocation(roundedIntPoint(FloatPoint(pageX() * zoomFactor, pageY() * zoomFactor)));
125}
126
127void MouseRelatedEvent::receivedTarget()
128{
129    ASSERT(target());
130    Node* targ = target()->toNode();
131    if (!targ)
132        return;
133
134    // Compute coordinates that are based on the target.
135    m_layerX = m_pageX;
136    m_layerY = m_pageY;
137    m_offsetX = m_pageX;
138    m_offsetY = m_pageY;
139
140    // Must have an updated render tree for this math to work correctly.
141    targ->document()->updateStyleIfNeeded();
142
143    // Adjust offsetX/Y to be relative to the target's position.
144    if (!isSimulated()) {
145        if (RenderObject* r = targ->renderer()) {
146            FloatPoint localPos = r->absoluteToLocal(absoluteLocation(), false, true);
147            float zoomFactor = (view() && view()->frame()) ? view()->frame()->pageZoomFactor() : 1.0f;
148            m_offsetX = lroundf(localPos.x() / zoomFactor);
149            m_offsetY = lroundf(localPos.y() / zoomFactor);
150        }
151    }
152
153    // Adjust layerX/Y to be relative to the layer.
154    // FIXME: We're pretty sure this is the wrong definition of "layer."
155    // Our RenderLayer is a more modern concept, and layerX/Y is some
156    // other notion about groups of elements (left over from the Netscape 4 days?);
157    // we should test and fix this.
158    Node* n = targ;
159    while (n && !n->renderer())
160        n = n->parent();
161    if (n) {
162        RenderLayer* layer = n->renderer()->enclosingLayer();
163        layer->updateLayerPosition();
164        for (; layer; layer = layer->parent()) {
165            m_layerX -= layer->x();
166            m_layerY -= layer->y();
167        }
168    }
169}
170
171int MouseRelatedEvent::pageX() const
172{
173    return m_pageX;
174}
175
176int MouseRelatedEvent::pageY() const
177{
178    return m_pageY;
179}
180
181int MouseRelatedEvent::x() const
182{
183    // FIXME: This is not correct.
184    // See Microsoft documentation and <http://www.quirksmode.org/dom/w3c_events.html>.
185    return m_clientX;
186}
187
188int MouseRelatedEvent::y() const
189{
190    // FIXME: This is not correct.
191    // See Microsoft documentation and <http://www.quirksmode.org/dom/w3c_events.html>.
192    return m_clientY;
193}
194
195} // namespace WebCore
196