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 "core/events/MouseRelatedEvent.h"
25
26#include "core/dom/Document.h"
27#include "core/frame/LocalDOMWindow.h"
28#include "core/frame/FrameView.h"
29#include "core/frame/LocalFrame.h"
30#include "core/rendering/RenderLayer.h"
31#include "core/rendering/RenderObject.h"
32
33namespace blink {
34
35MouseRelatedEvent::MouseRelatedEvent()
36    : m_isSimulated(false)
37    , m_hasCachedRelativePosition(false)
38{
39}
40
41static LayoutSize contentsScrollOffset(AbstractView* abstractView)
42{
43    if (!abstractView)
44        return LayoutSize();
45    LocalFrame* frame = abstractView->frame();
46    if (!frame)
47        return LayoutSize();
48    FrameView* frameView = frame->view();
49    if (!frameView)
50        return LayoutSize();
51    float scaleFactor = frame->pageZoomFactor();
52    return LayoutSize(frameView->scrollX() / scaleFactor, frameView->scrollY() / scaleFactor);
53}
54
55MouseRelatedEvent::MouseRelatedEvent(const AtomicString& eventType, bool canBubble, bool cancelable, PassRefPtrWillBeRawPtr<AbstractView> abstractView,
56                                     int detail, const IntPoint& screenLocation, const IntPoint& windowLocation,
57                                     const IntPoint& movementDelta,
58                                     bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, bool isSimulated)
59    : UIEventWithKeyState(eventType, canBubble, cancelable, abstractView, detail, ctrlKey, altKey, shiftKey, metaKey)
60    , m_screenLocation(screenLocation)
61    , m_movementDelta(movementDelta)
62    , m_isSimulated(isSimulated)
63{
64    LayoutPoint adjustedPageLocation;
65    LayoutPoint scrollPosition;
66
67    LocalFrame* frame = view() ? view()->frame() : 0;
68    if (frame && !isSimulated) {
69        if (FrameView* frameView = frame->view()) {
70            scrollPosition = frameView->scrollPosition();
71            adjustedPageLocation = frameView->windowToContents(windowLocation);
72            float scaleFactor = 1 / frame->pageZoomFactor();
73            if (scaleFactor != 1.0f) {
74                adjustedPageLocation.scale(scaleFactor, scaleFactor);
75                scrollPosition.scale(scaleFactor, scaleFactor);
76            }
77        }
78    }
79
80    m_clientLocation = adjustedPageLocation - toLayoutSize(scrollPosition);
81    m_pageLocation = adjustedPageLocation;
82
83    initCoordinates();
84}
85
86void MouseRelatedEvent::initCoordinates()
87{
88    // Set up initial values for coordinates.
89    // Correct values are computed lazily, see computeRelativePosition.
90    m_layerLocation = m_pageLocation;
91    m_offsetLocation = m_pageLocation;
92
93    computePageLocation();
94    m_hasCachedRelativePosition = false;
95}
96
97void MouseRelatedEvent::initCoordinates(const LayoutPoint& clientLocation)
98{
99    // Set up initial values for coordinates.
100    // Correct values are computed lazily, see computeRelativePosition.
101    m_clientLocation = clientLocation;
102    m_pageLocation = clientLocation + contentsScrollOffset(view());
103
104    m_layerLocation = m_pageLocation;
105    m_offsetLocation = m_pageLocation;
106
107    computePageLocation();
108    m_hasCachedRelativePosition = false;
109}
110
111static float pageZoomFactor(const UIEvent* event)
112{
113    LocalDOMWindow* window = event->view();
114    if (!window)
115        return 1;
116    LocalFrame* frame = window->frame();
117    if (!frame)
118        return 1;
119    return frame->pageZoomFactor();
120}
121
122void MouseRelatedEvent::computePageLocation()
123{
124    float scaleFactor = pageZoomFactor(this);
125    setAbsoluteLocation(roundedLayoutPoint(FloatPoint(pageX() * scaleFactor, pageY() * scaleFactor)));
126}
127
128void MouseRelatedEvent::receivedTarget()
129{
130    m_hasCachedRelativePosition = false;
131}
132
133void MouseRelatedEvent::computeRelativePosition()
134{
135    Node* targetNode = target() ? target()->toNode() : 0;
136    if (!targetNode)
137        return;
138
139    // Compute coordinates that are based on the target.
140    m_layerLocation = m_pageLocation;
141    m_offsetLocation = m_pageLocation;
142
143    // Must have an updated render tree for this math to work correctly.
144    targetNode->document().updateLayoutIgnorePendingStylesheets();
145
146    // Adjust offsetLocation to be relative to the target's position.
147    if (RenderObject* r = targetNode->renderer()) {
148        FloatPoint localPos = r->absoluteToLocal(absoluteLocation(), UseTransforms);
149        m_offsetLocation = roundedLayoutPoint(localPos);
150        float scaleFactor = 1 / pageZoomFactor(this);
151        if (scaleFactor != 1.0f)
152            m_offsetLocation.scale(scaleFactor, scaleFactor);
153    }
154
155    // Adjust layerLocation to be relative to the layer.
156    // FIXME: event.layerX and event.layerY are poorly defined,
157    // and probably don't always correspond to RenderLayer offsets.
158    // https://bugs.webkit.org/show_bug.cgi?id=21868
159    Node* n = targetNode;
160    while (n && !n->renderer())
161        n = n->parentNode();
162
163    if (n) {
164        // FIXME: This logic is a wrong implementation of convertToLayerCoords.
165        for (RenderLayer* layer = n->renderer()->enclosingLayer(); layer; layer = layer->parent())
166            m_layerLocation -= toLayoutSize(layer->location());
167    }
168
169    m_hasCachedRelativePosition = true;
170}
171
172int MouseRelatedEvent::layerX()
173{
174    if (!m_hasCachedRelativePosition)
175        computeRelativePosition();
176    return m_layerLocation.x();
177}
178
179int MouseRelatedEvent::layerY()
180{
181    if (!m_hasCachedRelativePosition)
182        computeRelativePosition();
183    return m_layerLocation.y();
184}
185
186int MouseRelatedEvent::offsetX()
187{
188    if (isSimulated())
189        return 0;
190    if (!m_hasCachedRelativePosition)
191        computeRelativePosition();
192    return roundToInt(m_offsetLocation.x());
193}
194
195int MouseRelatedEvent::offsetY()
196{
197    if (isSimulated())
198        return 0;
199    if (!m_hasCachedRelativePosition)
200        computeRelativePosition();
201    return roundToInt(m_offsetLocation.y());
202}
203
204int MouseRelatedEvent::pageX() const
205{
206    return m_pageLocation.x();
207}
208
209int MouseRelatedEvent::pageY() const
210{
211    return m_pageLocation.y();
212}
213
214int MouseRelatedEvent::x() const
215{
216    // FIXME: This is not correct.
217    // See Microsoft documentation and <http://www.quirksmode.org/dom/w3c_events.html>.
218    return m_clientLocation.x();
219}
220
221int MouseRelatedEvent::y() const
222{
223    // FIXME: This is not correct.
224    // See Microsoft documentation and <http://www.quirksmode.org/dom/w3c_events.html>.
225    return m_clientLocation.y();
226}
227
228void MouseRelatedEvent::trace(Visitor* visitor)
229{
230    UIEventWithKeyState::trace(visitor);
231}
232
233} // namespace blink
234