blob: 6156a1a9c2d463a5ea96d32541c90df01cc1d83e [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_UI_A11Y_LIB_MAGNIFIER_MAGNIFIER_2_H_
#define SRC_UI_A11Y_LIB_MAGNIFIER_MAGNIFIER_2_H_
#include <lib/zx/time.h>
#include <memory>
#include "src/lib/callback/scoped_task_runner.h"
#include "src/lib/fxl/memory/weak_ptr.h"
#include "src/ui/a11y/lib/gesture_manager/gesture_handler_v2.h"
#include "src/ui/a11y/lib/magnifier/magnifier_util.h"
#include <glm/glm.hpp>
namespace a11y {
class Magnifier2 {
public:
// The entity that interacts directly with scenic to effect visible
// magnification changes to the scene.
class Delegate {
public:
using SetMagnificationTransformCallback = fit::function<void()>;
virtual ~Delegate() = default;
// scale: Scale factor applied to the scene. Must be between kMinScale and
// kMaxScale (defined below).
//
// x: X component of translation applied to the scene.
//
// y: Y component of translation applied to the scene.
//
// callback: Invoked once changes to the magnification transform have reached
// the display.
virtual void SetMagnificationTransform(float scale, float x, float y,
SetMagnificationTransformCallback callback) = 0;
};
// Transition over .2 s @ 60 fps.
static constexpr zx::duration kTransitionPeriod = zx::msec(200);
static constexpr float kTransitionRate = 1 / (kTransitionPeriod.to_msecs() * .060f);
static constexpr float kDragThreshold = 1.f / 16; // NDC
static constexpr float kMinScale = 1, kMaxScale = 20;
static constexpr float kDefaultScale = 4;
static constexpr float kZoomMinFingerDistance =
0.3f; // Distance between the fingers must exceed this value before being considered a zoom.
// This avoids accidental zoom when trying to pan, on small screens. Only relevant
// for persistent zoom mode, since temporary zoom mode never changes the zoom level.
explicit Magnifier2(std::shared_ptr<Delegate> delegate);
~Magnifier2() = default;
// Method to register recognizers in a gesture recognition arena.
void BindGestures(a11y::GestureHandlerV2* gesture_handler);
// Returns the screen to "normal" zoom (scale = 1) if it's currently magnified.
void ZoomOutIfMagnified();
private:
// Indicates magnification mode.
// TODO(https://fxbug.dev/42148902): Mention that there are more details in README doc.
enum class Mode {
// In the unmagnified state, the magnifier is at "normal zoom" and is
// unresponsive to two-finger drags.
UNMAGNIFIED = 0,
// The temporary magnification mode is activated by a
// one-finger-triple-tap-drag or a three-finger-double-tap-drag.
// The screen is magnified to the default scale (kDefaultScale),
// and returns to normal zoom (scale = 1) once the finger(s) are lifted.
// The magnifier is not responive to two-finger drags in temporary
// magnification mode.
TEMPORARY = 1,
// The persistent magnification mode is activated by a one-finger-triple-tap
// or a three-finger-double-tap. The screen remains magnified until the next
// tap gesture explicity returns the magnifier to the unmagnified mode.
// The magnifier is responsive to two-finger drags in persistent
// magnification mode.
PERSISTENT = 2
};
struct State {
// Indicates current mode of magnification.
Mode mode = Mode::UNMAGNIFIED;
// Indicates current pointer locations (if a gesture has been recognized and
// is still in progress).
// This state is necessary to enable us to compute changes in magnification
// scale/translation.
a11y::gesture_util_v2::GestureContext gesture_context;
float transition_rate = 0;
float scale = kDefaultScale;
glm::vec2 translation = {0, 0};
bool operator==(const State& o) const;
bool operator!=(const State& o) const;
// Helper that sets the magnified translation to focus on the given screen coordinate. This does
// not call |UpdateTransform|.
void FocusOn(const ::fuchsia::math::PointF& focus);
// True if a call to SetClipSpaceTransform() is in progress, and we are
// waiting on a response from scenic.
// We need to maintain this state in order to avoid requesting multiple clip
// space transform updates before the first call returns.
bool update_in_progress = false;
// True if the clip space transform requires further updates.
// This state is used to help animate "smooth" transitions between different
// zoom levels.
bool update_pending = false;
// When we transition from one zoom/focus to another, we update the clip
// space transform incrementally to animate a "smooth" transition (e.g.
// instead of changing the scale directly from A->B, we change it from
// A -> (A + delta) -> (A + 2*delta) -> ... -> B).
//
// |transition_progress_| is a float between 0 and 1, and it's used to
// compute the transform at some intermediate point during the transition
// between two zoom/focus states.
float transition_progress = 0;
// Indicates whether to draw the viewport highlight.
// This state is necessary to avoid a race condition when transitioning out
// of zoom where we clear highlights before the transition is complete, in
// which case we would re-draw the magnification highlight (and it would
// never be cleared).
bool draw_highlight = false;
};
// Transitions from unmagnified to magnified at kDefaultScale.
void TransitionIntoZoom();
// Transitions from magnified to unmagnified.
void TransitionOutOfZoom();
// Sends the updated transform to the handler.
void UpdateTransform();
// Toggles persistent magnification on/off.
void TogglePersistentMagnification();
// Updates magnification transform to reflect the state of an in-progress
// drag during temporary magnification.
void HandleTemporaryDrag(const Delta& delta);
// Updates magnification transform to reflect the state of an in-progress
// drag during persistent magnification.
// NOTE: Do NOT update state_.gesture_context prior to calling this method, as
// it requires the "old" gesture context.
void HandlePersistentDrag(const Delta& delta);
// Ensures that the translation falls within the allowable range (as dictated
// by the min/max scale).
void ClampTranslation();
// Magnifier state.
State state_;
// Interfaces with scenic on behalf of the magnifier.
std::shared_ptr<Delegate> delegate_;
};
} // namespace a11y
#endif // SRC_UI_A11Y_LIB_MAGNIFIER_MAGNIFIER_2_H_