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