chromium/ios/chrome/browser/web/model/font_size/font_size_tab_helper.h

// Copyright 2018 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_CHROME_BROWSER_WEB_MODEL_FONT_SIZE_FONT_SIZE_TAB_HELPER_H_
#define IOS_CHROME_BROWSER_WEB_MODEL_FONT_SIZE_FONT_SIZE_TAB_HELPER_H_

#include <optional>
#include <string>

#import "base/memory/raw_ptr.h"
#import "ios/web/public/js_messaging/web_frames_manager.h"
#include "ios/web/public/web_state_observer.h"
#import "ios/web/public/web_state_user_data.h"

class PrefService;

namespace user_prefs {
class PrefRegistrySyncable;
}

namespace web {
class WebState;
}  // namespace web

enum Zoom {
  ZOOM_OUT = -1,
  ZOOM_RESET = 0,
  ZOOM_IN = 1,
};

// Adjusts font size of web page by mapping
// `UIApplication.sharedApplication.preferredContentSizeCategory` to a scaling
// percentage and setting it to "-webkit-font-size-adjust" style on <body> when
// the page is successfully loaded or system font size changes.
class FontSizeTabHelper : public web::WebFramesManager::Observer,
                          public web::WebStateObserver,
                          public web::WebStateUserData<FontSizeTabHelper> {
 public:
  FontSizeTabHelper(const FontSizeTabHelper&) = delete;
  FontSizeTabHelper& operator=(const FontSizeTabHelper&) = delete;

  ~FontSizeTabHelper() override;

  // Performs a zoom in the given direction on the WebState this is attached to.
  void UserZoom(Zoom zoom);

  // Returns whether the user can still zoom in. (I.e., They have not reached
  // the max zoom level.).
  bool CanUserZoomIn() const;
  // Returns whether the user can still zoom out. (I.e., They have not reached
  // the min zoom level.).
  bool CanUserZoomOut() const;
  // Returns whether the user can reset the zoom level. (I.e., They are not at
  // the default zoom level.)
  bool CanUserResetZoom() const;

  // Returns true if the Text Zoom process is currently active.
  bool IsTextZoomUIActive() const;

  // Marks the Text Zoom process as active or not.  This method does not
  // directly show or hide the UI.  It simply acts as a marker for whether or
  // not the UI should be displayed when possible.
  void SetTextZoomUIActive(bool active);

  // Text zoom is currently only supported on HTML pages.
  bool CurrentPageSupportsTextZoom() const;

  // Remove any stored zoom levels from `pref_service`.
  static void ClearUserZoomPrefs(PrefService* pref_service);

  static void RegisterBrowserStatePrefs(
      user_prefs::PrefRegistrySyncable* registry);

 private:
  friend class web::WebStateUserData<FontSizeTabHelper>;

  explicit FontSizeTabHelper(web::WebState* web_state);

  // Sets font size in web page by scaling percentage.
  void SetPageFontSize(int size);

  // Returns the true font size in scaling percentage (e.g. 150 for
  // 150%) taking all sources into account (system level and user zoom).
  int GetFontSize() const;

  // Used in callbacks related to `notification_observer_`.
  void OnContentSizeCategoryChanged();

  // Set the zoom level correctly for a new navigation.
  void NewPageZoom();

  PrefService* GetPrefService() const;

  // Logs any events after zooming.
  void LogZoomEvent(Zoom zoom) const;

  // Returns the new multiplier after zooming in the given direction. Returns
  // nullopt if it is impossible to zoom in the given direction;
  std::optional<double> NewMultiplierAfterZoom(Zoom zoom) const;
  // Returns the current user zoom multiplier (i.e. not counting any additional
  // zoom due to the system accessibility settings).
  double GetCurrentUserZoomMultiplier() const;
  void StoreCurrentUserZoomMultiplier(double multiplier);
  std::string GetCurrentUserZoomMultiplierKey() const;
  std::string GetUserZoomMultiplierKeyUrlPart() const;
  bool IsGoogleCachedAMPPage() const;
  bool tab_helper_has_zoomed_ = false;

  // web::WebStateObserver overrides:
  void PageLoaded(
      web::WebState* web_state,
      web::PageLoadCompletionStatus load_completion_status) override;
  void WebStateDestroyed(web::WebState* web_state) override;
  void DidFinishNavigation(web::WebState* web_state,
                           web::NavigationContext* context) override;
  void WebStateRealized(web::WebState* web_state) override;

  // Helper used to create notification observer.
  void CreateNotificationObserver();

  // web::WebFramesManager::Observer
  void WebFrameBecameAvailable(web::WebFramesManager* web_frames_manager,
                               web::WebFrame* web_frame) override;

  // WebState this tab helper is attached to.
  raw_ptr<web::WebState> web_state_ = nullptr;
  // Whether the Text Zoom UI is active
  bool text_zoom_ui_active_ = false;
  // Holds references to NSNotification callback observer.
  id notification_observer_;

  WEB_STATE_USER_DATA_KEY_DECL();

  base::WeakPtrFactory<FontSizeTabHelper> weak_factory_;
};

#endif  // IOS_CHROME_BROWSER_WEB_MODEL_FONT_SIZE_FONT_SIZE_TAB_HELPER_H_