text: // Copyright 2013 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "third_party/blink/public/common/input/synthetic_web_input_event_builders.h"
  
  #include "base/check_op.h"
  #include "ui/events/base_event_utils.h"
  
  namespace blink {
  
  WebMouseEvent SyntheticWebMouseEventBuilder::Build(
      blink::WebInputEvent::Type type) {
    return WebMouseEvent(type, WebInputEvent::kNoModifiers,
                         WebInputEvent::GetStaticTimeStampForTests());
  }
  
  WebMouseEvent SyntheticWebMouseEventBuilder::Build(
      blink::WebInputEvent::Type type,
      float window_x,
      float window_y,
      int modifiers,
      blink::WebPointerProperties::PointerType pointer_type) {
    DCHECK(WebInputEvent::IsMouseEventType(type));
    WebMouseEvent result(type, modifiers,
                         WebInputEvent::GetStaticTimeStampForTests());
    result.SetPositionInWidget(window_x, window_y);
    result.SetPositionInScreen(window_x, window_y);
    result.SetModifiers(modifiers);
    result.pointer_type = pointer_type;
    result.id = WebMouseEvent::kMousePointerId;
    return result;
  }
  
  WebMouseWheelEvent SyntheticWebMouseWheelEventBuilder::Build(
      WebMouseWheelEvent::Phase phase) {
    WebMouseWheelEvent result(WebInputEvent::Type::kMouseWheel,
                              WebInputEvent::kNoModifiers,
                              WebInputEvent::GetStaticTimeStampForTests());
    result.phase = phase;
    result.event_action =
        WebMouseWheelEvent::GetPlatformSpecificDefaultEventAction(result);
    return result;
  }
  
  WebMouseWheelEvent SyntheticWebMouseWheelEventBuilder::Build(
      float x,
      float y,
      float dx,
      float dy,
      int modifiers,
      ui::ScrollGranularity delta_units) {
    return Build(x, y, 0, 0, dx, dy, modifiers, delta_units);
  }
  
  WebMouseWheelEvent SyntheticWebMouseWheelEventBuilder::Build(
      float x,
      float y,
      float global_x,
      float global_y,
      float dx,
      float dy,
      int modifiers,
      ui::ScrollGranularity delta_units) {
    WebMouseWheelEvent result(WebInputEvent::Type::kMouseWheel, modifiers,
                              WebInputEvent::GetStaticTimeStampForTests());
    result.SetPositionInScreen(global_x, global_y);
    result.SetPositionInWidget(x, y);
    result.delta_units = delta_units;
    result.delta_x = dx;
    result.delta_y = dy;
    if (dx)
      result.wheel_ticks_x = dx > 0.0f ? 1.0f : -1.0f;
    if (dy)
      result.wheel_ticks_y = dy > 0.0f ? 1.0f : -1.0f;
  
    result.event_action =
        WebMouseWheelEvent::GetPlatformSpecificDefaultEventAction(result);
    return result;
  }
  
  WebGestureEvent SyntheticWebGestureEventBuilder::Build(
      WebInputEvent::Type type,
      blink::WebGestureDevice source_device,
      int modifiers) {
    DCHECK(WebInputEvent::IsGestureEventType(type));
    WebGestureEvent result(type, modifiers,
                           WebInputEvent::GetStaticTimeStampForTests(),
                           source_device);
    if (type == WebInputEvent::Type::kGestureTap ||
        type == WebInputEvent::Type::kGestureTapUnconfirmed ||
        type == WebInputEvent::Type::kGestureDoubleTap) {
      result.data.tap.tap_count = 1;
      result.data.tap.width = 10;
      result.data.tap.height = 10;
    }
  
    result.SetNeedsWheelEvent(result.IsTouchpadZoomEvent());
  
    return result;
  }
  
  WebGestureEvent SyntheticWebGestureEventBuilder::BuildScrollBegin(
      float dx_hint,
      float dy_hint,
      blink::WebGestureDevice source_device,
      int pointer_count) {
    WebGestureEvent result =
        Build(WebInputEvent::Type::kGestureScrollBegin, source_device);
    result.data.scroll_begin.delta_x_hint = dx_hint;
    result.data.scroll_begin.delta_y_hint = dy_hint;
    result.data.scroll_begin.pointer_count = pointer_count;
    return result;
  }
  
  WebGestureEvent SyntheticWebGestureEventBuilder::BuildScrollUpdate(
      float dx,
      float dy,
      int modifiers,
      blink::WebGestureDevice source_device) {
    WebGestureEvent result = Build(WebInputEvent::Type::kGestureScrollUpdate,
                                   source_device, modifiers);
    result.data.scroll_update.delta_x = dx;
    result.data.scroll_update.delta_y = dy;
    return result;
  }
  
  WebGestureEvent SyntheticWebGestureEventBuilder::BuildPinchUpdate(
      float scale,
      float anchor_x,
      float anchor_y,
      int modifiers,
      blink::WebGestureDevice source_device) {
    WebGestureEvent result =
        Build(WebInputEvent::Type::kGesturePinchUpdate, source_device, modifiers);
    result.data.pinch_update.scale = scale;
    result.SetPositionInWidget(gfx::PointF(anchor_x, anchor_y));
    result.SetPositionInScreen(gfx::PointF(anchor_x, anchor_y));
    return result;
  }
  
  WebGestureEvent SyntheticWebGestureEventBuilder::BuildFling(
      float velocity_x,
      float velocity_y,
      blink::WebGestureDevice source_device) {
    WebGestureEvent result =
        Build(WebInputEvent::Type::kGestureFlingStart, source_device);
    result.data.fling_start.velocity_x = velocity_x;
    result.data.fling_start.velocity_y = velocity_y;
    return result;
  }
  
  SyntheticWebTouchEvent::SyntheticWebTouchEvent() : WebTouchEvent() {
    unique_touch_event_id = ui::GetNextTouchEventId();
    SetTimestamp(WebInputEvent::GetStaticTimeStampForTests());
    pointer_id_ = 0;
  }
  
  void SyntheticWebTouchEvent::ResetPoints() {
    int activePointCount = 0;
    unsigned count = 0;
    for (unsigned int i = 0; i < kTouchesLengthCap; ++i) {
      switch (touches[i].state) {
        case WebTouchPoint::State::kStatePressed:
        case WebTouchPoint::State::kStateMoved:
        case WebTouchPoint::State::kStateStationary:
          touches[i].state = WebTouchPoint::State::kStateStationary;
          ++activePointCount;
          ++count;
          break;
        case WebTouchPoint::State::kStateReleased:
        case WebTouchPoint::State::kStateCancelled:
          touches[i] = WebTouchPoint();
          ++count;
          break;
        case WebTouchPoint::State::kStateUndefined:
          break;
      }
      if (count >= touches_length)
        break;
    }
    touches_length = activePointCount;
    type_ = WebInputEvent::Type::kUndefined;
    moved_beyond_slop_region = false;
    unique_touch_event_id = ui::GetNextTouchEventId();
  }
  
  int SyntheticWebTouchEvent::PressPoint(float x,
                                         float y,
                                         float radius_x,
                                         float radius_y,
                                         float rotation_angle,
                                         float force) {
    int index = FirstFreeIndex();
    if (index == -1)
      return -1;
    WebTouchPoint& point = touches[index];
    point.id = pointer_id_++;
    point.SetPositionInWidget(x, y);
    point.SetPositionInScreen(x, y);
    point.state = WebTouchPoint::State::kStatePressed;
    point.radius_x = radius_x;
    point.radius_y = radius_y;
    point.rotation_angle = rotation_angle;
    point.force = force;
    point.tilt_x = point.tilt_y = 0;
    point.pointer_type = blink::WebPointerProperties::PointerType::kTouch;
    ++touches_length;
    SetType(WebInputEvent::Type::kTouchStart);
    dispatch_type = WebInputEvent::DispatchType::kBlocking;
    return index;
  }
  
  void SyntheticWebTouchEvent::MovePoint(int index,
                                         float x,
                                         float y,
                                         float radius_x,
                                         float radius_y,
                                         float rotation_angle,
                                         float force) {
    CHECK_GE(index, 0);
    CHECK_LT(index, kTouchesLengthCap);
    // Always set this bit to avoid otherwise unexpected touchmove suppression.
    // The caller can opt-out explicitly, if necessary.
    moved_beyond_slop_region = true;
    WebTouchPoint& point = touches[index];
    point.SetPositionInWidget(x, y);
    point.SetPositionInScreen(x, y);
    point.state = WebTouchPoint::State::kStateMoved;
    point.radius_x = radius_x;
    point.radius_y = radius_y;
    point.rotation_angle = rotation_angle;
    point.force = force;
    SetType(WebInputEvent::Type::kTouchMove);
    dispatch_type = WebInputEvent::DispatchType::kBlocking;
  }
  
  void SyntheticWebTouchEvent::ReleasePoint(int index) {
    CHECK_GE(index, 0);
    CHECK_LT(index, kTouchesLengthCap);
    touches[index].state = WebTouchPoint::State::kStateReleased;
    touches[index].force = 0.f;
    SetType(WebInputEvent::Type::kTouchEnd);
    dispatch_type = WebInputEvent::DispatchType::kBlocking;
  }
  
  void SyntheticWebTouchEvent::CancelPoint(int index) {
    CHECK_GE(index, 0);
    CHECK_LT(index, kTouchesLengthCap);
    touches[index].state = WebTouchPoint::State::kStateCancelled;
    SetType(WebInputEvent::Type::kTouchCancel);
    dispatch_type = WebInputEvent::DispatchType::kEventNonBlocking;
  }
  
  void SyntheticWebTouchEvent::SetTimestamp(base::TimeTicks timestamp) {
    SetTimeStamp(timestamp);
  }
  
  int SyntheticWebTouchEvent::FirstFreeIndex() {
    for (size_t i = 0; i < kTouchesLengthCap; ++i) {
      if (touches[i].state == WebTouchPoint::State::kStateUndefined)
        return i;
    }
    return -1;
  }
  
  }  // namespace blink
  