| // Copyright 2013 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/events/event_source.h" |
| |
| #include "base/logging.h" |
| #include "base/memory/raw_ptr.h" |
| #include "ui/events/event_rewriter.h" |
| #include "ui/events/event_rewriter_continuation.h" |
| #include "ui/events/event_sink.h" |
| |
| namespace ui { |
| |
| namespace { |
| |
| bool IsLocatedEventWithDifferentLocations(const Event& event) { |
| if (!event.IsLocatedEvent()) |
| return false; |
| const LocatedEvent* located_event = event.AsLocatedEvent(); |
| return located_event->target() && |
| located_event->location_f() != located_event->root_location_f(); |
| } |
| |
| } // namespace |
| |
| class EventSource::EventRewriterContinuationImpl |
| : public EventRewriterContinuation { |
| public: |
| // Constructs an EventRewriterContinuationImpl at the end of the source's |
| // rewriter list. |
| static void Create(EventSource* const source, EventRewriter* rewriter) { |
| DCHECK(source); |
| DCHECK(rewriter); |
| DCHECK(source->FindContinuation(rewriter) == source->rewriter_list_.end()); |
| source->rewriter_list_.push_back( |
| std::make_unique<EventRewriterContinuationImpl>(source, rewriter)); |
| EventRewriterList::iterator it = source->rewriter_list_.end(); |
| --it; |
| CHECK((*it)->rewriter() == rewriter); |
| (*it)->self_ = it; |
| } |
| |
| EventRewriterContinuationImpl(EventSource* const source, |
| EventRewriter* rewriter) |
| : source_(source), |
| rewriter_(rewriter), |
| self_(source->rewriter_list_.end()) {} |
| |
| EventRewriterContinuationImpl(const EventRewriterContinuationImpl&) = delete; |
| EventRewriterContinuationImpl& operator=( |
| const EventRewriterContinuationImpl&) = delete; |
| |
| ~EventRewriterContinuationImpl() override {} |
| |
| EventRewriter* rewriter() const { return rewriter_; } |
| |
| base::WeakPtr<EventRewriterContinuationImpl> GetWeakPtr() { |
| return weak_ptr_factory_.GetWeakPtr(); |
| } |
| |
| // EventRewriterContinuation overrides: |
| EventDispatchDetails SendEvent(const Event* event) override { |
| EventRewriterList::iterator next = self_; |
| ++next; |
| if (next == source_->rewriter_list_.end()) |
| return SendEventFinally(event); |
| return (*next)->rewriter_->RewriteEvent(*event, (*next)->GetWeakPtr()); |
| } |
| |
| EventDispatchDetails SendEventFinally(const Event* event) override { |
| return source_->DeliverEventToSink(const_cast<Event*>(event)); |
| } |
| |
| EventDispatchDetails DiscardEvent() override { |
| ui::EventDispatchDetails details; |
| details.event_discarded = true; |
| return details; |
| } |
| |
| private: |
| const raw_ptr<EventSource> source_; |
| raw_ptr<EventRewriter, DanglingUntriaged> rewriter_; |
| EventRewriterList::iterator self_; |
| |
| base::WeakPtrFactory<EventRewriterContinuationImpl> weak_ptr_factory_{this}; |
| }; |
| |
| EventSource::EventSource() {} |
| |
| EventSource::~EventSource() {} |
| |
| void EventSource::AddEventRewriter(EventRewriter* rewriter) { |
| EventRewriterContinuationImpl::Create(this, rewriter); |
| } |
| |
| void EventSource::RemoveEventRewriter(EventRewriter* rewriter) { |
| EventRewriterList::iterator it = FindContinuation(rewriter); |
| if (it == rewriter_list_.end()) { |
| // We need to tolerate attempting to remove an unregistered |
| // EventRewriter, because many unit tests currently do so: |
| // the rewriter gets added to the current root window source |
| // on construction, and removed from the current root window |
| // source on destruction, but the root window changes in |
| // between. |
| LOG(WARNING) << "EventRewriter not registered"; |
| return; |
| } |
| rewriter_list_.erase(it); |
| } |
| |
| EventDispatchDetails EventSource::SendEventToSink(const Event* event) { |
| return SendEventToSinkFromRewriter(event, nullptr); |
| } |
| |
| EventDispatchDetails EventSource::DeliverEventToSink(Event* event) { |
| EventSink* sink = GetEventSink(); |
| CHECK(sink); |
| return sink->OnEventFromSource(event); |
| } |
| |
| EventDispatchDetails EventSource::SendEventToSinkFromRewriter( |
| const Event* event, |
| const EventRewriter* rewriter) { |
| std::unique_ptr<Event> event_clone; |
| EventRewriterList::iterator it = rewriter_list_.begin(); |
| if (rewriter) { |
| // If a rewriter reposted |event|, only send it to subsequent rewriters. |
| it = FindContinuation(rewriter); |
| CHECK(it != rewriter_list_.end()); |
| ++it; |
| } |
| if (it == rewriter_list_.end()) { |
| return DeliverEventToSink(const_cast<Event*>(event)); |
| } |
| |
| const Event* event_for_rewriting = event; |
| EventRewriterContinuationImpl* const next = it->get(); |
| // Historically, EventRewriters are not expected to honor the event target. |
| // Though, due to observed crashes (see https://crbug.com/1347192), rewriters |
| // are being refactored to honor it. Thus, unless the next rewriter supports |
| // such behavior, event location must be equal to its root_location and target |
| // unset, which is not copied by Event::Clone() call below. |
| if (IsLocatedEventWithDifferentLocations(*event) && |
| !next->rewriter()->SupportsNonRootLocation()) { |
| event_clone = event->Clone(); |
| event_clone->AsLocatedEvent()->set_location_f( |
| event_clone->AsLocatedEvent()->root_location_f()); |
| event_for_rewriting = event_clone.get(); |
| } |
| return next->rewriter()->RewriteEvent(*event_for_rewriting, |
| next->GetWeakPtr()); |
| } |
| |
| EventSource::EventRewriterList::iterator EventSource::FindContinuation( |
| const EventRewriter* rewriter) { |
| auto it = find_if( |
| rewriter_list_.begin(), rewriter_list_.end(), |
| [rewriter](const std::unique_ptr<EventRewriterContinuationImpl>& p) |
| -> bool { return p->rewriter() == rewriter; }); |
| return it; |
| } |
| |
| } // namespace ui |