1 // This file is part of Desktop App Toolkit,
2 // a set of libraries for developing nice desktop applications.
3 //
4 // For license and copyright information please follow this link:
5 // https://github.com/desktop-app/legal/blob/master/LEGAL
6 //
7 #pragma once
8 
9 #include "lottie/lottie_player.h"
10 #include "base/timer.h"
11 #include "base/algorithm.h"
12 #include "base/flat_set.h"
13 #include "base/flat_map.h"
14 
15 #include <rpl/event_stream.h>
16 
17 namespace Lottie {
18 
19 class Animation;
20 class FrameRenderer;
21 
22 struct MultiUpdate {
23 	//std::variant<
24 	//	std::pair<Animation*, Information>,
25 	//	DisplayMultiFrameRequest,
26 	//	std::pair<Animation*, Error>> data;
27 };
28 
29 class MultiPlayer final : public Player {
30 public:
31 	MultiPlayer(
32 		Quality quality = Quality::Default,
33 		std::shared_ptr<FrameRenderer> renderer = nullptr);
34 	~MultiPlayer();
35 
36 	void start(
37 		not_null<Animation*> animation,
38 		std::unique_ptr<SharedState> state) override;
39 	void failed(not_null<Animation*> animation, Error error) override;
40 	void updateFrameRequest(
41 		not_null<const Animation*> animation,
42 		const FrameRequest &request) override;
43 	bool markFrameShown() override;
44 	void checkStep() override;
45 
46 	not_null<Animation*> append(
47 		const QByteArray &content,
48 		const FrameRequest &request);
49 	not_null<Animation*> append(
50 		FnMut<void(FnMut<void(QByteArray &&cached)>)> get, // Main thread.
51 		FnMut<void(QByteArray &&cached)> put, // Unknown thread.
52 		const QByteArray &content,
53 		const FrameRequest &request);
54 
55 	rpl::producer<MultiUpdate> updates() const;
56 
57 	void remove(not_null<Animation*> animation);
58 
59 	void pause(not_null<Animation*> animation);
60 	void unpause(not_null<Animation*> animation);
61 
62 private:
63 	struct PausedInfo {
64 		not_null<SharedState*> state;
65 		crl::time pauseTime = kTimeUnknown;
66 		crl::time pauseDelay = kTimeUnknown;
67 	};
68 	struct StartingInfo {
69 		std::unique_ptr<SharedState> state;
70 		bool paused = false;
71 	};
72 
73 	void addNewToActive(
74 		not_null<Animation*> animation,
75 		StartingInfo &&info);
76 	[[nodiscard]] int countFrameIndex(
77 		not_null<SharedState*> state,
78 		crl::time time,
79 		crl::time delay) const;
80 	void startAtRightTime(std::unique_ptr<SharedState> state);
81 	void processPending();
82 	void markFrameDisplayed(crl::time now);
83 	void addTimelineDelay(crl::time delayed);
84 	void checkNextFrameAvailability();
85 	void checkNextFrameRender();
86 	void unpauseFirst(
87 		not_null<Animation*> animation,
88 		not_null<SharedState*> state);
89 	void pauseAndSaveState(not_null<Animation*> animation);
90 	void unpauseAndKeepUp(not_null<Animation*> animation);
91 	void removeNow(not_null<Animation*> animation);
92 
93 	Quality _quality = Quality::Default;
94 	base::Timer _timer;
95 	const std::shared_ptr<FrameRenderer> _renderer;
96 	std::vector<std::unique_ptr<Animation>> _animations;
97 	base::flat_map<not_null<Animation*>, not_null<SharedState*>> _active;
98 	base::flat_map<not_null<Animation*>, PausedInfo> _paused;
99 	base::flat_set<not_null<Animation*>> _pendingPause;
100 	base::flat_set<not_null<Animation*>> _pendingUnpause;
101 	base::flat_set<not_null<Animation*>> _pausedBeforeStart;
102 	base::flat_set<not_null<Animation*>> _pendingRemove;
103 	base::flat_map<not_null<Animation*>, StartingInfo> _pendingToStart;
104 	crl::time _started = kTimeUnknown;
105 	crl::time _lastSyncTime = kTimeUnknown;
106 	crl::time _delay = 0;
107 	crl::time _nextFrameTime = kTimeUnknown;
108 	rpl::event_stream<MultiUpdate> _updates;
109 	rpl::lifetime _lifetime;
110 
111 };
112 
113 } // namespace Lottie
114