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 "third_party/blink/renderer/core/events/mouse_event.h"
24 
25 #include "third_party/blink/public/common/input/web_pointer_properties.h"
26 #include "third_party/blink/renderer/bindings/core/v8/v8_mouse_event_init.h"
27 #include "third_party/blink/renderer/core/dom/element.h"
28 #include "third_party/blink/renderer/core/dom/events/event_dispatcher.h"
29 #include "third_party/blink/renderer/core/dom/events/event_path.h"
30 #include "third_party/blink/renderer/core/event_interface_names.h"
31 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
32 #include "third_party/blink/renderer/core/frame/local_frame.h"
33 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
34 #include "third_party/blink/renderer/core/input/input_device_capabilities.h"
35 #include "third_party/blink/renderer/core/layout/layout_object.h"
36 #include "third_party/blink/renderer/core/layout/layout_view.h"
37 #include "third_party/blink/renderer/core/page/page.h"
38 #include "third_party/blink/renderer/core/page/pointer_lock_controller.h"
39 #include "third_party/blink/renderer/core/paint/paint_layer.h"
40 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
41 #include "third_party/blink/renderer/core/svg/svg_element.h"
42 #include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
43 #include "third_party/blink/renderer/platform/bindings/script_state.h"
44 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
45 
46 namespace blink {
47 
48 namespace {
49 
ContentsScrollOffset(AbstractView * abstract_view)50 DoubleSize ContentsScrollOffset(AbstractView* abstract_view) {
51   auto* local_dom_window = DynamicTo<LocalDOMWindow>(abstract_view);
52   if (!local_dom_window)
53     return DoubleSize();
54   LocalFrame* frame = local_dom_window->GetFrame();
55   if (!frame)
56     return DoubleSize();
57   ScrollableArea* scrollable_area = frame->View()->LayoutViewport();
58   if (!scrollable_area)
59     return DoubleSize();
60   float scale_factor = frame->PageZoomFactor();
61   return DoubleSize(scrollable_area->ScrollOffsetInt().Width() / scale_factor,
62                     scrollable_area->ScrollOffsetInt().Height() / scale_factor);
63 }
64 
PageZoomFactor(const UIEvent * event)65 float PageZoomFactor(const UIEvent* event) {
66   auto* local_dom_window = DynamicTo<LocalDOMWindow>(event->view());
67   if (!local_dom_window)
68     return 1;
69   LocalFrame* frame = local_dom_window->GetFrame();
70   if (!frame)
71     return 1;
72   return frame->PageZoomFactor();
73 }
74 
FindTargetLayoutObject(Node * & target_node)75 const LayoutObject* FindTargetLayoutObject(Node*& target_node) {
76   LayoutObject* layout_object = target_node->GetLayoutObject();
77   if (!layout_object || !layout_object->IsSVG())
78     return layout_object;
79   // If this is an SVG node, compute the offset to the padding box of the
80   // outermost SVG root (== the closest ancestor that has a CSS layout box.)
81   while (!layout_object->IsSVGRoot())
82     layout_object = layout_object->Parent();
83   // Update the target node to point to the SVG root.
84   target_node = layout_object->GetNode();
85   auto* svg_element = DynamicTo<SVGElement>(target_node);
86   DCHECK(!target_node ||
87          (svg_element && svg_element->IsOutermostSVGSVGElement()));
88   return layout_object;
89 }
90 
ButtonsToWebInputEventModifiers(uint16_t buttons)91 unsigned ButtonsToWebInputEventModifiers(uint16_t buttons) {
92   unsigned modifiers = 0;
93 
94   if (buttons & static_cast<uint16_t>(WebPointerProperties::Buttons::kLeft))
95     modifiers |= WebInputEvent::kLeftButtonDown;
96   if (buttons & static_cast<uint16_t>(WebPointerProperties::Buttons::kRight))
97     modifiers |= WebInputEvent::kRightButtonDown;
98   if (buttons & static_cast<uint16_t>(WebPointerProperties::Buttons::kMiddle))
99     modifiers |= WebInputEvent::kMiddleButtonDown;
100   if (buttons & static_cast<uint16_t>(WebPointerProperties::Buttons::kBack))
101     modifiers |= WebInputEvent::kBackButtonDown;
102   if (buttons & static_cast<uint16_t>(WebPointerProperties::Buttons::kForward))
103     modifiers |= WebInputEvent::kForwardButtonDown;
104 
105   return modifiers;
106 }
107 
108 }  // namespace
109 
Create(ScriptState * script_state,const AtomicString & type,const MouseEventInit * initializer)110 MouseEvent* MouseEvent::Create(ScriptState* script_state,
111                                const AtomicString& type,
112                                const MouseEventInit* initializer) {
113   if (script_state && script_state->World().IsIsolatedWorld()) {
114     UIEventWithKeyState::DidCreateEventInIsolatedWorld(
115         initializer->ctrlKey(), initializer->altKey(), initializer->shiftKey(),
116         initializer->metaKey());
117   }
118   return MakeGarbageCollected<MouseEvent>(type, initializer);
119 }
120 
Create(const AtomicString & event_type,const MouseEventInit * initializer,base::TimeTicks platform_time_stamp,SyntheticEventType synthetic_event_type,WebMenuSourceType menu_source_type)121 MouseEvent* MouseEvent::Create(const AtomicString& event_type,
122                                const MouseEventInit* initializer,
123                                base::TimeTicks platform_time_stamp,
124                                SyntheticEventType synthetic_event_type,
125                                WebMenuSourceType menu_source_type) {
126   return MakeGarbageCollected<MouseEvent>(
127       event_type, initializer, platform_time_stamp, synthetic_event_type,
128       menu_source_type);
129 }
130 
Create(const AtomicString & event_type,AbstractView * view,const Event * underlying_event,SimulatedClickCreationScope creation_scope)131 MouseEvent* MouseEvent::Create(const AtomicString& event_type,
132                                AbstractView* view,
133                                const Event* underlying_event,
134                                SimulatedClickCreationScope creation_scope) {
135   WebInputEvent::Modifiers modifiers = WebInputEvent::kNoModifiers;
136   if (const UIEventWithKeyState* key_state_event =
137           FindEventWithKeyState(underlying_event)) {
138     modifiers = key_state_event->GetModifiers();
139   }
140 
141   SyntheticEventType synthetic_type = kPositionless;
142   MouseEventInit* initializer = MouseEventInit::Create();
143   if (const auto* mouse_event = DynamicTo<MouseEvent>(underlying_event)) {
144     synthetic_type = kRealOrIndistinguishable;
145     initializer->setScreenX(mouse_event->screenX());
146     initializer->setScreenY(mouse_event->screenY());
147     initializer->setSourceCapabilities(
148         view ? view->GetInputDeviceCapabilities()->FiresTouchEvents(false)
149              : nullptr);
150   }
151 
152   initializer->setBubbles(true);
153   initializer->setCancelable(true);
154   initializer->setView(view);
155   initializer->setComposed(true);
156   UIEventWithKeyState::SetFromWebInputEventModifiers(initializer, modifiers);
157   initializer->setButtons(
158       MouseEvent::WebInputEventModifiersToButtons(modifiers));
159 
160   base::TimeTicks timestamp = underlying_event
161                                   ? underlying_event->PlatformTimeStamp()
162                                   : base::TimeTicks::Now();
163   MouseEvent* created_event = MakeGarbageCollected<MouseEvent>(
164       event_type, initializer, timestamp, synthetic_type);
165 
166   created_event->SetTrusted(creation_scope ==
167                             SimulatedClickCreationScope::kFromUserAgent);
168   created_event->SetUnderlyingEvent(underlying_event);
169   if (synthetic_type == kRealOrIndistinguishable) {
170     auto* mouse_event = To<MouseEvent>(created_event->UnderlyingEvent());
171     created_event->InitCoordinates(mouse_event->clientX(),
172                                    mouse_event->clientY());
173   }
174 
175   return created_event;
176 }
177 
MouseEvent()178 MouseEvent::MouseEvent()
179     : position_type_(PositionType::kPosition),
180       button_(0),
181       buttons_(0),
182       related_target_(nullptr),
183       synthetic_event_type_(kRealOrIndistinguishable) {}
184 
MouseEvent(const AtomicString & event_type,const MouseEventInit * initializer,base::TimeTicks platform_time_stamp,SyntheticEventType synthetic_event_type,WebMenuSourceType menu_source_type)185 MouseEvent::MouseEvent(const AtomicString& event_type,
186                        const MouseEventInit* initializer,
187                        base::TimeTicks platform_time_stamp,
188                        SyntheticEventType synthetic_event_type,
189                        WebMenuSourceType menu_source_type)
190     : UIEventWithKeyState(event_type, initializer, platform_time_stamp),
191       screen_location_(
192           DoublePoint(initializer->screenX(), initializer->screenY())),
193       movement_delta_(
194           DoublePoint(initializer->movementX(), initializer->movementY())),
195       position_type_(synthetic_event_type == kPositionless
196                          ? PositionType::kPositionless
197                          : PositionType::kPosition),
198       button_(initializer->button()),
199       buttons_(initializer->buttons()),
200       related_target_(initializer->relatedTarget()),
201       synthetic_event_type_(synthetic_event_type),
202       region_(initializer->region()),
203       menu_source_type_(menu_source_type) {
204   InitCoordinates(initializer->clientX(), initializer->clientY());
205   modifiers_ |= ButtonsToWebInputEventModifiers(buttons_);
206 }
207 
InitCoordinates(const double client_x,const double client_y)208 void MouseEvent::InitCoordinates(const double client_x, const double client_y) {
209   // Set up initial values for coordinates.
210   // Correct values are computed lazily, see computeRelativePosition.
211   client_location_ = DoublePoint(client_x, client_y);
212   page_location_ = client_location_ + ContentsScrollOffset(view());
213 
214   layer_location_ = page_location_;
215   offset_location_ = page_location_;
216 
217   ComputePageLocation();
218   has_cached_relative_position_ = false;
219 }
220 
SetCoordinatesFromWebPointerProperties(const WebPointerProperties & web_pointer_properties,const LocalDOMWindow * dom_window,MouseEventInit * initializer)221 void MouseEvent::SetCoordinatesFromWebPointerProperties(
222     const WebPointerProperties& web_pointer_properties,
223     const LocalDOMWindow* dom_window,
224     MouseEventInit* initializer) {
225   FloatPoint client_point;
226   FloatPoint screen_point(web_pointer_properties.PositionInScreen());
227   float scale_factor = 1.0f;
228   if (dom_window && dom_window->GetFrame() && dom_window->GetFrame()->View()) {
229     LocalFrame* frame = dom_window->GetFrame();
230     FloatPoint root_frame_point(web_pointer_properties.PositionInWidget());
231     if (Page* p = frame->GetPage()) {
232       if (p->GetPointerLockController().GetElement() &&
233           !p->GetPointerLockController().LockPending()) {
234         p->GetPointerLockController().GetPointerLockPosition(&root_frame_point,
235                                                              &screen_point);
236       }
237     }
238     FloatPoint frame_point =
239         frame->View()->ConvertFromRootFrame(root_frame_point);
240     scale_factor = 1.0f / frame->PageZoomFactor();
241     client_point = frame_point.ScaledBy(scale_factor);
242   }
243 
244   initializer->setScreenX(screen_point.X());
245   initializer->setScreenY(screen_point.Y());
246   initializer->setClientX(client_point.X());
247   initializer->setClientY(client_point.Y());
248 
249   // TODO(crbug.com/982379): We need to merge the code path of raw movement
250   // events and regular events so that we can remove the block below.
251   if (web_pointer_properties.is_raw_movement_event ||
252       !RuntimeEnabledFeatures::ConsolidatedMovementXYEnabled()) {
253     // TODO(nzolghadr): We need to scale movement attrinutes as well. But if we
254     // do that here and round it to the int again it causes inconsistencies
255     // between screenX/Y and cumulative movementX/Y.
256     initializer->setMovementX(web_pointer_properties.movement_x);
257     initializer->setMovementY(web_pointer_properties.movement_y);
258   }
259 }
260 
261 MouseEvent::~MouseEvent() = default;
262 
WebInputEventModifiersToButtons(unsigned modifiers)263 uint16_t MouseEvent::WebInputEventModifiersToButtons(unsigned modifiers) {
264   uint16_t buttons = 0;
265 
266   if (modifiers & WebInputEvent::kLeftButtonDown)
267     buttons |= static_cast<uint16_t>(WebPointerProperties::Buttons::kLeft);
268   if (modifiers & WebInputEvent::kRightButtonDown) {
269     buttons |= static_cast<uint16_t>(WebPointerProperties::Buttons::kRight);
270   }
271   if (modifiers & WebInputEvent::kMiddleButtonDown) {
272     buttons |= static_cast<uint16_t>(WebPointerProperties::Buttons::kMiddle);
273   }
274   if (modifiers & WebInputEvent::kBackButtonDown)
275     buttons |= static_cast<uint16_t>(WebPointerProperties::Buttons::kBack);
276   if (modifiers & WebInputEvent::kForwardButtonDown) {
277     buttons |= static_cast<uint16_t>(WebPointerProperties::Buttons::kForward);
278   }
279 
280   return buttons;
281 }
282 
initMouseEvent(ScriptState * script_state,const AtomicString & type,bool bubbles,bool cancelable,AbstractView * view,int detail,int screen_x,int screen_y,int client_x,int client_y,bool ctrl_key,bool alt_key,bool shift_key,bool meta_key,int16_t button,EventTarget * related_target,uint16_t buttons)283 void MouseEvent::initMouseEvent(ScriptState* script_state,
284                                 const AtomicString& type,
285                                 bool bubbles,
286                                 bool cancelable,
287                                 AbstractView* view,
288                                 int detail,
289                                 int screen_x,
290                                 int screen_y,
291                                 int client_x,
292                                 int client_y,
293                                 bool ctrl_key,
294                                 bool alt_key,
295                                 bool shift_key,
296                                 bool meta_key,
297                                 int16_t button,
298                                 EventTarget* related_target,
299                                 uint16_t buttons) {
300   if (IsBeingDispatched())
301     return;
302 
303   if (script_state && script_state->World().IsIsolatedWorld())
304     UIEventWithKeyState::DidCreateEventInIsolatedWorld(ctrl_key, alt_key,
305                                                        shift_key, meta_key);
306 
307   InitModifiers(ctrl_key, alt_key, shift_key, meta_key);
308   InitMouseEventInternal(type, bubbles, cancelable, view, detail, screen_x,
309                          screen_y, client_x, client_y, GetModifiers(), button,
310                          related_target, nullptr, buttons);
311 }
312 
InitMouseEventInternal(const AtomicString & type,bool bubbles,bool cancelable,AbstractView * view,int detail,double screen_x,double screen_y,double client_x,double client_y,WebInputEvent::Modifiers modifiers,int16_t button,EventTarget * related_target,InputDeviceCapabilities * source_capabilities,uint16_t buttons)313 void MouseEvent::InitMouseEventInternal(
314     const AtomicString& type,
315     bool bubbles,
316     bool cancelable,
317     AbstractView* view,
318     int detail,
319     double screen_x,
320     double screen_y,
321     double client_x,
322     double client_y,
323     WebInputEvent::Modifiers modifiers,
324     int16_t button,
325     EventTarget* related_target,
326     InputDeviceCapabilities* source_capabilities,
327     uint16_t buttons) {
328   InitUIEventInternal(type, bubbles, cancelable, related_target, view, detail,
329                       source_capabilities);
330 
331   screen_location_ = DoublePoint(screen_x, screen_y);
332   button_ = button;
333   buttons_ = buttons;
334   related_target_ = related_target;
335   modifiers_ = modifiers;
336 
337   InitCoordinates(client_x, client_y);
338 
339   // FIXME: SyntheticEventType is not set to RealOrIndistinguishable here.
340 }
341 
InterfaceName() const342 const AtomicString& MouseEvent::InterfaceName() const {
343   return event_interface_names::kMouseEvent;
344 }
345 
IsMouseEvent() const346 bool MouseEvent::IsMouseEvent() const {
347   return true;
348 }
349 
button() const350 int16_t MouseEvent::button() const {
351   const AtomicString& event_name = type();
352   if (button_ == -1 || event_name == event_type_names::kMousemove ||
353       event_name == event_type_names::kMouseleave ||
354       event_name == event_type_names::kMouseenter ||
355       event_name == event_type_names::kMouseover ||
356       event_name == event_type_names::kMouseout) {
357     return 0;
358   }
359   return button_;
360 }
361 
which() const362 unsigned MouseEvent::which() const {
363   // For the DOM, the return values for left, middle and right mouse buttons are
364   // 0, 1, 2, respectively.
365   // For the Netscape "which" property, the return values for left, middle and
366   // right mouse buttons are 1, 2, 3, respectively.
367   // So we must add 1.
368   return (unsigned)(button_ + 1);
369 }
370 
toElement() const371 Node* MouseEvent::toElement() const {
372   // MSIE extension - "the object toward which the user is moving the mouse
373   // pointer"
374   if (type() == event_type_names::kMouseout ||
375       type() == event_type_names::kMouseleave)
376     return relatedTarget() ? relatedTarget()->ToNode() : nullptr;
377 
378   return target() ? target()->ToNode() : nullptr;
379 }
380 
fromElement() const381 Node* MouseEvent::fromElement() const {
382   // MSIE extension - "object from which activation or the mouse pointer is
383   // exiting during the event" (huh?)
384   if (type() != event_type_names::kMouseout &&
385       type() != event_type_names::kMouseleave)
386     return relatedTarget() ? relatedTarget()->ToNode() : nullptr;
387 
388   return target() ? target()->ToNode() : nullptr;
389 }
390 
Trace(Visitor * visitor)391 void MouseEvent::Trace(Visitor* visitor) {
392   visitor->Trace(related_target_);
393   UIEventWithKeyState::Trace(visitor);
394 }
395 
DispatchEvent(EventDispatcher & dispatcher)396 DispatchEventResult MouseEvent::DispatchEvent(EventDispatcher& dispatcher) {
397   GetEventPath().AdjustForRelatedTarget(dispatcher.GetNode(), relatedTarget());
398 
399   bool is_click = type() == event_type_names::kClick;
400   bool send_to_disabled_form_controls =
401       RuntimeEnabledFeatures::SendMouseEventsDisabledFormControlsEnabled();
402 
403   if (send_to_disabled_form_controls && is_click &&
404       GetEventPath().DisabledFormControlExistsInPath()) {
405     return DispatchEventResult::kCanceledBeforeDispatch;
406   }
407 
408   if (!isTrusted())
409     return dispatcher.Dispatch();
410 
411   if (!send_to_disabled_form_controls &&
412       IsDisabledFormControl(&dispatcher.GetNode())) {
413     if (GetEventPath().HasEventListenersInPath(type())) {
414       UseCounter::Count(dispatcher.GetNode().GetDocument(),
415                         WebFeature::kDispatchMouseEventOnDisabledFormControl);
416       if (type() == event_type_names::kMousedown ||
417           type() == event_type_names::kMouseup) {
418         UseCounter::Count(
419             dispatcher.GetNode().GetDocument(),
420             WebFeature::kDispatchMouseUpDownEventOnDisabledFormControl);
421       }
422     }
423     return DispatchEventResult::kCanceledBeforeDispatch;
424   }
425 
426   if (type().IsEmpty())
427     return DispatchEventResult::kNotCanceled;  // Shouldn't happen.
428 
429   DCHECK(!target() || target() != relatedTarget());
430 
431   EventTarget* related_target = relatedTarget();
432 
433   DispatchEventResult dispatch_result = dispatcher.Dispatch();
434 
435   if (!is_click || detail() != 2)
436     return dispatch_result;
437 
438   // Special case: If it's a double click event, we also send the dblclick
439   // event. This is not part of the DOM specs, but is used for compatibility
440   // with the ondblclick="" attribute. This is treated as a separate event in
441   // other DOM-compliant browsers like Firefox, and so we do the same.
442   MouseEvent& double_click_event = *MouseEvent::Create();
443   double_click_event.InitMouseEventInternal(
444       event_type_names::kDblclick, bubbles(), cancelable(), view(), detail(),
445       screenX(), screenY(), clientX(), clientY(), GetModifiers(), button(),
446       related_target, sourceCapabilities(), buttons());
447   double_click_event.SetComposed(composed());
448 
449   // Inherit the trusted status from the original event.
450   double_click_event.SetTrusted(isTrusted());
451   if (DefaultHandled())
452     double_click_event.SetDefaultHandled();
453   DispatchEventResult double_click_dispatch_result =
454       EventDispatcher::DispatchEvent(dispatcher.GetNode(), double_click_event);
455   if (double_click_dispatch_result != DispatchEventResult::kNotCanceled)
456     return double_click_dispatch_result;
457   return dispatch_result;
458 }
459 
ComputePageLocation()460 void MouseEvent::ComputePageLocation() {
461   auto* local_dom_window = DynamicTo<LocalDOMWindow>(view());
462   LocalFrame* frame = local_dom_window ? local_dom_window->GetFrame() : nullptr;
463   DoublePoint scaled_page_location =
464       page_location_.ScaledBy(PageZoomFactor(this));
465   if (frame && frame->View()) {
466     absolute_location_ = frame->View()->DocumentToFrame(scaled_page_location);
467   } else {
468     absolute_location_ = scaled_page_location;
469   }
470 }
471 
ReceivedTarget()472 void MouseEvent::ReceivedTarget() {
473   has_cached_relative_position_ = false;
474 }
475 
ComputeRelativePosition()476 void MouseEvent::ComputeRelativePosition() {
477   Node* target_node = target() ? target()->ToNode() : nullptr;
478   if (!target_node)
479     return;
480 
481   // Compute coordinates that are based on the target.
482   layer_location_ = page_location_;
483   offset_location_ = page_location_;
484   float inverse_zoom_factor = 1 / PageZoomFactor(this);
485 
486   // Must have an updated layout tree for this math to work correctly.
487   target_node->GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kInput);
488 
489   // Adjust offsetLocation to be relative to the target's padding box.
490   if (const LayoutObject* layout_object = FindTargetLayoutObject(target_node)) {
491     FloatPoint local_pos = layout_object->AbsoluteToLocalFloatPoint(
492         FloatPoint(AbsoluteLocation()));
493 
494     // Adding this here to address crbug.com/570666. Basically we'd like to
495     // find the local coordinates relative to the padding box not the border
496     // box.
497     if (layout_object->IsBoxModelObject()) {
498       const LayoutBoxModelObject* layout_box =
499           ToLayoutBoxModelObject(layout_object);
500       local_pos.Move(-layout_box->BorderLeft(), -layout_box->BorderTop());
501     }
502 
503     offset_location_ = DoublePoint(local_pos);
504     if (inverse_zoom_factor != 1.0f)
505       offset_location_.Scale(inverse_zoom_factor, inverse_zoom_factor);
506   }
507 
508   // Adjust layerLocation to be relative to the layer.
509   // FIXME: event.layerX and event.layerY are poorly defined,
510   // and probably don't always correspond to PaintLayer offsets.
511   // https://bugs.webkit.org/show_bug.cgi?id=21868
512   Node* n = target_node;
513   while (n && !n->GetLayoutObject())
514     n = n->parentNode();
515 
516   if (n) {
517     DoublePoint scaled_page_location =
518         page_location_.ScaledBy(PageZoomFactor(this));
519     if (LocalFrameView* view = n->GetLayoutObject()->View()->GetFrameView())
520       layer_location_ = view->DocumentToFrame(scaled_page_location);
521 
522     PaintLayer* layer = n->GetLayoutObject()->EnclosingLayer();
523 
524     PhysicalOffset physical_offset;
525     layer->ConvertToLayerCoords(nullptr, physical_offset);
526     layer_location_ -= DoubleSize(physical_offset.left.ToDouble(),
527                                   physical_offset.top.ToDouble());
528 
529     if (inverse_zoom_factor != 1.0f)
530       layer_location_.Scale(inverse_zoom_factor, inverse_zoom_factor);
531   }
532 
533   has_cached_relative_position_ = true;
534 }
535 
layerX()536 int MouseEvent::layerX() {
537   if (!has_cached_relative_position_)
538     ComputeRelativePosition();
539 
540   // TODO(mustaq): Remove the PointerEvent specific code when mouse has
541   // fractional coordinates. See crbug.com/655786.
542 
543   return IsPointerEvent() ? layer_location_.X()
544                           : static_cast<int>(layer_location_.X());
545 }
546 
layerY()547 int MouseEvent::layerY() {
548   if (!has_cached_relative_position_)
549     ComputeRelativePosition();
550 
551   // TODO(mustaq): Remove the PointerEvent specific code when mouse has
552   // fractional coordinates. See crbug.com/655786.
553 
554   return IsPointerEvent() ? layer_location_.Y()
555                           : static_cast<int>(layer_location_.Y());
556 }
557 
offsetX() const558 double MouseEvent::offsetX() const {
559   if (!HasPosition())
560     return 0;
561   if (!has_cached_relative_position_)
562     const_cast<MouseEvent*>(this)->ComputeRelativePosition();
563   return std::round(offset_location_.X());
564 }
565 
offsetY() const566 double MouseEvent::offsetY() const {
567   if (!HasPosition())
568     return 0;
569   if (!has_cached_relative_position_)
570     const_cast<MouseEvent*>(this)->ComputeRelativePosition();
571   return std::round(offset_location_.Y());
572 }
573 
574 }  // namespace blink
575