text:
// Copyright 2016 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/renderer/core/input/scroll_manager.h"

#include <utility>

#include "cc/input/main_thread_scrolling_reason.h"
#include "cc/input/snap_selection_strategy.h"
#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/events/gesture_event.h"
#include "third_party/blink/renderer/core/frame/browser_controls.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
#include "third_party/blink/renderer/core/input/event_handling_util.h"
#include "third_party/blink/renderer/core/layout/layout_block.h"
#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/page/autoscroll_controller.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/page/scrolling/overscroll_controller.h"
#include "third_party/blink/renderer/core/page/scrolling/root_scroller_controller.h"
#include "third_party/blink/renderer/core/page/scrolling/scroll_state.h"
#include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/core/scroll/scroll_animator_base.h"
#include "third_party/blink/renderer/core/scroll/scroll_customization.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/widget/input/input_metrics.h"
#include "ui/gfx/geometry/point_conversions.h"

namespace blink {
namespace {

cc::SnapFlingController::GestureScrollType ToGestureScrollType(
    WebInputEvent::Type web_event_type) {
  switch (web_event_type) {
    case WebInputEvent::Type::kGestureScrollBegin:
      return cc::SnapFlingController::GestureScrollType::kBegin;
    case WebInputEvent::Type::kGestureScrollUpdate:
      return cc::SnapFlingController::GestureScrollType::kUpdate;
    case WebInputEvent::Type::kGestureScrollEnd:
      return cc::SnapFlingController::GestureScrollType::kEnd;
    default:
      NOTREACHED();
      return cc::SnapFlingController::GestureScrollType::kBegin;
  }
}

cc::SnapFlingController::GestureScrollUpdateInfo GetGestureScrollUpdateInfo(
    const WebGestureEvent& event) {
  return {
      .delta = gfx::Vector2dF(-event.data.scroll_update.delta_x,
                              -event.data.scroll_update.delta_y),
      .is_in_inertial_phase = event.data.scroll_update.inertial_phase ==
                              WebGestureEvent::InertialPhaseState::kMomentum,
      .event_time = event.TimeStamp()};
}
}  // namespace

ScrollManager::ScrollManager(LocalFrame& frame) : frame_(frame) {
  snap_fling_controller_ = std::make_unique<cc::SnapFlingController>(this);

  Clear();
}

void ScrollManager::Clear() {
  scrollbar_handling_scroll_gesture_ = nullptr;
  resize_scrollable_area_ = nullptr;
  offset_from_resize_corner_ = LayoutSize();
  ClearGestureScrollState();
}

void ScrollManager::Trace(Visitor* visitor) const {
  visitor->Trace(frame_);
  visitor->Trace(scroll_gesture_handling_node_);
  visitor->Trace(previous_gesture_scrolled_node_);
  visitor->Trace(scrollbar_handling_scroll_gesture_);
  visitor->Trace(resize_scrollable_area_);
}

void ScrollManager::ClearGestureScrollState() {
  last_gesture_scroll_over_embedded_content_view_ = false;
  scroll_gesture_handling_node_ = nullptr;
  previous_gesture_scrolled_node_ = nullptr;
  last_scroll_delta_for_scroll_gesture_ = ScrollOffset();
  delta_consumed_for_scroll_sequence_ = false;
  did_scroll_x_for_scroll_gesture_ = false;
  did_scroll_y_for_scroll_gesture_ = false;
  current_scroll_chain_.clear();

  if (Page* page = frame_->GetPage()) {
    bool reset_x = true;
    bool reset_y = true;
    page->GetOverscrollController().ResetAccumulated(reset_x, reset_y);
  }
}

Node* ScrollManager::GetScrollEventTarget() {
  // Send the overscroll event to the node that scrolling is latched to which
  // is either previously scrolled node or the last node in the scroll chain.
  Node* scroll_target = previous_gesture_scrolled_node_;
  if (!scroll_target && !current_scroll_chain_.IsEmpty())
    scroll_target = DOMNodeIds::NodeForId(current_scroll_chain_.front());
  return scroll_target;
}

void ScrollManager::StopAutoscroll() {
  if (AutoscrollController* controller = GetAutoscrollController())
    controller->StopAutoscroll();
}

void ScrollManager::StopMiddleClickAutoscroll() {
  if (AutoscrollController* controller = GetAutoscrollController())
    controller->StopMiddleClickAutoscroll(frame_);
}

bool ScrollManager::MiddleClickAutoscrollInProgress() const {
  return GetAutoscrollController() &&
         GetAutoscrollController()->MiddleClickAutoscrollInProgress();
}

AutoscrollController* ScrollManager::GetAutoscrollController() const {
  if (Page* page = frame_->GetPage())
    return &page->GetAutoscrollController();
  return nullptr;
}

ScrollPropagationDirection ScrollManager::ComputePropagationDirection(
    const ScrollState& scroll_state) {
  if (scroll_state.deltaXHint() == 0 && scroll_state.deltaYHint() != 0)
    return ScrollPropagationDirection::kVertical;
  if (scroll_state.deltaXHint() != 0 && scroll_state.deltaYHint() == 0)
    return ScrollPropagationDirection::kHorizontal;
  if (scroll_state.deltaXHint() != 0 && scroll_state.deltaYHint() != 0)
    return ScrollPropagationDirection::kBoth;
  return ScrollPropagationDirection::kNone;
}

bool ScrollManager::CanPropagate(const LayoutBox* layout_box,
                                 ScrollPropagationDirection direction) {
  ScrollableArea* scrollable_area = layout_box->GetScrollableArea();
  if (!scrollable_area)
    return true;

  if (!scrollable_area->UserInputScrollable(kHorizontalScrollbar) &&
      !scrollable_area->UserInputScrollable(kVerticalScrollbar))
    return true;

  switch (direction) {
    case ScrollPropagationDirection::kBoth:
      return ((layout_box->StyleRef().OverscrollBehaviorX() ==
               EOverscrollBehavior::kAuto) &&
              (layout_box->StyleRef().OverscrollBehaviorY() ==
               EOverscrollBehavior::kAuto));
    case ScrollPropagationDirection::kVertical:
      return layout_box->StyleRef().OverscrollBehaviorY() ==
             EOverscrollBehavior::kAuto;
    case ScrollPropagationDirection::kHorizontal:
      return layout_box->StyleRef().OverscrollBehaviorX() ==
             EOverscrollBehavior::kAuto;
    case ScrollPropagationDirection::kNone:
      return true;
    default:
      NOTREACHED();
  }
}

void ScrollManager::RecomputeScrollChain(const Node& start_node,
                                         const ScrollState& scroll_state,
                                         Deque<DOMNodeId>& scroll_chain,
                                         bool is_autoscroll) {
  DCHECK(scroll_chain.IsEmpty());
  scroll_chain.clear();

  DCHECK(start_node.GetLayoutObject());

  if (is_autoscroll) {
    // Propagate the autoscroll along the layout object chain, and
    // append only the first node which is able to consume the scroll delta.
    // The scroll node is computed differently to regular scrolls in order to
    // maintain consistency with the autoscroll controller.
    LayoutBox* autoscrollable = LayoutBox::FindAutoscrollable(
        start_node.GetLayoutObject(), is_autoscroll);
    if (autoscrollable) {
      Node* cur_node = autoscrollable->GetNode();
      LayoutObject* layout_object = cur_node->GetLayoutObject();
      while (layout_object &&
             !CanScroll(scroll_state, *cur_node, is_autoscroll)) {
        ScrollPropagationDirection direction =
            ComputePropagationDirection(scroll_state);

        if (!CanPropagate(cur_node->GetLayoutBox(), direction))
          break;

        if (!layout_object->Parent() &&
            layout_object->GetNode() == layout_object->GetDocument() &&
            layout_object->GetDocument().LocalOwner()) {
          layout_object =
              layout_object->GetDocument().LocalOwner()->GetLayoutObject();
        } else {
          layout_object = layout_object->Parent();
        }
        LayoutBox* new_autoscrollable =
            LayoutBox::FindAutoscrollable(layout_object, is_autoscroll);
        if (new_autoscrollable)
          cur_node = new_autoscrollable->GetNode();
      }
      scroll_chain.push_front(DOMNodeIds::IdForNode(cur_node));
    }
  } else {
    LayoutBox* cur_box = start_node.GetLayoutObject()->EnclosingBox();

    // Scrolling propagates along the containing block chain and ends at the
    // RootScroller node. The RootScroller node will have a custom applyScroll
    // callback that performs scrolling as well as associated "root" actions
    // like browser control movement and overscroll glow.
    while (cur_box) {
      Node* cur_node = cur_box->GetNode();

      if (cur_node) {
        if (CanScroll(scroll_state, *cur_node, /* for_autoscroll */ false))
          scroll_chain.push_front(DOMNodeIds::IdForNode(cur_node));

        if (cur_node->IsEffectiveRootScroller())
          break;

        ScrollPropagationDirection direction =
            ComputePropagationDirection(scroll_state);
        if (!CanPropagate(cur_node->GetLayoutBox(), direction)) {
          // We should add the first node with non-auto overscroll-behavior to
          // the scroll chain regardlessly, as it's the only node we can latch
          // to.
          if (scroll_chain.empty() ||
              scroll_chain.front() != DOMNodeIds::IdForNode(cur_node)) {
            scroll_chain.push_front(DOMNodeIds::IdForNode(cur_node));
          }
          break;
        }
      }

      cur_box = cur_box->ContainingBlock();
    }
  }
}

bool ScrollManager::CanScroll(const ScrollState& scroll_state,
                              const Node& current_node,
                              bool for_autoscroll) {
  LayoutBox* scrolling_box = current_node.GetLayoutBox();
  if (auto* element = DynamicTo<Element>(current_node))
    scrolling_box = element->GetLayoutBoxForScrolling();
  if (!scrolling_box)
    return false;

  // We need to always add the global root scroller even if it isn't scrollable
  // since we can always pinch-zoom and scroll as well as for overscroll
  // effects. If autoscrolling, ignore this condition because we latch on
  // to the deepest autoscrollable node.
  if (scrolling_box->IsGlobalRootScroller() && !for_autoscroll)
    return true;

  // If this is the main LayoutView, and it's not the root scroller, that means
  // we have a non-default root scroller on the page. In this case, attempts to
  // scroll the LayoutView should cause panning of the visual viewport as well
  // so ensure it gets added to the scroll chain. See LTHI::ApplyScroll for the
  // equivalent behavior in CC. Node::NativeApplyScroll contains a special
  // handler for this case. If autoscrolling, ignore this condition because we
  // latch on to the deepest autoscrollable node.
  if (IsA<LayoutView>(scrolling_box) &&
      current_node.GetDocument().GetFrame()->IsMainFrame() && !for_autoscroll) {
    return true;
  }

  ScrollableArea* scrollable_area = scrolling_box->GetScrollableArea();

  if (!scrollable_area)
    return false;

  double delta_x = scroll_state.isBeginning() ? scroll_state.deltaXHint()
                                              : scroll_state.deltaX();
  double delta_y = scroll_state.isBeginning() ? scroll_state.deltaYHint()
                                              : scroll_state.deltaY();
  if (!delta_x && !delta_y)
    return true;

  if (!scrollable_area->UserInputScrollable(kHorizontalScrollbar))
    delta_x = 0;
  if (!scrollable_area->UserInputScrollable(kVerticalScrollbar))
    delta_y = 0;

  if (scroll_state.deltaGranularity() ==
      static_cast<double>(ui::ScrollGranularity::kScrollByPercentage)) {
    delta_x *= scrollable_area->ScrollStep(
        ui::ScrollGranularity::kScrollByPercentage, kHorizontalScrollbar);
    delta_y *= scrollable_area->ScrollStep(
        ui::ScrollGranularity::kScrollByPercentage, kVerticalScrollbar);
  }

  ScrollOffset current_offset = scrollable_area->GetScrollOffset();
  ScrollOffset target_offset = current_offset + ScrollOffset(delta_x, delta_y);
  ScrollOffset clamped_offset =
      scrollable_area->ClampScrollOffset(target_offset);
  return clamped_offset != current_offset;
}

bool ScrollManager::LogicalScroll(mojom::blink::ScrollDirection direction,
                                  ui::ScrollGranularity granularity,
                                  Node* start_node,
                                  Node* mouse_press_node) {
  Node* node = start_node;

  if (!node)
    node = frame_->GetDocument()->FocusedElement();

  if (!node)
    node = mouse_press_node;

  if ((!node || !node->GetLayoutObject()) && frame_->View() &&
      frame_->View()->GetLayoutView())
    node = frame_->View()->GetLayoutView()->GetNode();

  if (!node)
    return false;

  Document& document = node->GetDocument();

  document.UpdateStyleAndLayout(DocumentUpdateReason::kScroll);

  Deque<DOMNodeId> scroll_chain;
  std::unique_ptr<ScrollStateData> scroll_state_data =
      std::make_unique<ScrollStateData>();
  auto* scroll_state =
      MakeGarbageCollected<ScrollState>(std::move(scroll_state_data));
  RecomputeScrollChain(*node, *scroll_state, scroll_chain,
                       /* is_autoscroll */ false);

  while (!scroll_chain.IsEmpty()) {
    Node* scroll_chain_node = DOMNodeIds::NodeForId(scroll_chain.TakeLast());
    DCHECK(scroll_chain_node);

    auto* box = To<LayoutBox>(scroll_chain_node->GetLayoutObject());
    DCHECK(box);

    ScrollDirectionPhysical physical_direction =
        ToPhysicalDirection(direction, box->IsHorizontalWritingMode(),
                            box->Style()->IsFlippedBlocksWritingMode());

    ScrollableArea* scrollable_area = ScrollableArea::GetForScrolling(box);
    DCHECK(scrollable_area);

    ScrollOffset delta =
        ToScrollDelta(physical_direction,
                      ScrollableArea::DirectionBasedScrollDelta(granularity));
    delta.Scale(scrollable_area->ScrollStep(granularity, kHorizontalScrollbar),
                scrollable_area->ScrollStep(granularity, kVerticalScrollbar));
    // Pressing the arrow key is considered as a scroll with intended direction
    // only (this results in kScrollByLine or kScrollByPercentage, depending on
    // REF::PercentBasedScrollingEnabled). Pressing the PgUp/PgDn key is
    // considered as a scroll with intended direction and end position. Pressing
    // the Home/End key is considered as a scroll with intended end position
    // only.
    switch (granularity) {
      case ui::ScrollGranularity::kScrollByLine:
      case ui::ScrollGranularity::kScrollByPercentage: {
        if (scrollable_area->SnapForDirection(delta))
          return true;
        break;
      }
      case ui::ScrollGranularity::kScrollByPage: {
        if (scrollable_area->SnapForEndAndDirection(delta))
          return true;
        break;
      }
      case ui::ScrollGranularity::kScrollByDocument: {
        gfx::PointF end_position = scrollable_area->ScrollPosition() + delta;
        bool scrolled_x = physical_direction == kScrollLeft ||
                          physical_direction == kScrollRight;
        bool scrolled_y = physical_direction == kScrollUp ||
                          physical_direction == kScrollDown;
        if (scrollable_area->SnapForEndPosition(end_position, scrolled_x,
                                                scrolled_y))
          return true;
        break;
      }
      default:
        NOTREACHED();
    }

    ScrollableArea::ScrollCallback callback(WTF::Bind(
        [](WeakPersistent<ScrollableArea> area) {
          if (area)
            area->OnScrollFinished();
        },
        WrapWeakPersistent(scrollable_area)));
    ScrollResult result = scrollable_area->UserScroll(
        granularity,
        ToScrollDelta(physical_direction,
                      ScrollableArea::DirectionBasedScrollDelta(granularity)),
        std::move(callback));

    if (result.DidScroll())
      return true;
  }

  return false;
}

// TODO(bokan): This should be merged with logicalScroll assuming
// defaultSpaceEventHandler's chaining scroll can be done crossing frames.
bool ScrollManager::BubblingScroll(mojom::blink::ScrollDirection direction,
                                   ui::ScrollGranularity granularity,
                                   Node* starting_node,
                                   Node* mouse_press_node) {
  // The layout needs to be up to date to determine if we can scroll. We may be
  // here because of an onLoad event, in which case the final layout hasn't been
  // performed yet.
  frame_->GetDocument()->UpdateStyleAndLayout(DocumentUpdateReason::kScroll);
  // FIXME: enable scroll customization in this case. See crbug.com/410974.
  if (LogicalScroll(direction, granularity, starting_node, mouse_press_node))
    return true;

  Frame* parent_frame = frame_->Tree().Parent();
  if (!parent_frame)
    return false;

  return parent_frame->BubbleLogicalScrollFromChildFrame(direction, granularity,
                                                         frame_);
}

void ScrollManager::CustomizedScroll(ScrollState& scroll_state) {
  TRACE_EVENT0("input", "ScrollManager::CustomizedScroll");
  if (scroll_state.FullyConsumed())
    return;

  if (scroll_state.deltaX() || scroll_state.deltaY()) {
    frame_->GetDocument()->UpdateStyleAndLayout(DocumentUpdateReason::kScroll);
  }

  DCHECK(!current_scroll_chain_.IsEmpty());

  scroll_state.SetScrollChain(current_scroll_chain_);

  scroll_state.distributeToScrollChainDescendant();
}

uint32_t ScrollManager::GetNonCompositedMainThreadScrollingReasons() const {
  // When scrolling on the main thread, the scrollableArea may or may not be
  // composited. Either way, we have recorded either the reasons stored in
  // its layer or the reason NonFastScrollableRegion from the compositor
  // side. Here we record scrolls that occurred on main thread due to a
  // non-composited scroller.
  if (!scroll_gesture_handling_node_->GetLayoutObject())
    return 0;

  uint32_t non_composited_main_thread_scrolling_reasons = 0;
  for (auto* cur_box =
           scroll_gesture_handling_node_->GetLayoutObject()->EnclosingBox();
       cur_box; cur_box = cur_box->ContainingBlock()) {
    PaintLayerScrollableArea* scrollable_area = cur_box->GetScrollableArea();

    if (!scrollable_area || !scrollable_area->ScrollsOverflow())
      continue;

    // TODO(bokan): This DCHECK is occasionally tripped. See crbug.com/944706.
    // DCHECK(!scrollable_area->UsesCompositedScrolling() ||
    //        !scrollable_area->GetNonCompositedMainThreadScrollingReasons());
    non_composited_main_thread_scrolling_reasons |=
        scrollable_area->GetNonCompositedMainThreadScrollingReasons();
  }
  return non_composited_main_thread_scrolling_reasons;
}

void ScrollManager::RecordScrollRelatedMetrics(WebGestureDevice device) const {
  if (device != WebGestureDevice::kTouchpad &&
      device != WebGestureDevice::kTouchscreen) {
    return;
  }

  if (uint32_t non_composited_main_thread_scrolling_reasons =
          GetNonCompositedMainThreadScrollingReasons()) {
    RecordScrollReasonsMetric(device,
                              non_composited_main_thread_scrolling_reasons);
  }
}

WebInputEventResult ScrollManager::HandleGestureScrollBegin(
    const WebGestureEvent& gesture_event) {
  TRACE_EVENT0("input", "ScrollManager::handleGestureScrollBegin");
  DCHECK(!RuntimeEnabledFeatures::ScrollUnificationEnabled());
  if (RuntimeEnabledFeatures::ScrollUnificationEnabled()) {
    return WebInputEventResult::kNotHandled;
  }

  Document* document = frame_->GetDocument();

  if (!document->GetLayoutView())
    return WebInputEventResult::kNotHandled;

  // If there's no layoutObject on the node, send the event to the nearest
  // ancestor with a layoutObject.  Needed for <option> and <optgroup> elements
  // so we can touch scroll <select>s
  while (scroll_gesture_handling_node_ &&
         !scroll_gesture_handling_node_->GetLayoutObject())
    scroll_gesture_handling_node_ =
        scroll_gesture_handling_node_->ParentOrShadowHostNode();

  if (!scroll_gesture_handling_node_)
    scroll_gesture_handling_node_ = frame_->GetDocument();

  if (!scroll_gesture_handling_node_ ||
      !scroll_gesture_handling_node_->GetLayoutObject()) {
    TRACE_EVENT_INSTANT0("input", "Dropping: No LayoutObject",
                         TRACE_EVENT_SCOPE_THREAD);
    return WebInputEventResult::kNotHandled;
  }

  WebInputEventResult child_result = PassScrollGestureEvent(
      gesture_event, scroll_gesture_handling_node_->GetLayoutObject());

  RecordScrollRelatedMetrics(gesture_event.SourceDevice());

  current_scroll_chain_.clear();
  std::unique_ptr<ScrollStateData> scroll_state_data =
      std::make_unique<ScrollStateData>();
  gfx::Point position =
      gfx::ToFlooredPoint(gesture_event.PositionInRootFrame());
  scroll_state_data->position_x = position.x();
  scroll_state_data->position_y = position.y();
  scroll_state_data->delta_x_hint = -gesture_event.DeltaXInRootFrame();
  scroll_state_data->delta_y_hint = -gesture_event.DeltaYInRootFrame();
  scroll_state_data->delta_granularity = gesture_event.DeltaUnits();
  scroll_state_data->is_beginning = true;
  scroll_state_data->from_user_input = true;
  scroll_state_data->is_direct_manipulation =
      gesture_event.SourceDevice() == WebGestureDevice::kTouchscreen;
  scroll_state_data->delta_consumed_for_scroll_sequence =
      delta_consumed_for_scroll_sequence_;
  auto* scroll_state =
      MakeGarbageCollected<ScrollState>(std::move(scroll_state_data));

  RecomputeScrollChain(
      *scroll_gesture_handling_node_.Get(), *scroll_state,
      current_scroll_chain_,
      gesture_event.SourceDevice() == WebGestureDevice::kSyntheticAutoscroll);

  TRACE_EVENT_INSTANT1("input", "Computed Scroll Chain",
                       TRACE_EVENT_SCOPE_THREAD, "length",
                       current_scroll_chain_.size());

  if (current_scroll_chain_.IsEmpty()) {
    // If a child has a non-empty scroll chain, we need to consider that instead
    // of simply returning WebInputEventResult::kNotHandled.
    return child_result;
  }

  NotifyScrollPhaseBeginForCustomizedScroll(*scroll_state);

  CustomizedScroll(*scroll_state);

  if (gesture_event.SourceDevice() == WebGestureDevice::kTouchpad &&
      gesture_event.data.scroll_begin.delta_hint_units ==
          ui::ScrollGranularity::kScrollByPrecisePixel) {
    UseCounter::Count(document, WebFeature::kScrollByPrecisionTouchPad);
  } else if (gesture_event.SourceDevice() == WebGestureDevice::kTouchscreen) {
    UseCounter::Count(document, WebFeature::kScrollByTouch);
  } else {
    UseCounter::Count(document, WebFeature::kScrollByWheel);
  }

  return WebInputEventResult::kHandledSystem;
}

WebInputEventResult ScrollManager::HandleGestureScrollUpdate(
    const WebGestureEvent& gesture_event) {
  TRACE_EVENT0("input", "ScrollManager::handleGestureScrollUpdate");
  DCHECK_EQ(gesture_event.GetType(), WebInputEvent::Type::kGestureScrollUpdate);

  DCHECK(!RuntimeEnabledFeatures::ScrollUnificationEnabled());
  if (RuntimeEnabledFeatures::ScrollUnificationEnabled()) {
    return WebInputEventResult::kNotHandled;
  }

  Node* node = scroll_gesture_handling_node_.Get();
  if (!node || !node->GetLayoutObject()) {
    TRACE_EVENT_INSTANT0("input", "Lost scroll_gesture_handling_node",
                         TRACE_EVENT_SCOPE_THREAD);
    if (previous_gesture_scrolled_node_) {
      // When the scroll_gesture_handling_node_ gets deleted in the middle of
      // scrolling call HandleGestureScrollEvent to start scrolling a new node
      // if possible.
      ClearGestureScrollState();
      WebGestureEvent scroll_begin =
          SynthesizeGestureScrollBegin(gesture_event);
      HandleGestureScrollEvent(scroll_begin);
      node = scroll_gesture_handling_node_.Get();
      if (!node || !node->GetLayoutObject()) {
        TRACE_EVENT_INSTANT0("input", "Failed to find new node",
                             TRACE_EVENT_SCOPE_THREAD);
        return WebInputEventResult::kNotHandled;
      }
    } else {
      TRACE_EVENT_INSTANT0("input", "No previously scrolled node",
                           TRACE_EVENT_SCOPE_THREAD);
      return WebInputEventResult::kNotHandled;
    }
  }
  if (snap_fling_controller_) {
    if (snap_fling_controller_->HandleGestureScrollUpdate(
            GetGestureScrollUpdateInfo(gesture_event))) {
      return WebInputEventResult::kHandledSystem;
    }
  }

  // Negate the deltas since the gesture event stores finger movement and
  // scrolling occurs in the direction opposite the finger's movement
  // direction. e.g. Finger moving up has negative event delta but causes the
  // page to scroll down causing positive scroll delta.
  ScrollOffset delta(-gesture_event.DeltaXInRootFrame(),
                     -gesture_event.DeltaYInRootFrame());
  gfx::Vector2dF velocity(-gesture_event.VelocityX(),
                          -gesture_event.VelocityY());
  gfx::PointF position = gesture_event.PositionInRootFrame();

  if (delta.IsZero())
    return WebInputEventResult::kNotHandled;

  LayoutObject* layout_object = node->GetLayoutObject();

  // Try to send the event to the correct view.
  WebInputEventResult result =
      PassScrollGestureEvent(gesture_event, layout_object);
  if (result != WebInputEventResult::kNotHandled) {
    // FIXME: we should allow simultaneous scrolling of nested
    // iframes along perpendicular axes. See crbug.com/466991.
    delta_consumed_for_scroll_sequence_ = true;
    return result;
  }

  if (current_scroll_chain_.IsEmpty()) {
    TRACE_EVENT_INSTANT0("input", "Empty Scroll Chain",
                         TRACE_EVENT_SCOPE_THREAD);
    return WebInputEventResult::kNotHandled;
  }

  std::unique_ptr<ScrollStateData> scroll_state_data =
      std::make_unique<ScrollStateData>();
  scroll_state_data->delta_x = delta.x();
  scroll_state_data->delta_y = delta.y();
  scroll_state_data->delta_granularity = gesture_event.DeltaUnits();
  scroll_state_data->velocity_x = velocity.x();
  scroll_state_data->velocity_y = velocity.y();
  scroll_state_data->position_x = position.x();
  scroll_state_data->position_y = position.y();
  scroll_state_data->is_in_inertial_phase =
      gesture_event.InertialPhase() ==
      WebGestureEvent::InertialPhaseState::kMomentum;
  scroll_state_data->is_direct_manipulation =
      gesture_event.SourceDevice() == WebGestureDevice::kTouchscreen;
  scroll_state_data->from_user_input = true;
  scroll_state_data->delta_consumed_for_scroll_sequence =
      delta_consumed_for_scroll_sequence_;
  // Scrollbar interactions trigger scroll snap depending on the scrollbar part.
  if (gesture_event.SourceDevice() == WebGestureDevice::kScrollbar)
    AdjustForSnapAtScrollUpdate(gesture_event, scroll_state_data.get());
  auto* scroll_state =
      MakeGarbageCollected<ScrollState>(std::move(scroll_state_data));
  if (previous_gesture_scrolled_node_) {
    // The ScrollState needs to know what the current
    // native scrolling element is, so that for an
    // inertial scroll that shouldn't propagate, only the
    // currently scrolling element responds.
    scroll_state->SetCurrentNativeScrollingNode(
        previous_gesture_scrolled_node_);
  }

  CustomizedScroll(*scroll_state);
  previous_gesture_scrolled_node_ = scroll_state->CurrentNativeScrollingNode();
  delta_consumed_for_scroll_sequence_ =
      scroll_state->DeltaConsumedForScrollSequence();

  last_scroll_delta_for_scroll_gesture_ = delta;

  bool did_scroll_x = scroll_state->deltaX() != delta.x();
  bool did_scroll_y = scroll_state->deltaY() != delta.y();

  did_scroll_x_for_scroll_gesture_ |= did_scroll_x;
  did_scroll_y_for_scroll_gesture_ |= did_scroll_y;

  // TODO(bokan): This looks like it resets overscroll if any *effective* root
  // scroller is scrolled. This should probably be if the *global* root
  // scroller is scrolled.
  if (!previous_gesture_scrolled_node_ ||
      !previous_gesture_scrolled_node_->IsEffectiveRootScroller())
    GetPage()->GetOverscrollController().ResetAccumulated(did_scroll_x,
                                                          did_scroll_y);

  if (did_scroll_x || did_scroll_y)
    return WebInputEventResult::kHandledSystem;

  if (RuntimeEnabledFeatures::OverscrollCustomizationEnabled()) {
    if (Node* overscroll_target = GetScrollEventTarget()) {
      overscroll_target->GetDocument().EnqueueOverscrollEventForNode(
          overscroll_target, delta.x(), delta.y());
    }
  }

  return WebInputEventResult::kNotHandled;
}

void ScrollManager::AdjustForSnapAtScrollUpdate(
    const WebGestureEvent& gesture_event,
    ScrollStateData* scroll_state_data) {
  // Scrollbar interactions outside of the scroll thumb behave like logical
  // scrolls with respect to scroll snap behavior.
  // Scrollbar arrows trigger scroll by line, whereas the scrollbar track
  // triggers scroll by page.
  DCHECK(gesture_event.SourceDevice() == WebGestureDevice::kScrollbar);
  ui::ScrollGranularity granularity = gesture_event.DeltaUnits();
  if (granularity != ui::ScrollGranularity::kScrollByLine &&
      granularity != ui::ScrollGranularity::kScrollByPage) {
    return;
  }

  Node* node = scroll_gesture_handling_node_;
  ScrollableArea* scrollable_area = nullptr;
  if (node && node->GetLayoutObject()) {
    LayoutBox* layout_box = node->GetLayoutBox();
    if (!layout_box)
      return;
    scrollable_area = ScrollableArea::GetForScrolling(layout_box);
  }

  if (!scrollable_area)
    return;

  gfx::PointF current_position = scrollable_area->ScrollPosition();
  std::unique_ptr<cc::SnapSelectionStrategy> strategy =
      cc::SnapSelectionStrategy::CreateForDirection(
          current_position,
          gfx::Vector2dF(scroll_state_data->delta_x,
                         scroll_state_data->delta_y),
          RuntimeEnabledFeatures::FractionalScrollOffsetsEnabled());

  absl::optional<gfx::PointF> snap_point =
      scrollable_area->GetSnapPositionAndSetTarget(*strategy);
  if (!snap_point)
    return;

  scroll_state_data->delta_x = (snap_point->x() - current_position.x());
  scroll_state_data->delta_y = (snap_point->y() - current_position.y());
  scroll_state_data->delta_granularity = ui::ScrollGranularity::kScrollByPixel;
}

// This method is used as a ScrollCallback which requires a void return. Since
// this call to HandleGestureScrollEnd is async, we can just ignore the return
// value.
void ScrollManager::HandleDeferredGestureScrollEnd(
    const WebGestureEvent& gesture_event) {
  HandleGestureScrollEnd(gesture_event);
}

WebInputEventResult ScrollManager::HandleGestureScrollEnd(
    const WebGestureEvent& gesture_event) {
  TRACE_EVENT0("input", "ScrollManager::handleGestureScrollEnd");

  DCHECK(!RuntimeEnabledFeatures::ScrollUnificationEnabled());
  if (RuntimeEnabledFeatures::ScrollUnificationEnabled()) {
    return WebInputEventResult::kNotHandled;
  }

  GetPage()->GetBrowserControls().ScrollEnd();

  Node* node = scroll_gesture_handling_node_;

  if (node && node->GetLayoutObject()) {
    // If the GSE is for a scrollable area that has an in-progress animation,
    // defer the handling of the gesture event until the scroll animation is
    // complete. This will allow things like scroll snapping to be deferred so
    // that users can see the result of their scroll before the snap is applied.
    LayoutBox* layout_box = node->GetLayoutBox();
    ScrollableArea* scrollable_area =
        layout_box ? layout_box->GetScrollableArea() : nullptr;
    if (scrollable_area && scrollable_area->ExistingScrollAnimator() &&
        scrollable_area->ExistingScrollAnimator()->HasRunningAnimation()) {
      scrollable_area->RegisterScrollCompleteCallback(
          WTF::Bind(&ScrollManager::HandleDeferredGestureScrollEnd,
                    WrapWeakPersistent(this), gesture_event));
      return WebInputEventResult::kNotHandled;
    }

    PassScrollGestureEvent(gesture_event, node->GetLayoutObject());
    if (current_scroll_chain_.IsEmpty()) {
      ClearGestureScrollState();
      return WebInputEventResult::kNotHandled;
    }
    std::unique_ptr<ScrollStateData> scroll_state_data =
        std::make_unique<ScrollStateData>();
    scroll_state_data->is_ending = true;
    scroll_state_data->is_in_inertial_phase =
        gesture_event.InertialPhase() ==
        WebGestureEvent::InertialPhaseState::kMomentum;
    scroll_state_data->from_user_input = true;
    scroll_state_data->is_direct_manipulation =
        gesture_event.SourceDevice() == WebGestureDevice::kTouchscreen;
    scroll_state_data->delta_consumed_for_scroll_sequence =
        delta_consumed_for_scroll_sequence_;
    auto* scroll_state =
        MakeGarbageCollected<ScrollState>(std::move(scroll_state_data));
    CustomizedScroll(*scroll_state);

    // We add a callback to set the hover state dirty and send a scroll end
    // event when the scroll ends without snap or the snap point is the same as
    // the scroll position.
    base::ScopedClosureRunner callback(WTF::Bind(
        [](WeakPersistent<LocalFrame> local_frame,
           WeakPersistent<ScrollManager> scroll_manager) {
          if (local_frame) {
            local_frame->GetEventHandler().MarkHoverStateDirty();
          }

          Node* scroll_end_target = scroll_manager->GetScrollEventTarget();
          if (RuntimeEnabledFeatures::OverscrollCustomizationEnabled() &&
              scroll_end_target) {
            scroll_end_target->GetDocument().EnqueueScrollEndEventForNode(
                scroll_end_target);
          }
        },
        WrapWeakPersistent(&(frame_->LocalFrameRoot())),
        WrapWeakPersistent(this)));

    SnapAtGestureScrollEnd(gesture_event, std::move(callback));
    NotifyScrollPhaseEndForCustomizedScroll();
  }

  ClearGestureScrollState();

  return WebInputEventResult::kNotHandled;
}

LayoutBox* ScrollManager::LayoutBoxForSnapping() const {
  if (!previous_gesture_scrolled_node_)
    return nullptr;
  return previous_gesture_scrolled_node_->GetLayoutBox();
}

ScrollOffset GetScrollDirection(ScrollOffset delta) {
  delta.SetToMax(ScrollOffset(-1, -1));
  delta.SetToMin(ScrollOffset(1, 1));
  return delta;
}

bool ScrollManager::SnapAtGestureScrollEnd(
    const WebGestureEvent& end_event,
    base::ScopedClosureRunner on_finish) {
  if (!previous_gesture_scrolled_node_ ||
      (!did_scroll_x_for_scroll_gesture_ && !did_scroll_y_for_scroll_gesture_))
    return false;
  ScrollableArea* scrollable_area =
      ScrollableArea::GetForScrolling(LayoutBoxForSnapping());
  if (!scrollable_area)
    return false;

  bool is_mouse_wheel =
      end_event.SourceDevice() == WebGestureDevice::kTouchpad &&
      end_event.data.scroll_end.delta_units !=
          ui::ScrollGranularity::kScrollByPrecisePixel;

  // Treat mouse wheel scrolls as direction only scroll with its last scroll
  // delta amout. This means each wheel tick will prefer the next snap position
  // in the given direction. This leads to a much better UX for wheels.
  //
  // Precise wheel and trackpads continue to be treated similar as end position
  // scrolling.
  if (is_mouse_wheel && !last_scroll_delta_for_scroll_gesture_.IsZero()) {
    // TODO(majidvp): Currently DirectionStrategy uses current offset + delta as
    // the intended offset and chooses snap offset closest to that intended
    // offset. In this case, this is not correct because we are already at the
    // intended position. DirectionStategy should be updated to use current
    // offset as intended position. This requires changing how we snap in
    // |ScrollManager::LogicalScroll()|. For now use a unit scroll offset to
    // limit the miscalculation to 1px.
    ScrollOffset scroll_direction =
        GetScrollDirection(last_scroll_delta_for_scroll_gesture_);
    return scrollable_area->SnapForDirection(scroll_direction,
                                             std::move(on_finish));
  }

  return scrollable_area->SnapAtCurrentPosition(
      did_scroll_x_for_scroll_gesture_, did_scroll_y_for_scroll_gesture_,
      std::move(on_finish));
}

bool ScrollManager::GetSnapFlingInfoAndSetAnimatingSnapTarget(
    const gfx::Vector2dF& natural_displacement,
    gfx::PointF* out_initial_position,
    gfx::PointF* out_target_position) const {
  ScrollableArea* scrollable_area =
      ScrollableArea::GetForScrolling(LayoutBoxForSnapping());
  if (!scrollable_area)
    return false;

  gfx::PointF current_position = scrollable_area->ScrollPosition();
  *out_initial_position = current_position;
  std::unique_ptr<cc::SnapSelectionStrategy> strategy =
      cc::SnapSelectionStrategy::CreateForEndAndDirection(
          *out_initial_position, natural_displacement,
          RuntimeEnabledFeatures::FractionalScrollOffsetsEnabled());
  absl::optional<gfx::PointF> snap_end =
      scrollable_area->GetSnapPositionAndSetTarget(*strategy);
  if (!snap_end.has_value())
    return false;
  *out_target_position = snap_end.value();
  return true;
}

gfx::PointF ScrollManager::ScrollByForSnapFling(const gfx::Vector2dF& delta) {
  ScrollableArea* scrollable_area =
      ScrollableArea::GetForScrolling(LayoutBoxForSnapping());
  if (!scrollable_area)
    return gfx::PointF();

  std::unique_ptr<ScrollStateData> scroll_state_data =
      std::make_unique<ScrollStateData>();

  // TODO(sunyunjia): Plumb the velocity of the snap curve as well.
  scroll_state_data->delta_x = delta.x();
  scroll_state_data->delta_y = delta.y();
  scroll_state_data->is_in_inertial_phase = true;
  scroll_state_data->from_user_input = true;
  scroll_state_data->delta_granularity =
      ui::ScrollGranularity::kScrollByPrecisePixel;
  scroll_state_data->delta_consumed_for_scroll_sequence =
      delta_consumed_for_scroll_sequence_;
  auto* scroll_state =
      MakeGarbageCollected<ScrollState>(std::move(scroll_state_data));
  scroll_state->SetCurrentNativeScrollingNode(previous_gesture_scrolled_node_);

  CustomizedScroll(*scroll_state);
  // Return the end scroll position.
  return scrollable_area->ScrollPosition();
}

void ScrollManager::ScrollEndForSnapFling(bool did_finish) {
  if (RuntimeEnabledFeatures::OverscrollCustomizationEnabled()) {
    if (Node* scroll_end_target = GetScrollEventTarget()) {
      scroll_end_target->GetDocument().EnqueueScrollEndEventForNode(
          scroll_end_target);
    }
  }
  if (current_scroll_chain_.IsEmpty()) {
    NotifyScrollPhaseEndForCustomizedScroll();
    ClearGestureScrollState();
    return;
  }
  std::unique_ptr<ScrollStateData> scroll_state_data =
      std::make_unique<ScrollStateData>();
  scroll_state_data->is_ending = true;
  scroll_state_data->is_in_inertial_phase = true;
  scroll_state_data->from_user_input = true;
  scroll_state_data->delta_consumed_for_scroll_sequence =
      delta_consumed_for_scroll_sequence_;
  auto* scroll_state =
      MakeGarbageCollected<ScrollState>(std::move(scroll_state_data));
  CustomizedScroll(*scroll_state);
  NotifyScrollPhaseEndForCustomizedScroll();
  ClearGestureScrollState();
}

void ScrollManager::RequestAnimationForSnapFling() {
  if (Page* page = frame_->GetPage())
    page->GetChromeClient().ScheduleAnimation(frame_->View());
}

void ScrollManager::AnimateSnapFling(base::TimeTicks monotonic_time) {
  DCHECK(snap_fling_controller_);
  snap_fling_controller_->Animate(monotonic_time);
}

Page* ScrollManager::GetPage() const {
  return frame_->GetPage();
}

WebInputEventResult ScrollManager::PassScrollGestureEvent(
    const WebGestureEvent& gesture_event,
    LayoutObject* layout_object) {
  DCHECK(gesture_event.IsScrollEvent());

  auto* embedded = DynamicTo<LayoutEmbeddedContent>(layout_object);
  if (!last_gesture_scroll_over_embedded_content_view_ || !embedded)
    return WebInputEventResult::kNotHandled;

  FrameView* frame_view = embedded->ChildFrameView();

  if (!frame_view)
    return WebInputEventResult::kNotHandled;

  auto* local_frame_view = DynamicTo<LocalFrameView>(frame_view);
  if (!local_frame_view)
    return WebInputEventResult::kNotHandled;

  return local_frame_view->GetFrame()
      .GetEventHandler()
      .HandleGestureScrollEvent(gesture_event);
}

WebInputEventResult ScrollManager::HandleGestureScrollEvent(
    const WebGestureEvent& gesture_event) {
  if (!frame_->View())
    return WebInputEventResult::kNotHandled;

  TRACE_EVENT0("input", "ScrollManager::handleGestureScrollEvent");

  Node* event_target = nullptr;
  Scrollbar* scrollbar = nullptr;
  if (gesture_event.GetType() != WebInputEvent::Type::kGestureScrollBegin) {
    scrollbar = scrollbar_handling_scroll_gesture_.Get();
    event_target = scroll_gesture_handling_node_.Get();
  } else if (gesture_event.GetType() ==
                 WebInputEvent::Type::kGestureScrollBegin &&
             gesture_event.data.scroll_begin.scrollable_area_element_id) {
    CompositorElementId element_id = CompositorElementId(
        gesture_event.data.scroll_begin.scrollable_area_element_id);
    event_target = NodeTargetForScrollableAreaElementId(element_id);
    if (!event_target) {
      // If we couldn't find a node associated with the targeted scrollable
      // area, just drop the gesture. This may be due to the fact that the
      // targeted has been removed from the tree between when the gesture
      // was queued and when we handle it.
      return WebInputEventResult::kNotHandled;
    }

    ClearGestureScrollState();
    scroll_gesture_handling_node_ = event_target;
    if (event_target->GetLayoutObject()->IsLayoutEmbeddedContent()) {
      last_gesture_scroll_over_embedded_content_view_ = true;
    }
  }

  if (!event_target) {
    Document* document = frame_->GetDocument();
    if (!document->GetLayoutView())
      return WebInputEventResult::kNotHandled;

    TRACE_EVENT_INSTANT0("input", "Retargeting Scroll",
                         TRACE_EVENT_SCOPE_THREAD);

    LocalFrameView* view = frame_->View();
    PhysicalOffset view_point(view->ConvertFromRootFrame(
        gfx::ToFlooredPoint(gesture_event.PositionInRootFrame())));
    HitTestRequest request(HitTestRequest::kReadOnly);
    HitTestLocation location(view_point);
    HitTestResult result(request, location);
    document->GetLayoutView()->HitTest(location, result);

    event_target = result.InnerNode();

    last_gesture_scroll_over_embedded_content_view_ =
        result.IsOverEmbeddedContentView();

    scroll_gesture_handling_node_ = event_target;
    previous_gesture_scrolled_node_ = nullptr;
    delta_consumed_for_scroll_sequence_ = false;
    did_scroll_x_for_scroll_gesture_ = false;
    did_scroll_y_for_scroll_gesture_ = false;

    if (!scrollbar)
      scrollbar = result.GetScrollbar();
  }

  // Gesture scroll events injected by scrollbars should not be routed back to
  // the scrollbar itself as they are intended to perform the scroll action on
  // the scrollable area. Scrollbar injected gestures don't clear
  // scrollbar_handling_scroll_gesture_ because touch-based scroll gestures need
  // to continue going to the scrollbar first so that the scroll direction
  // can be made proportional to the scroll thumb/ScrollableArea size and
  // inverted.
  if (scrollbar &&
      gesture_event.SourceDevice() != WebGestureDevice::kScrollbar) {
    bool should_update_capture = false;
    if (scrollbar->GestureEvent(gesture_event, &should_update_capture)) {
      if (should_update_capture)
        scrollbar_handling_scroll_gesture_ = scrollbar;
      return WebInputEventResult::kHandledSuppressed;
    }

    scrollbar_handling_scroll_gesture_ = nullptr;
  }

  if (event_target) {
    if (HandleScrollGestureOnResizer(event_target, gesture_event))
      return WebInputEventResult::kHandledSuppressed;

    GestureEvent* gesture_dom_event = GestureEvent::Create(
        event_target->GetDocument().domWindow(), gesture_event);
    if (gesture_dom_event) {
      DispatchEventResult gesture_dom_event_result =
          event_target->DispatchEvent(*gesture_dom_event);
      if (gesture_dom_event_result != DispatchEventResult::kNotCanceled) {
        DCHECK(gesture_dom_event_result !=
               DispatchEventResult::kCanceledByEventHandler);
        return event_handling_util::ToWebInputEventResult(
            gesture_dom_event_result);
      }
    }
  }

  if (snap_fling_controller_) {
    if (gesture_event.IsGestureScroll() &&
        (snap_fling_controller_->FilterEventForSnap(
            ToGestureScrollType(gesture_event.GetType())))) {
      return WebInputEventResult::kNotHandled;
    }
  }
  switch (gesture_event.GetType()) {
    case WebInputEvent::Type::kGestureScrollBegin:
      return HandleGestureScrollBegin(gesture_event);
    case WebInputEvent::Type::kGestureScrollUpdate:
      return HandleGestureScrollUpdate(gesture_event);
    case WebInputEvent::Type::kGestureScrollEnd:
      return HandleGestureScrollEnd(gesture_event);
    case WebInputEvent::Type::kGestureFlingStart:
    case WebInputEvent::Type::kGestureFlingCancel:
      return WebInputEventResult::kNotHandled;
    default:
      NOTREACHED();
      return WebInputEventResult::kNotHandled;
  }
}

Node* ScrollManager::NodeTargetForScrollableAreaElementId(
    CompositorElementId element_id) const {
  Page* page = frame_->GetPage();
  DCHECK(page);
  ScrollableArea* scrollable_area = nullptr;
  if (page->GetVisualViewport().GetScrollElementId() == element_id) {
    // If the element_id is the visual viewport, redirect to the
    // root LocalFrameView's scrollable area (i.e. the RootFrameViewport).
    scrollable_area = frame_->LocalFrameRoot().View()->GetScrollableArea();
  } else {
    ScrollingCoordinator* scrolling_coordinator =
        page->GetScrollingCoordinator();
    scrollable_area =
        scrolling_coordinator->ScrollableAreaWithElementIdInAllLocalFrames(
            element_id);
  }

  // It is possible for an unrelated task to run between the time that
  // the gesture targeting element_id is queued and when we're processing
  // the gesture here, so we must validate the scrollable_area still
  // exists along with it's layout information. If not, just drop this
  // gesture since there is no relevant data on where to target the gesture.
  LayoutBox* layout_box =
      scrollable_area ? scrollable_area->GetLayoutBox() : nullptr;
  if (!layout_box) {
    return nullptr;
  }

  Node* event_target = nullptr;
  if (layout_box->GetDocument().GetFrame() == frame_) {
    event_target = scrollable_area->EventTargetNode();
  } else {
    // The targeted ScrollableArea may not belong to this frame. If that
    // is the case, target its ancestor HTMLFrameOwnerElement that exists
    // in this view, so that the gesture handling can be passed down to
    // the appropriate event handler.
    LocalFrame* current_frame = layout_box->GetDocument().GetFrame();
    while (current_frame) {
      HTMLFrameOwnerElement* owner = current_frame->GetDocument()->LocalOwner();
      // If the hosting element has no layout box, don't return it for targeting
      // since there's nothing to scroll.
      if (!owner->GetLayoutBox())
        break;

      LocalFrame* owner_frame =
          owner ? owner->GetDocument().GetFrame() : nullptr;
      if (owner_frame == frame_) {
        event_target = owner;
        break;
      }
      current_frame = owner_frame;
    }
  }

  return event_target;
}

bool ScrollManager::IsScrollbarHandlingGestures() const {
  return scrollbar_handling_scroll_gesture_.Get();
}

bool ScrollManager::HandleScrollGestureOnResizer(
    Node* event_target,
    const WebGestureEvent& gesture_event) {
  if (gesture_event.SourceDevice() != WebGestureDevice::kTouchscreen)
    return false;

  if (gesture_event.GetType() == WebInputEvent::Type::kGestureScrollBegin) {
    PaintLayer* layer = event_target->GetLayoutObject()
                            ? event_target->GetLayoutObject()->EnclosingLayer()
                            : nullptr;
    gfx::Point p = frame_->View()->ConvertFromRootFrame(
        gfx::ToFlooredPoint(gesture_event.PositionInRootFrame()));
    if (layer && layer->GetScrollableArea() &&
        layer->GetScrollableArea()->IsAbsolutePointInResizeControl(
            p, kResizerForTouch)) {
      resize_scrollable_area_ = layer->GetScrollableArea();
      resize_scrollable_area_->SetInResizeMode(true);
      offset_from_resize_corner_ =
          LayoutSize(resize_scrollable_area_->OffsetFromResizeCorner(p));
      return true;
    }
  } else if (gesture_event.GetType() ==
             WebInputEvent::Type::kGestureScrollUpdate) {
    if (resize_scrollable_area_ && resize_scrollable_area_->InResizeMode()) {
      gfx::Point pos = gfx::ToRoundedPoint(gesture_event.PositionInRootFrame());
      pos.Offset(gesture_event.DeltaXInRootFrame(),
                 gesture_event.DeltaYInRootFrame());
      resize_scrollable_area_->Resize(pos, offset_from_resize_corner_);
      return true;
    }
  } else if (gesture_event.GetType() ==
             WebInputEvent::Type::kGestureScrollEnd) {
    if (resize_scrollable_area_ && resize_scrollable_area_->InResizeMode()) {
      resize_scrollable_area_->SetInResizeMode(false);
      resize_scrollable_area_ = nullptr;
      return false;
    }
  }

  return false;
}

bool ScrollManager::InResizeMode() const {
  return resize_scrollable_area_ && resize_scrollable_area_->InResizeMode();
}

void ScrollManager::Resize(const WebMouseEvent& evt) {
  if (evt.GetType() == WebInputEvent::Type::kMouseMove) {
    if (!frame_->GetEventHandler().MousePressed())
      return;
    resize_scrollable_area_->Resize(
        gfx::ToFlooredPoint(evt.PositionInRootFrame()),
        offset_from_resize_corner_);
  }
}

void ScrollManager::ClearResizeScrollableArea(bool should_not_be_null) {
  if (should_not_be_null)
    DCHECK(resize_scrollable_area_);

  if (resize_scrollable_area_)
    resize_scrollable_area_->SetInResizeMode(false);
  resize_scrollable_area_ = nullptr;
}

void ScrollManager::SetResizeScrollableArea(PaintLayer* layer, gfx::Point p) {
  resize_scrollable_area_ = layer->GetScrollableArea();
  resize_scrollable_area_->SetInResizeMode(true);
  offset_from_resize_corner_ =
      LayoutSize(resize_scrollable_area_->OffsetFromResizeCorner(p));
}

bool ScrollManager::CanHandleGestureEvent(
    const GestureEventWithHitTestResults& targeted_event) {
  Scrollbar* scrollbar = targeted_event.GetHitTestResult().GetScrollbar();

  if (scrollbar) {
    bool should_update_capture = false;
    if (scrollbar->GestureEvent(targeted_event.Event(),
                                &should_update_capture)) {
      if (should_update_capture)
        scrollbar_handling_scroll_gesture_ = scrollbar;
      return true;
    }
  }
  return false;
}

WebGestureEvent ScrollManager::SynthesizeGestureScrollBegin(
    const WebGestureEvent& update_event) {
  DCHECK_EQ(update_event.GetType(), WebInputEvent::Type::kGestureScrollUpdate);
  WebGestureEvent scroll_begin(update_event);
  scroll_begin.SetType(WebInputEvent::Type::kGestureScrollBegin);
  scroll_begin.data.scroll_begin.delta_x_hint =
      update_event.data.scroll_update.delta_x;
  scroll_begin.data.scroll_begin.delta_y_hint =
      update_event.data.scroll_update.delta_y;
  scroll_begin.data.scroll_begin.delta_hint_units =
      update_event.data.scroll_update.delta_units;
  scroll_begin.data.scroll_begin.scrollable_area_element_id = 0;
  return scroll_begin;
}

void ScrollManager::NotifyScrollPhaseBeginForCustomizedScroll(
    const ScrollState& scroll_state) {
  scroll_customization::ScrollDirection direction =
      scroll_customization::GetScrollDirectionFromDeltas(
          scroll_state.deltaXHint(), scroll_state.deltaYHint());
  for (auto id : current_scroll_chain_) {
    Node* node = DOMNodeIds::NodeForId(id);
    if (node)
      node->WillBeginCustomizedScrollPhase(direction);
  }
}

void ScrollManager::NotifyScrollPhaseEndForCustomizedScroll() {
  for (auto id : current_scroll_chain_) {
    Node* node = DOMNodeIds::NodeForId(id);
    if (node)
      node->DidEndCustomizedScrollPhase();
  }
}

}  // namespace blink


text:
package org.finos.waltz.data.attestation;

import org.finos.waltz.schema.tables.DataType;
import org.finos.waltz.schema.tables.*;
import org.finos.waltz.model.EntityKind;
import org.finos.waltz.model.EntityLifecycleStatus;
import org.finos.waltz.model.EntityReference;
import org.finos.waltz.model.attestation.ImmutableLogicalFlowAttestationPreChecks;
import org.finos.waltz.model.attestation.LogicalFlowAttestationPreChecks;
import org.jooq.*;
import org.jooq.impl.DSL;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import static org.finos.waltz.schema.Tables.*;
import static org.finos.waltz.schema.tables.DataType.DATA_TYPE;
import static org.finos.waltz.common.Checks.checkNotNull;

@Repository
public class AttestationPreCheckDao {

    public static final String EXEMPT_FROM_DEPRECATED_DATA_TYPE_CHECK = "EXEMPT_FROM_DEPRECATED_DATA_TYPE_CHECK";
    public static final String EXEMPT_FROM_UNKNOWN_DATA_TYPE_CHECK = "EXEMPT_FROM_UNKNOWN_DATA_TYPE_CHECK";
    public static final String EXEMPT_FROM_FLOW_COUNT_CHECK = "EXEMPT_FROM_FLOW_COUNT_CHECK";
    public static final String GROUP_LOGICAL_FLOW_ATTESTATION_EXEMPT_FROM_FLOW_COUNT_CHECK = "LOGICAL_FLOW_ATTESTATION_EXEMPT_FROM_FLOW_COUNT_CHECK";
    public static final String GROUP_LOGICAL_FLOW_ATTESTATION_EXEMPT_FROM_UNKNOWN_DATA_TYPE_CHECK = "LOGICAL_FLOW_ATTESTATION_EXEMPT_FROM_UNKNOWN_DATA_TYPE_CHECK";
    public static final String GROUP_LOGICAL_FLOW_ATTESTATION_EXEMPT_FROM_DEPRECATED_DATA_TYPE_CHECK = "LOGICAL_FLOW_ATTESTATION_EXEMPT_FROM_DEPRECATED_DATA_TYPE_CHECK";

    private static final LogicalFlow lf = LOGICAL_FLOW;
    private static final LogicalFlowDecorator lfd = LOGICAL_FLOW_DECORATOR;
    private static final ApplicationGroupEntry age = APPLICATION_GROUP_ENTRY;
    private static final ApplicationGroup ag = APPLICATION_GROUP;
    private static final DataType dt = DATA_TYPE;

    private final DSLContext dsl;

    @Autowired
    public AttestationPreCheckDao(DSLContext dsl) {
        this.dsl = checkNotNull(dsl, "DSL cannot be null");
    }

    public LogicalFlowAttestationPreChecks calcLogicalFlowAttestationPreChecks(EntityReference ref) {

        Condition upstreamFlowsCondition = lf.TARGET_ENTITY_KIND.eq(ref.kind().name()).and(lf.TARGET_ENTITY_ID.eq(ref.id()));
        Condition downstreamFlowsCondition = lf.SOURCE_ENTITY_KIND.eq(ref.kind().name()).and(lf.SOURCE_ENTITY_ID.eq(ref.id()));

        CommonTableExpression<Record1<Long>> upstreamFlows = mkInScopeFlowsQry("upstream_flows", upstreamFlowsCondition);
        CommonTableExpression<Record1<Long>> anyFlows = mkInScopeFlowsQry("any_flows", upstreamFlowsCondition.or(downstreamFlowsCondition));

        CommonTableExpression<Record2<String, Integer>> flowCount = DSL
                .name("flow_count")
                .as(DSL
                        .select(DSL.val("FLOWS").as("chk"),
                                DSL.count().as("count"))
                        .from(anyFlows));

        CommonTableExpression<Record2<String, Integer>> unknownFlowCount = DSL
                .name("unknown_flow_count")
                .as(DSL
                        .select(DSL.val("UNKNOWN").as("chk"),
                                DSL.count().as("count"))
                        .from(lfd)
                        .where(lfd.LOGICAL_FLOW_ID.in(DSL
                                .select(upstreamFlows.field(0, Long.class))
                                .from(upstreamFlows)))
                        .and(lfd.DECORATOR_ENTITY_KIND.eq(EntityKind.DATA_TYPE.name()))
                        .and(lfd.DECORATOR_ENTITY_ID.in(DSL.select(dt.ID).from(dt).where(dt.UNKNOWN.isTrue()))));

        CommonTableExpression<Record2<String, Integer>> deprecatedFlowCount = DSL
                .name("deprecated_flow_count")
                .as(DSL
                        .select(DSL.val("DEPRECATED").as("chk"),
                                DSL.count().as("count"))
                        .from(lfd)
                        .where(lfd.LOGICAL_FLOW_ID.in(DSL
                                .select(upstreamFlows.field(0, long.class))
                                .from(upstreamFlows)))
                        .and(lfd.DECORATOR_ENTITY_KIND.eq(EntityKind.DATA_TYPE.name()))
                        .and(lfd.DECORATOR_ENTITY_ID.in(DSL.select(dt.ID).from(dt).where(dt.DEPRECATED.isTrue()))));

        CommonTableExpression<Record2<String, Integer>> exemptForMustHaveFlows = mkExemptionCTE(
                ref,
                EXEMPT_FROM_FLOW_COUNT_CHECK,
                GROUP_LOGICAL_FLOW_ATTESTATION_EXEMPT_FROM_FLOW_COUNT_CHECK);

        CommonTableExpression<Record2<String, Integer>> exemptForUnknownFlows = mkExemptionCTE(
                ref,
                EXEMPT_FROM_UNKNOWN_DATA_TYPE_CHECK,
                GROUP_LOGICAL_FLOW_ATTESTATION_EXEMPT_FROM_UNKNOWN_DATA_TYPE_CHECK);

        CommonTableExpression<Record2<String, Integer>> exemptForDeprecatedFlows = mkExemptionCTE(
                ref,
                EXEMPT_FROM_DEPRECATED_DATA_TYPE_CHECK,
                GROUP_LOGICAL_FLOW_ATTESTATION_EXEMPT_FROM_DEPRECATED_DATA_TYPE_CHECK);

        SelectOrderByStep<Record> qry = dsl
                .with(upstreamFlows)
                .with(anyFlows)
                .with(unknownFlowCount)
                .with(deprecatedFlowCount)
                .with(exemptForMustHaveFlows)
                .with(exemptForUnknownFlows)
                .with(exemptForDeprecatedFlows)
                .with(flowCount)
                .select(unknownFlowCount.asterisk()).from(unknownFlowCount)
                .union(DSL.select(deprecatedFlowCount.asterisk()).from(deprecatedFlowCount))
                .union(DSL.select(exemptForMustHaveFlows.asterisk()).from(exemptForMustHaveFlows))
                .union(DSL.select(exemptForUnknownFlows.asterisk()).from(exemptForUnknownFlows))
                .union(DSL.select(exemptForDeprecatedFlows.asterisk()).from(exemptForDeprecatedFlows))
                .union(DSL.select(flowCount.asterisk()).from(flowCount));

        ImmutableLogicalFlowAttestationPreChecks.Builder builder = ImmutableLogicalFlowAttestationPreChecks.builder();

        qry.forEach(r -> {
            String check = r.get("chk", String.class);
            int count = r.get("count", Integer.class);
            switch (check) {
                case "FLOWS":
                    builder.flowCount(count);
                    break;
                case "UNKNOWN":
                    builder.unknownCount(count);
                    break;
                case "DEPRECATED":
                    builder.deprecatedCount(count);
                    break;
                case EXEMPT_FROM_FLOW_COUNT_CHECK:
                    builder.exemptFromFlowCountCheck(count > 0);
                    break;
                case EXEMPT_FROM_UNKNOWN_DATA_TYPE_CHECK:
                    builder.exemptFromUnknownCheck(count > 0);
                    break;
                case EXEMPT_FROM_DEPRECATED_DATA_TYPE_CHECK:
                    builder.exemptFromDeprecatedCheck(count > 0);
                    break;
                default:
                    throw new IllegalArgumentException("Unexpected check: " + check);
            }
        });

        return builder.build();
    }

    private CommonTableExpression<Record1<Long>> mkInScopeFlowsQry(String cteName, Condition inScopeFlowsCondition) {
        return DSL
                .name(cteName)
                .as(DSL
                        .select(lf.ID)
                        .from(lf)
                        .where(inScopeFlowsCondition)
                        .and(lf.ENTITY_LIFECYCLE_STATUS.eq(EntityLifecycleStatus.ACTIVE.name()))
                        .and(lf.IS_REMOVED.isFalse()));
    }

    private CommonTableExpression<Record2<String, Integer>> mkExemptionCTE(EntityReference ref,
                                                                           String checkName,
                                                                           String groupExtId) {
        return DSL
                .name(checkName)
                .as(DSL
                    .select(DSL.val(checkName).as("chk"),
                            DSL.count().as("count"))
                    .from(age)
                    .where(age.APPLICATION_ID.eq(ref.id()))
                    .and(age.GROUP_ID.eq(DSL
                            .select(ag.ID)
                            .from(ag)
                            .where(ag.EXTERNAL_ID.eq(groupExtId)))));
    }

}

redpajama_set_name: RedPajamaGithub


text:
<?php namespace Smallworldfs\Payscout;

use Config;
class Payscout
{
    /**
     * Create a new Skeleton Instance
     */
    public function __construct()
    {
        // constructor body
    }

    public function generateTransaction(){

    }

    public static function appendXmlNode($domDocument, $parentNode, $name, $value) {
            $childNode      = $domDocument->createElement($name);
            $childNodeValue = $domDocument->createTextNode($value);
            $childNode->appendChild($childNodeValue);
            $parentNode->appendChild($childNode);
    }

    public static function sendXMLviaCurl($xmlRequest,$gatewayURL) {
       // helper function demonstrating how to send the xml with curl

        $ch = curl_init(); // Initialize curl handle
        curl_setopt($ch, CURLOPT_URL, $gatewayURL); // Set POST URL

        $headers = array();
        $headers[] = "Content-type: text/xml";
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); // Add http headers to let it know we're sending XML
        $xmlString = $xmlRequest->saveXML();
        curl_setopt($ch, CURLOPT_FAILONERROR, 1); // Fail on errors
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // Allow redirects
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // Return into a variable
        curl_setopt($ch, CURLOPT_PORT, 443); // Set the port number
        curl_setopt($ch, CURLOPT_TIMEOUT, 30); // Times out after 30s
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlString); // Add XML directly in POST

        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);

        // This should be unset in production use. With it on, it forces the ssl cert to be valid
        // before sending info.
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);

        if (!($data = curl_exec($ch))) {
            print  "curl error =>" .curl_error($ch) ."\n";
            throw New Exception(" CURL ERROR :" . curl_error($ch));

        }
        curl_close($ch);

        return $data;
    }

    /**
     * Friendly welcome
     *
     * @param string $phrase Phrase to return
     *
     * @return string Returns the phrase passed in
     */
    public function echoPhrase($phrase)
    {
        return $phrase;
    }

    public static function printField($name, $value = "") {
        return "<input type=hidden name=\"$name\" value=\"$value\">\n";
    }

    public static function printHash($fields) {
        $gw_merchantKeyText = Config::get('payscout.api_key');
        $stringToHash = implode('|', array_values($fields)) .
            "|" . $gw_merchantKeyText;
        $value = implode("|", array_keys($fields)) . "|" . md5($stringToHash);

        return $value;
    }
}


text:
namespace jxl {
namespace extras {

struct EncodedImage {
  // One (if the format supports animations or the image has only one frame) or
  // more sequential bitstreams.
  std::vector<std::vector<uint8_t>> bitstreams;

  // For each extra channel one or more sequential bitstreams.
  std::vector<std::vector<std::vector<uint8_t>>> extra_channel_bitstreams;

  std::vector<uint8_t> preview_bitstream;

  // If the format does not support embedding color profiles into the bitstreams
  // above, it will be present here, to be written as a separate file. If it
  // does support them, this field will be empty.
  std::vector<uint8_t> icc;

  // Additional output for conformance testing, only filled in by NumPyEncoder.
  std::vector<uint8_t> metadata;
};

class Encoder {
 public:
  static std::unique_ptr<Encoder> FromExtension(std::string extension);

  virtual ~Encoder() = default;

  virtual std::vector<JxlPixelFormat> AcceptedFormats() const = 0;

  // Any existing data in encoded_image is discarded.
  virtual Status Encode(const PackedPixelFile& ppf, EncodedImage* encoded_image,
                        ThreadPool* pool = nullptr) const = 0;

  void SetOption(std::string name, std::string value) {
    options_[std::move(name)] = std::move(value);
  }

 protected:
  const std::unordered_map<std::string, std::string>& options() const {
    return options_;
  }

  Status VerifyBasicInfo(const JxlBasicInfo& info) const;

  Status VerifyFormat(const JxlPixelFormat& format) const;

  Status VerifyBitDepth(JxlDataType data_type, uint32_t bits_per_sample,
                        uint32_t exponent_bits) const;

  Status VerifyPackedImage(const PackedImage& image,
                           const JxlBasicInfo& info) const;

 private:
  std::unordered_map<std::string, std::string> options_;
};

// TODO(sboukortt): consider exposing this as part of the C API.
Status SelectFormat(const std::vector<JxlPixelFormat>& accepted_formats,
                    const JxlBasicInfo& basic_info, JxlPixelFormat* format);

}  // namespace extras
}  // namespace jxl

#endif  // LIB_EXTRAS_ENC_ENCODE_H_


text: Checked arithmetic operations


text:
help:
	@echo "coverage-console - run code coverage and output to console"
	@echo "coverage-html - run code coverage and output to HTML"
	@echo "db - create and migrate database"
	@echo "install - install Python dependencies"
	@echo "loaddata - load initial data"
	@echo "setup - prepare development environment"
	@echo "test - run tests"

install:
	pip install -r requirements.txt

loaddata:
	python manage.py loaddata deck/fixtures/user.json
	python manage.py loaddata deck/fixtures/event.json
	python manage.py loaddata deck/fixtures/proposal.json
	python manage.py loaddata deck/fixtures/socialapp.json

db:
	python manage.py migrate

setup: install db loaddata

test:
	./manage.py test

coverage:
	coverage erase
	coverage run ./manage.py test

coverage-console: coverage
	coverage report -m

coverage-html: coverage
	coverage html


text:
 [](#skip-navbar_top "Skip navigation links")

<colgroup>
<col width="50%" />
<col width="50%" />
</colgroup>

Overview
Package
 Class
Use
Tree
Deprecated
Index
Help

 PREV CLASS   NEXT CLASS
FRAMES    NO FRAMES
All Classes

SUMMARY: NESTED | FIELD | CONSTR | METHOD
DETAIL: FIELD | CONSTR | METHOD

------------------------------------------------------------------------

org.apache.struts.taglib.logic
 Class ConditionalTagBase
------------------------------

    java.lang.Object
      javax.servlet.jsp.tagext.TagSupport
          org.apache.struts.taglib.logic.ConditionalTagBase

**All Implemented Interfaces:**
[Serializable](http://java.sun.com/j2se/1.4.2/docs/api/java/io/Serializable.html.md?is-external=true "class or interface in java.io"), [IterationTag](http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/jsp/tagext/IterationTag.html?is-external=true "class or interface in javax.servlet.jsp.tagext"), [Tag](http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/jsp/tagext/Tag.html?is-external=true "class or interface in javax.servlet.jsp.tagext")

**Direct Known Subclasses:**
[CompareTagBase](../../../../../org/apache/struts/taglib/logic/CompareTagBase.html.md "class in org.apache.struts.taglib.logic"), [EmptyTag](../../../../../org/apache/struts/taglib/logic/EmptyTag.html "class in org.apache.struts.taglib.logic"), [MatchTag](../../../../../org/apache/struts/taglib/logic/MatchTag.html "class in org.apache.struts.taglib.logic"), [MessagesPresentTag](../../../../../org/apache/struts/taglib/logic/MessagesPresentTag.html "class in org.apache.struts.taglib.logic"), [PresentTag](../../../../../org/apache/struts/taglib/logic/PresentTag.html "class in org.apache.struts.taglib.logic")

------------------------------------------------------------------------

    public abstract class ConditionalTagBase

extends [TagSupport](http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/jsp/tagext/TagSupport.html.md?is-external=true "class or interface in javax.servlet.jsp.tagext")

Abstract base class for the various conditional evaluation tags.

**Version:**
$Rev: 471754 $ $Date: 2004-10-16 12:38:42 -0400 (Sat, 16 Oct 2004) $

**See Also:**
[Serialized Form](../../../../../serialized-form.html.md#org.apache.struts.taglib.logic.ConditionalTagBase)

------------------------------------------------------------------------

**Field Summary**

`protected  String`

` cookie`
           The name of the cookie to be used as a variable.

`protected  String`

` header`
           The name of the HTTP request header to be used as a variable.

`protected static MessageResources`

` messages`
           The message resources for this package.

`protected  String`

` name`
           The name of the JSP bean to be used as a variable (if `property` is not specified), or whose property is to be accessed (if `property` is specified).

`protected  String`

` parameter`
           The name of the HTTP request parameter to be used as a variable.

`protected  String`

` property`
           The name of the bean property to be used as a variable.

`protected  String`

` role`
           The name of the security role to be checked for.

`protected  String`

` scope`
           The scope to search for the bean named by the name property, or "any scope" if null.

`protected  String`

` user`
           The user principal name to be checked for.

| **Fields inherited from class javax.servlet.jsp.tagext.[TagSupport](http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/jsp/tagext/TagSupport.html.md?is-external=true "class or interface in javax.servlet.jsp.tagext")** |
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `id, pageContext`                                                                                |

| **Fields inherited from interface javax.servlet.jsp.tagext.[IterationTag](http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/jsp/tagext/IterationTag.html.md?is-external=true "class or interface in javax.servlet.jsp.tagext")** |
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `EVAL_BODY_AGAIN`                                                                                |

| **Fields inherited from interface javax.servlet.jsp.tagext.[Tag](http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/jsp/tagext/Tag.html.md?is-external=true "class or interface in javax.servlet.jsp.tagext")** |
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `EVAL_BODY_INCLUDE, EVAL_PAGE, SKIP_BODY, SKIP_PAGE`                                                                                |

| **Constructor Summary** |
|-------------------------|
| ` ConditionalTagBase()`
                          |

**Method Summary**

`protected abstract  boolean`

` condition()`
           Evaluate the condition that is being tested by this particular tag, and return `true` if the nested body content of this tag should be evaluated, or `false` if it should be skipped.

` int`

` doEndTag()`
           Evaluate the remainder of the current page normally.

` int`

` doStartTag()`
           Perform the test required for this particular tag, and either evaluate or skip the body of this tag.

` String`

` getCookie()`

` String`

` getHeader()`

` String`

` getName()`

` String`

` getParameter()`

` String`

` getProperty()`

` String`

` getRole()`

` String`

` getScope()`

` String`

` getUser()`

` void`

` release()`
           Release all allocated resources.

` void`

` setCookie(String cookie)`

` void`

` setHeader(String header)`

` void`

` setName(String name)`

` void`

` setParameter(String parameter)`

` void`

` setProperty(String property)`

` void`

` setRole(String role)`

` void`

` setScope(String scope)`

` void`

` setUser(String user)`

| **Methods inherited from class javax.servlet.jsp.tagext.[TagSupport](http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/jsp/tagext/TagSupport.html.md?is-external=true "class or interface in javax.servlet.jsp.tagext")** |
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `doAfterBody, findAncestorWithClass, getId, getParent, getValue, getValues, removeValue, setId, setPageContext, setParent, setValue`                                                                                |

| **Methods inherited from class java.lang.[Object](http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Object.html.md?is-external=true "class or interface in java.lang")** |
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`                                                                          |

**Field Detail**

### messages

    protected static MessageResources messages

The message resources for this package.

------------------------------------------------------------------------

### cookie

    protected String cookie

The name of the cookie to be used as a variable.

------------------------------------------------------------------------

### header

    protected String header

The name of the HTTP request header to be used as a variable.

------------------------------------------------------------------------

### name

    protected String name

The name of the JSP bean to be used as a variable (if `property` is not specified), or whose property is to be accessed (if `property` is specified).

------------------------------------------------------------------------

### parameter

    protected String parameter

The name of the HTTP request parameter to be used as a variable.

------------------------------------------------------------------------

### property

    protected String property

The name of the bean property to be used as a variable.

------------------------------------------------------------------------

### role

    protected String role

The name of the security role to be checked for.

------------------------------------------------------------------------

### scope

    protected String scope

The scope to search for the bean named by the name property, or "any scope" if null.

------------------------------------------------------------------------

### user

    protected String user

The user principal name to be checked for.

**Constructor Detail**

### ConditionalTagBase

    public ConditionalTagBase()

**Method Detail**

### getCookie

    public String getCookie()

------------------------------------------------------------------------

### setCookie

    public void setCookie(String cookie)

------------------------------------------------------------------------

### getHeader

    public String getHeader()

------------------------------------------------------------------------

### setHeader

    public void setHeader(String header)

------------------------------------------------------------------------

### getName

    public String getName()

------------------------------------------------------------------------

### setName

    public void setName(String name)

------------------------------------------------------------------------

### getParameter

    public String getParameter()

------------------------------------------------------------------------

### setParameter

    public void setParameter(String parameter)

------------------------------------------------------------------------

### getProperty

    public String getProperty()

------------------------------------------------------------------------

### setProperty

    public void setProperty(String property)

------------------------------------------------------------------------

### getRole

    public String getRole()

------------------------------------------------------------------------

### setRole

    public void setRole(String role)

------------------------------------------------------------------------

### getScope

    public String getScope()

------------------------------------------------------------------------

### setScope

    public void setScope(String scope)

------------------------------------------------------------------------

### getUser

    public String getUser()

------------------------------------------------------------------------

### setUser

    public void setUser(String user)

------------------------------------------------------------------------

### doStartTag

    public int doStartTag()
                   throws JspException

Perform the test required for this particular tag, and either evaluate or skip the body of this tag.

**Specified by:**
`doStartTag` in interface `Tag`

**Overrides:**
`doStartTag` in class `TagSupport`

**Throws:**
`JspException` - if a JSP exception occurs

------------------------------------------------------------------------

### doEndTag

    public int doEndTag()
                 throws JspException

Evaluate the remainder of the current page normally.

**Specified by:**
`doEndTag` in interface `Tag`

**Overrides:**
`doEndTag` in class `TagSupport`

**Throws:**
`JspException` - if a JSP exception occurs

------------------------------------------------------------------------

### release

    public void release()

Release all allocated resources.

**Specified by:**
`release` in interface `Tag`

**Overrides:**
`release` in class `TagSupport`

------------------------------------------------------------------------

### condition

    protected abstract boolean condition()
                                  throws JspException

Evaluate the condition that is being tested by this particular tag, and return `true` if the nested body content of this tag should be evaluated, or `false` if it should be skipped. This method must be implemented by concrete subclasses.

**Throws:**
`JspException` - if a JSP exception occurs

------------------------------------------------------------------------

 [](#skip-navbar_bottom "Skip navigation links")

<colgroup>
<col width="50%" />
<col width="50%" />
</colgroup>

Overview
Package
 Class
Use
Tree
Deprecated
Index
Help

 PREV CLASS   NEXT CLASS
FRAMES    NO FRAMES
All Classes

SUMMARY: NESTED | FIELD | CONSTR | METHOD
DETAIL: FIELD | CONSTR | METHOD

------------------------------------------------------------------------

Copyright © 2000-2008 [Apache Software Foundation](http://www.apache.org/). All Rights Reserved.


text:
'use strict';

function SignInCtrl(signInName, session, lib, $scope, $location, $window, $http) {

	$scope.signup = {};
	$scope.signup.once = false;

	var hash = $window.location.hash;
	if (hash.indexOf('/') >= 0) {
		session.lastLocationPath = hash.slice(hash.indexOf('/'));

		// Redirect to the page if it is public and does not
		// require a signin.
		var path = $location.path();

		// isPagePublic is defined in TopLevelCtrl, and it is
		// a bad practice to use scope inheritance like this.
		if ($scope.isPagePublic(path) && path !== "/sponsor") {
			$window.location.href = path;
		}
	}

	var goHome = function (user, session, callback) {
		var defaultGroup = undefined;

		var onCircleFound = function (circle) {
			session.activeCircle = circle;
			session.user = user;
			session.save();

			if (session.lastLocationPath) {
				$window.location.href = "/#" + session.lastLocationPath;
				callback();
			}
			else {
				$window.location.href = "/";
				callback();
			}
		};

		if (user.memberships && user.memberships.length > 0) {
			var membershipIndex = 0;

			// Find the first group we're a part of that has a
			// circle associated with it, and that's our default circle.
			var tryToFindGroupStartingAtIndex = function (index) {
				defaultGroup = user.memberships[index].group;

				$http.get('/data/group/' + defaultGroup)
				.success(function (group) {
					if (group.projectId) {
						onCircleFound(group.projectId);
					}
					else {
						index++;
						if (index < user.memberships.length) {
							tryToFindGroupStartingAtIndex(index);
						}
						else {
							// There are no circles!
							onCircleFound(null);
						}
					}
				})
				.error(function () {
					var err = new Error("Sorry, the server failed to get your circle.");
					callback(err);
				});
			};

			tryToFindGroupStartingAtIndex(0);
		}
		else {
			// Not a member of any groups. Go to create one.
			$window.location.href = "/create";
			callback();
		}
	};

	$scope.signIn = function() {

		var success = function(user) {
			$scope.message = "Success!";

			if ($scope.rememberMe) {
				signInName.set(user.email);
			}

			goHome(user, session, function (err) {
				if (err) {
					$scope.message = err.message;
					return;
				}
				else {
					// Even though we changed the href above,
					// we don't refresh automatically unless
					// the URL changes, so force a reload here,
					// and this will bring us to the home page.
					if ($window.location.pathname === "/") {
						$window.location.reload();
					}
				}
			});
		};

		var failure = function(data, status) {
			$scope.message = "Sorry, please try something else."
			$scope.signinFailure = true;
			if (status === 429) {
				$scope.message = "Sorry, it seems someone is trying " +
				"to guess your password, so we aren't allowing any more sign-in " +
				"attempts, today. Please call us to be allowed into the site.";
			}
		};

		var email = $scope.user.email;
		var password = $scope.user.password;

		lib.signIn(email, password, function (err, user) {
			if (err) {
				failure(err, err.status);
				return;
			}
			success(user);
		});
	};

	$scope.signUp = function() {
		if ($scope.signup.once) {
			return;
		}
		$scope.signup.once = true;

		var success = function (data) {
			$scope.signup.message = "Thank you. :-)";

			$scope.user = {};
			$scope.user.email = $scope.signup.email;
			$scope.user.password = $scope.signup.password;

			session.lastLocationPath = "/welcome";
			$scope.signIn();
		};

		var failure = function (data, status) {
			var message = "Sorry, our computers aren't working. " +
			"Please try again at a later time.";
			if (status === 400 || status === 403) {
				// we have a well-known error.
				message = data;
			}
			$scope.signup.message = message;
		};

		var data = {
			circle: $scope.signup.circle,
			name: $scope.signup.name,
			email: $scope.signup.email,
			password: $scope.signup.password
		};

		$http.post('/data/signup/now', data)
		.success(success)
		.error(failure);
	};

	$scope.isPaymentEnabled = function () {
		if (session.settings && session.settings['stripe-public-key'].value) {
			return true;
		}
		return false;
	};

	// TODO: Duplicate code in story.js
	$scope.isNotificationEnabled = function () {
		if (session.settings && session.settings['smtp-enabled'].value) {
			return true;
		}
		return false;
	};

	var sendingSecret = false;
	$scope.sendSecret = function () {
		if (sendingSecret) {
			// already sending ...
			return;
		}

		sendingSecret = true;
		$scope.signinFailure = undefined;
		$scope.message = "Sending emal ...";

		var data = {
			email: $scope.user.email
		};

		$http.post('/auth/signin/forgot', data)
		.success(function () {
			$scope.message = "Ok! Check your email, please.";
			sendingSecret = false;
		})
		.error(function () {
			$scope.message = "Sorry, our computers are broken now. " +
				"Please try again at a later time.";
			sendingSecret = false;
		});
	};

	var signinInfoChanged = function () {
		$scope.message = undefined;
		$scope.signinFailure = undefined;
	};

	$scope.$watch('user.email', signinInfoChanged);
	$scope.$watch('user.password', signinInfoChanged);

	var init = function () {
		// Redirect to home if we're already signed in.
		if ($scope.isSignedIn() && $window.location.pathname !== "/") {
			$window.location.href = "/";
			return;
		}

		lib.mindset.set('detailed');
		$scope.user = {};

		var name = signInName.get();
		if (name) {
			$scope.user.email = name;
		}

		$scope.rememberMe = true;
	};

	init();
}
SignInCtrl.$inject = ['signInName', 'session', 'lib', '$scope', '$location', '$window', '$http'];


text:
angular.module('starter', ['ionic'])

.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if(window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if(window.StatusBar) {
      StatusBar.styleDefault();
    }
  });
})

.config(function($stateProvider, $urlRouterProvider) {
  $stateProvider
    .state('tabs', {
      url: '/tab',
      abstract: true,
      templateUrl: 'templates/tabs.html'
    })

    .state('tabs.home', {
      url: '/home',
      views: {
        'home-tab' : {
          templateUrl: 'templates/home.html'
        }
      }
    })

    .state('tabs.list', {
      url: '/list',
      views: {
        'list-tab' : {
          templateUrl: 'templates/list.html',
          controller: 'ListController'
        }
      }
    })

    .state('tabs.detail', {
      url: '/list/:aId',
      views: {
        'list-tab' : {
          templateUrl: 'templates/detail.html',
          controller: 'ListController'
        }
      }
    })

    .state('tabs.calendar', {
      url: '/calendar',
      views: {
        'calendar-tab' : {
          templateUrl: 'templates/calendar.html',
          controller: 'CalendarController'
        }
      }
    })

  $urlRouterProvider.otherwise('/tab/home');

})

.controller('CalendarController', ['$scope', '$http', '$state',
    function($scope, $http, $state) {
    $http.get('js/data.json').success(function(data) {
      $scope.calendar = data.calendar;

      // delete calendar item method
      $scope.onItemDelete = function(dayIndex, item) {
        $scope.calendar[dayIndex].schedule.splice($scope.calendar[dayIndex].schedule.indexOf(item), 1);
      }

      // refresh caledar data
      $scope.doRefresh =function() {
      $http.get('js/data.json').success(function(data) {
          $scope.calendar = data.calendar;
          $scope.$broadcast('scroll.refreshComplete');
        });
      }

      // toggle calendar star
      $scope.toggleStar = function(item) {
        item.star = !item.star;
      }

    });
}])

.controller('ListController', ['$scope', '$http', '$state',
    function($scope, $http, $state) {
    $http.get('js/data.json').success(function(data) {
      $scope.artists = data.artists;
      $scope.whichartist=$state.params.aId;
      $scope.data = { showDelete: false, showReorder: false };

      // move artist item method
      $scope.moveItem = function(item, fromIndex, toIndex) {
        $scope.artists.splice(fromIndex, 1);
        $scope.artists.splice(toIndex, 0, item);
      };

      // delete artist item method
      $scope.onItemDelete = function(item) {
        $scope.artists.splice($scope.artists.indexOf(item), 1);
      };

      // toogle artist star
      $scope.toggleStar = function(item) {
        item.star = !item.star;
      };

      // refresh artist data
      $scope.doRefresh = function() {
      $http.get('js/data.json').success(function(data) {
          $scope.artists = data.artists;
          $scope.$broadcast('scroll.refreshComplete');
        });
      };

    }); // http.get
}]);


text:
<?php
class MageTool_Tool_MageExtension_Profile_FileParser_Xml extends Zend_Tool_Project_Profile_FileParser_Xml {

    /**
     * unserialize()
     *
     * Create a structure in the object $profile from the structure specficied
     * in the xml string provided
     *
     * @param string xml data
     * @param Zend_Tool_Project_Profile The profile to use as the top node
     * @return Zend_Tool_Project_Profile
     */
    public function unserialize($data, Zend_Tool_Project_Profile $profile)
    {
        if ($data == null) {
            throw new Exception('contents not available to unserialize.');
        }

        $this->_profile = $profile;

        $xmlDataIterator = new SimpleXMLIterator($data);

        if ($xmlDataIterator->getName() != 'extensionProfile') {
            throw new Exception('Extension profile must start with a extensionProfile node');
        }

        if (isset($xmlDataIterator['type'])) {
            $this->_profile->setAttribute('type', (string) $xmlDataIterator['type']);
        }

        if (isset($xmlDataIterator['version'])) {
            $this->_profile->setAttribute('version', (string) $xmlDataIterator['version']);
        }

        // start un-serialization of the xml doc
        $this->_unserializeRecurser($xmlDataIterator);

        // contexts should be initialized after the unwinding of the profile structure
        $this->_lazyLoadContexts();

        return $this->_profile;

    }
}


text:
package jenkins.python.expoint;

import hudson.ExtensionPoint;
import hudson.ExtensionList;
import hudson.Extension;
import jenkins.model.Jenkins;
import hudson.model.Item;
import hudson.model.listeners.*;
import hudson.model.listeners.ItemListener.*;
import jenkins.python.DataConvertor;
import jenkins.python.PythonExecutor;

/**
 * This class was automatically generated by the PWM tool on 2014/03/21.
 * @see hudson.model.listeners.ItemListener
 */
public abstract class ItemListenerPW extends ItemListener {
	private transient PythonExecutor pexec;

	private void initPython() {
		if (pexec == null) {
			pexec = new PythonExecutor(this);
			String[] jMethods = new String[0];
			String[] pFuncs = new String[0];
			Class[][] argTypes = new Class[0][];
			pexec.checkAbstrMethods(jMethods, pFuncs, argTypes);
			String[] functions = new String[8];
			functions[0] = "on_created";
			functions[1] = "on_copied";
			functions[2] = "on_loaded";
			functions[3] = "on_deleted";
			functions[4] = "on_renamed";
			functions[5] = "on_updated";
			functions[6] = "on_before_shutdown";
			functions[7] = "register";
			int[] argsCount = new int[8];
			argsCount[0] = 1;
			argsCount[1] = 2;
			argsCount[2] = 0;
			argsCount[3] = 1;
			argsCount[4] = 3;
			argsCount[5] = 1;
			argsCount[6] = 0;
			argsCount[7] = 0;
			pexec.registerFunctions(functions, argsCount);
		}
	}

	@Override
	public void onCreated(Item item) {
		initPython();
		if (pexec.isImplemented(0)) {
			pexec.execPythonVoid("on_created", item);
		} else {
			super.onCreated(item);
		}
	}

	@Override
	public void onCopied(Item src, Item item) {
		initPython();
		if (pexec.isImplemented(1)) {
			pexec.execPythonVoid("on_copied", src, item);
		} else {
			super.onCopied(src, item);
		}
	}

	@Override
	public void onLoaded() {
		initPython();
		if (pexec.isImplemented(2)) {
			pexec.execPythonVoid("on_loaded");
		} else {
			super.onLoaded();
		}
	}

	@Override
	public void onDeleted(Item item) {
		initPython();
		if (pexec.isImplemented(3)) {
			pexec.execPythonVoid("on_deleted", item);
		} else {
			super.onDeleted(item);
		}
	}

	@Override
	public void onRenamed(Item item, String oldName, String newName) {
		initPython();
		if (pexec.isImplemented(4)) {
			pexec.execPythonVoid("on_renamed", item, oldName, newName);
		} else {
			super.onRenamed(item, oldName, newName);
		}
	}

	@Override
	public void onUpdated(Item item) {
		initPython();
		if (pexec.isImplemented(5)) {
			pexec.execPythonVoid("on_updated", item);
		} else {
			super.onUpdated(item);
		}
	}

	@Override
	public void onBeforeShutdown() {
		initPython();
		if (pexec.isImplemented(6)) {
			pexec.execPythonVoid("on_before_shutdown");
		} else {
			super.onBeforeShutdown();
		}
	}

	@Override
	public void register() {
		initPython();
		if (pexec.isImplemented(7)) {
			pexec.execPythonVoid("register");
		} else {
			super.register();
		}
	}

	public void superOnCreated(Item item) {
		super.onCreated(item);
	}

	public void superOnCopied(Item src, Item item) {
		super.onCopied(src, item);
	}

	public void superOnLoaded() {
		super.onLoaded();
	}

	public void superOnDeleted(Item item) {
		super.onDeleted(item);
	}

	public void superOnRenamed(Item item, String oldName, String newName) {
		super.onRenamed(item, oldName, newName);
	}

	public void superOnUpdated(Item item) {
		super.onUpdated(item);
	}

	public void superOnBeforeShutdown() {
		super.onBeforeShutdown();
	}

	public void superRegister() {
		super.register();
	}

	public Object execPython(String function, Object... params) {
		initPython();
		return pexec.execPython(function, params);
	}

	public byte execPythonByte(String function, Object... params) {
		initPython();
		return pexec.execPythonByte(function, params);
	}

	public short execPythonShort(String function, Object... params) {
		initPython();
		return pexec.execPythonShort(function, params);
	}

	public char execPythonChar(String function, Object... params) {
		initPython();
		return pexec.execPythonChar(function, params);
	}

	public int execPythonInt(String function, Object... params) {
		initPython();
		return pexec.execPythonInt(function, params);
	}

	public long execPythonLong(String function, Object... params) {
		initPython();
		return pexec.execPythonLong(function, params);
	}

	public float execPythonFloat(String function, Object... params) {
		initPython();
		return pexec.execPythonFloat(function, params);
	}

	public double execPythonDouble(String function, Object... params) {
		initPython();
		return pexec.execPythonDouble(function, params);
	}

	public boolean execPythonBool(String function, Object... params) {
		initPython();
		return pexec.execPythonBool(function, params);
	}

	public void execPythonVoid(String function, Object... params) {
		initPython();
		pexec.execPythonVoid(function, params);
	}
}