blob: e3184c8c3862af023073e83310ffccfa8db3465e [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_GLIC_BROWSER_UI_GLIC_ANIMATED_EFFECT_VIEW_H_
#define CHROME_BROWSER_GLIC_BROWSER_UI_GLIC_ANIMATED_EFFECT_VIEW_H_
#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "cc/paint/paint_shader.h"
#include "chrome/browser/glic/public/glic_keyed_service.h"
#include "content/public/browser/gpu_data_manager_observer.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/compositor/compositor_animation_observer.h"
#include "ui/compositor/compositor_observer.h"
#include "ui/gfx/geometry/rounded_corners_f.h"
#include "ui/views/metadata/view_factory.h"
#include "ui/views/view.h"
class Browser;
class ThemeService;
namespace content {
class GpuDataManager;
} // namespace content
namespace glic {
class GlicAnimatedEffectView : public views::View,
public ui::CompositorAnimationObserver,
public ui::CompositorObserver,
public content::GpuDataManagerObserver {
METADATA_HEADER(GlicAnimatedEffectView, views::View)
public:
GlicAnimatedEffectView(const GlicAnimatedEffectView&) = delete;
GlicAnimatedEffectView& operator=(const GlicAnimatedEffectView&) = delete;
~GlicAnimatedEffectView() override;
// `views::View`:
void OnPaint(gfx::Canvas* canvas) override;
// `ui::CompositorAnimationObserver`:
void OnAnimationStep(base::TimeTicks timestamp) override;
// `ui::CompositorObserver`:
void OnCompositingShuttingDown(ui::Compositor* compositor) override;
// `content::GpuDataManagerObserver`:
void OnGpuInfoUpdate() override;
bool IsShowing() const;
// Note: We should avoid adding test-only code in production as it is an
// anti-pattern. There is a planned effort to remove this code and migrate
// to unittests + pixel tests. See https://crbug.com/412335211
float opacity_for_testing() const { return opacity_; }
float progress_for_testing() const { return progress_; }
float GetEffectTimeForTesting() const;
class Tester {
public:
virtual ~Tester() = default;
virtual base::TimeTicks GetTestTimestamp() = 0;
virtual base::TimeTicks GetTestCreationTime() = 0;
virtual void AnimationStarted() = 0;
virtual void AnimationReset() = 0;
virtual void RampDownStarted() = 0;
};
Tester* tester() const { return tester_.get(); }
protected:
GlicAnimatedEffectView(Browser* browser, std::unique_ptr<Tester> tester);
// Returns whether the current effect's animation has completed.
virtual bool IsCycleDone(base::TimeTicks timestamp) = 0;
// Sets the shader uniforms for the given effect.
virtual void PopulateShaderUniforms(
std::vector<cc::PaintShader::FloatUniform>& float_uniforms,
std::vector<cc::PaintShader::Float2Uniform>& float2_uniforms,
std::vector<cc::PaintShader::Float4Uniform>& float4_uniforms,
std::vector<cc::PaintShader::IntUniform>& int_uniforms) const = 0;
// Computes the bounds for the effect and draws to `canvas`.
virtual void DrawEffect(gfx::Canvas* canvas, const cc::PaintFlags& flags) = 0;
void Show();
void StopShowing();
// Only valid to call after the animation has started.
void ResetAnimationCycle();
// A value from 0 to 1 indicating the opacity of the effect.
float GetOpacity(base::TimeTicks timestamp);
// Sets the necessary bits to start ramping down the opacity once it's called.
void StartRampingDown();
// Returns the effect evolution time; wraps after an hour.
float GetEffectTime() const;
// Returns a value from 0 to 1 indicating progress through the effect.
float GetEffectProgress(base::TimeTicks timestamp) const;
// new helper
virtual base::TimeDelta GetTotalDuration() const = 0;
// Returns the timestamp when the instance was created (but permits being
// adjusted by the Tester).
base::TimeTicks GetCreationTime() const;
bool ForceSimplifiedShader() const;
GlicKeyedService* GetGlicService() const;
void UpdateShader();
raw_ptr<Browser> browser_ = nullptr;
std::string shader_;
// When it is true, the class directly presents a static visual component and
// when it is false, it animates the effect first.
// TODO(crbug.com/433136761): Implement a simplified underline with clearer
// difference in motion.
bool skip_animation_cycle_ = false;
float opacity_ = 0.f;
float progress_ = 0.f;
// Note: not relevant to calculations for the tab underline implementation of
// the effect.
float emphasis_ = 0.f;
gfx::RoundedCornersF corner_radius_;
const base::TimeTicks creation_time_;
base::TimeTicks first_frame_time_;
base::TimeTicks first_cycle_frame_;
base::TimeTicks last_cycle_frame_;
base::TimeTicks last_animation_step_time_;
base::TimeDelta total_steady_time_;
bool record_first_ramp_down_frame_ = false;
base::TimeTicks first_ramp_down_frame_;
// See crbug.com/407106595: Allows the effect animation to play seamlessly
// when the browser UI has lost focus temporarily.
// TODO(crbug.com/408210785): Add a test for this case.
float ramp_down_opacity_ = 0.f;
bool has_hardware_acceleration_ = false;
base::ScopedObservation<content::GpuDataManager,
content::GpuDataManagerObserver>
gpu_data_manager_observer_{this};
base::ScopedObservation<ui::Compositor, ui::CompositorObserver>
compositor_observation_{this};
base::ScopedObservation<ui::Compositor, ui::CompositorAnimationObserver>
compositor_animation_observation_{this};
// Empty in production environment.
const std::unique_ptr<Tester> tester_;
sk_sp<cc::PaintShader> cached_paint_shader_;
const std::vector<SkColor> colors_;
const std::vector<float> floats_;
raw_ptr<ui::Compositor> compositor_ = nullptr;
raw_ptr<ThemeService> theme_service_ = nullptr;
};
BEGIN_VIEW_BUILDER(, GlicAnimatedEffectView, views::View)
END_VIEW_BUILDER
} // namespace glic
#endif // CHROME_BROWSER_GLIC_BROWSER_UI_GLIC_ANIMATED_EFFECT_VIEW_H_