chromium/ios/web/find_in_page/find_in_page_manager_impl.h

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef IOS_WEB_FIND_IN_PAGE_FIND_IN_PAGE_MANAGER_IMPL_H_
#define IOS_WEB_FIND_IN_PAGE_FIND_IN_PAGE_MANAGER_IMPL_H_

#import "base/memory/raw_ptr.h"
#import "base/timer/timer.h"
#import "ios/web/public/find_in_page/find_in_page_manager.h"
#import "ios/web/public/web_state_observer.h"

#import "base/memory/weak_ptr.h"

@protocol CRWFindInteraction;
@protocol CRWFindSession;

namespace web {

class FindInPageManagerImpl : public FindInPageManager,
                              public web::WebStateObserver {
 public:
  explicit FindInPageManagerImpl(web::WebState* web_state);
  ~FindInPageManagerImpl() override;

  // AbstractFindInPageManager:
  void Find(NSString* query, FindInPageOptions options) override;
  void StopFinding() override;
  bool CanSearchContent() override;
  FindInPageManagerDelegate* GetDelegate() override;
  void SetDelegate(FindInPageManagerDelegate* delegate) override;

 private:
  friend class web::WebStateUserData<FindInPageManagerImpl>;
  friend class FindInPageManagerImplTest;

  // Lazily creates the Find interaction in the web state and returns it. Should
  // only be called if `use_find_interaction_`.
  id<CRWFindInteraction> GetOrCreateFindInteraction() API_AVAILABLE(ios(16));

  // Executes find logic for `FindInPageSearch` option.
  void StartSearch(NSString* query) API_AVAILABLE(ios(16));
  // Executes find logic for `FindInPageNext` option.
  void SelectNextMatch() API_AVAILABLE(ios(16));
  // Executes find logic for `FindInPagePrevious` option.
  void SelectPreviousMatch() API_AVAILABLE(ios(16));
  // Executes `StopFinding` logic.
  void StopSearch() API_AVAILABLE(ios(16));

  // Returns the currently active Find session if any. If there is a Find
  // interaction in the web state, then its active Find session is returned. If
  // not, `find_session_` is returned.
  id<CRWFindSession> GetActiveFindSession() API_AVAILABLE(ios(16));
  // Start calling `PollActiveFindSession` repeatedly to report Find session
  // results to `delegate_` using `find_session_polling_timer_`.
  void StartPollingActiveFindSession() API_AVAILABLE(ios(16));
  // Stop calling `PollActiveFindSession` repeatedly using
  // `find_session_polling_timer_`.
  void StopPollingActiveFindSession() API_AVAILABLE(ios(16));
  // Report the current Find session's results to `delegate_`.
  void PollActiveFindSession() API_AVAILABLE(ios(16));

  // WebStateObserver overrides
  void WasShown(WebState* web_state) override;
  void WasHidden(WebState* web_state) override;
  void WebStateDestroyed(WebState* web_state) override;

 protected:
  // Last value given to `StartSearch`. This is used in `PollActiveFindSession`
  // so a query value can be provided to the delegate.
  NSString* current_query_ = nil;
  // Last result count reported to the delegate through `DidHighlightMatches`.
  // This is used to ensure nothing is reported if the value has not changed.
  NSInteger current_result_count_ = -1;
  // Last highlighted result index reported to the delegate through
  // `DidSelectMatch`. This is used to ensure nothing is reported if the value
  // has not changed.
  NSInteger current_highlighted_result_index_ = NSNotFound;
  // Timer started in `StartPollingActiveFindSession()` and stopped in
  // `StopPollingActiveFindSession()` to periodically call
  // `PollActiveFindSession()` so as to report any changes in the state of the
  // active Find session to the delegate.
  base::RepeatingTimer find_session_polling_timer_;
  // Delay between each call to `PollActiveFindSession()`.
  base::TimeDelta poll_active_find_session_delay_;

  // Current Find session if `use_find_interaction_` is not `true`. Instantiated
  // in `StartSearch` and set back to `nil` in `StopSearch`.
  id<CRWFindSession> find_session_ API_AVAILABLE(ios(16)) = nil;

  raw_ptr<FindInPageManagerDelegate> delegate_ = nullptr;
  raw_ptr<web::WebState> web_state_ = nullptr;
  base::WeakPtrFactory<FindInPageManagerImpl> weak_factory_;
};

}  // namespace web

#endif  // IOS_WEB_FIND_IN_PAGE_FIND_IN_PAGE_MANAGER_IMPL_H_