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    , m_hasCachedRelativePosition(false)
48{
49}
50
51static int contentsX(AbstractView* abstractView)
52{
53    if (!abstractView)
54        return 0;
55    Frame* frame = abstractView->frame();
56    if (!frame)
57        return 0;
58    FrameView* frameView = frame->view();
59    if (!frameView)
60        return 0;
61    return frameView->scrollX() / frame->pageZoomFactor();
62}
63
64static int contentsY(AbstractView* abstractView)
65{
66    if (!abstractView)
67        return 0;
68    Frame* frame = abstractView->frame();
69    if (!frame)
70        return 0;
71    FrameView* frameView = frame->view();
72    if (!frameView)
73        return 0;
74    return frameView->scrollY() / frame->pageZoomFactor();
75}
76
77MouseRelatedEvent::MouseRelatedEvent(const AtomicString& eventType, bool canBubble, bool cancelable, PassRefPtr<AbstractView> abstractView,
78                                     int detail, int screenX, int screenY, int windowX, int windowY,
79                                     bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, bool isSimulated)
80    : UIEventWithKeyState(eventType, canBubble, cancelable, abstractView, detail, ctrlKey, altKey, shiftKey, metaKey)
81    , m_screenX(screenX)
82    , m_screenY(screenY)
83    , m_clientX(0)
84    , m_clientY(0)
85    , m_pageX(0)
86    , m_pageY(0)
87    , m_isSimulated(isSimulated)
88{
89    IntPoint adjustedPageLocation;
90    IntPoint scrollPosition;
91
92    Frame* frame = view() ? view()->frame() : 0;
93    if (frame && !isSimulated) {
94        if (FrameView* frameView = frame->view()) {
95            scrollPosition = frameView->scrollPosition();
96            adjustedPageLocation = frameView->windowToContents(IntPoint(windowX, windowY));
97            float pageZoom = frame->pageZoomFactor();
98            if (pageZoom != 1.0f) {
99                // Adjust our pageX and pageY to account for the page zoom.
100                adjustedPageLocation.setX(lroundf(adjustedPageLocation.x() / pageZoom));
101                adjustedPageLocation.setY(lroundf(adjustedPageLocation.y() / pageZoom));
102                scrollPosition.setX(scrollPosition.x() / pageZoom);
103                scrollPosition.setY(scrollPosition.y() / pageZoom);
104            }
105        }
106    }
107
108    IntPoint clientLocation(adjustedPageLocation - scrollPosition);
109    m_clientX = clientLocation.x();
110    m_clientY = clientLocation.y();
111    m_pageX = adjustedPageLocation.x();
112    m_pageY = adjustedPageLocation.y();
113
114    initCoordinates();
115}
116
117void MouseRelatedEvent::initCoordinates()
118{
119    // Set up initial values for coordinates.
120    // Correct values are computed lazily, see computeRelativePosition.
121    m_layerX = m_pageX;
122    m_layerY = m_pageY;
123    m_offsetX = m_pageX;
124    m_offsetY = m_pageY;
125
126    computePageLocation();
127    m_hasCachedRelativePosition = false;
128}
129
130void MouseRelatedEvent::initCoordinates(int clientX, int clientY)
131{
132    // Set up initial values for coordinates.
133    // Correct values are computed lazily, see computeRelativePosition.
134    m_clientX = clientX;
135    m_clientY = clientY;
136    m_pageX = clientX + contentsX(view());
137    m_pageY = clientY + contentsY(view());
138    m_layerX = m_pageX;
139    m_layerY = m_pageY;
140    m_offsetX = m_pageX;
141    m_offsetY = m_pageY;
142
143    computePageLocation();
144    m_hasCachedRelativePosition = false;
145}
146
147static float pageZoomFactor(const UIEvent* event)
148{
149    DOMWindow* window = event->view();
150    if (!window)
151        return 1;
152    Frame* frame = window->frame();
153    if (!frame)
154        return 1;
155    return frame->pageZoomFactor();
156}
157
158void MouseRelatedEvent::computePageLocation()
159{
160    float zoomFactor = pageZoomFactor(this);
161    setAbsoluteLocation(roundedIntPoint(FloatPoint(pageX() * zoomFactor, pageY() * zoomFactor)));
162}
163
164void MouseRelatedEvent::receivedTarget()
165{
166    m_hasCachedRelativePosition = false;
167}
168
169void MouseRelatedEvent::computeRelativePosition()
170{
171    Node* targetNode = target() ? target()->toNode() : 0;
172    if (!targetNode)
173        return;
174
175    // Compute coordinates that are based on the target.
176    m_layerX = m_pageX;
177    m_layerY = m_pageY;
178    m_offsetX = m_pageX;
179    m_offsetY = m_pageY;
180
181    // Must have an updated render tree for this math to work correctly.
182    targetNode->document()->updateStyleIfNeeded();
183
184    // Adjust offsetX/Y to be relative to the target's position.
185    if (!isSimulated()) {
186        if (RenderObject* r = targetNode->renderer()) {
187            FloatPoint localPos = r->absoluteToLocal(absoluteLocation(), false, true);
188            float zoomFactor = pageZoomFactor(this);
189            m_offsetX = lroundf(localPos.x() / zoomFactor);
190            m_offsetY = lroundf(localPos.y() / zoomFactor);
191        }
192    }
193
194    // Adjust layerX/Y to be relative to the layer.
195    // FIXME: We're pretty sure this is the wrong definition of "layer."
196    // Our RenderLayer is a more modern concept, and layerX/Y is some
197    // other notion about groups of elements (left over from the Netscape 4 days?);
198    // we should test and fix this.
199    Node* n = targetNode;
200    while (n && !n->renderer())
201        n = n->parentNode();
202
203    RenderLayer* layer;
204    if (n && (layer = n->renderer()->enclosingLayer())) {
205        layer->updateLayerPosition();
206        for (; layer; layer = layer->parent()) {
207            m_layerX -= layer->x();
208            m_layerY -= layer->y();
209        }
210    }
211
212    m_hasCachedRelativePosition = true;
213}
214
215int MouseRelatedEvent::layerX()
216{
217    if (!m_hasCachedRelativePosition)
218        computeRelativePosition();
219    return m_layerX;
220}
221
222int MouseRelatedEvent::layerY()
223{
224    if (!m_hasCachedRelativePosition)
225        computeRelativePosition();
226    return m_layerY;
227}
228
229int MouseRelatedEvent::offsetX()
230{
231    if (!m_hasCachedRelativePosition)
232        computeRelativePosition();
233    return m_offsetX;
234}
235
236int MouseRelatedEvent::offsetY()
237{
238    if (!m_hasCachedRelativePosition)
239        computeRelativePosition();
240    return m_offsetY;
241}
242
243int MouseRelatedEvent::pageX() const
244{
245    return m_pageX;
246}
247
248int MouseRelatedEvent::pageY() const
249{
250    return m_pageY;
251}
252
253int MouseRelatedEvent::x() const
254{
255    // FIXME: This is not correct.
256    // See Microsoft documentation and <http://www.quirksmode.org/dom/w3c_events.html>.
257    return m_clientX;
258}
259
260int MouseRelatedEvent::y() const
261{
262    // FIXME: This is not correct.
263    // See Microsoft documentation and <http://www.quirksmode.org/dom/w3c_events.html>.
264    return m_clientY;
265}
266
267} // namespace WebCore
268