1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef COMMON_PLATFORM_VIEW_H_
6#define COMMON_PLATFORM_VIEW_H_
7
8#include <memory>
9
10#include "flutter/common/task_runners.h"
11#include "flutter/flow/surface.h"
12#include "flutter/flow/texture.h"
13#include "flutter/fml/macros.h"
14#include "flutter/fml/memory/weak_ptr.h"
15#include "flutter/lib/ui/semantics/custom_accessibility_action.h"
16#include "flutter/lib/ui/semantics/semantics_node.h"
17#include "flutter/lib/ui/window/platform_message.h"
18#include "flutter/lib/ui/window/pointer_data_packet.h"
19#include "flutter/lib/ui/window/pointer_data_packet_converter.h"
20#include "flutter/lib/ui/window/viewport_metrics.h"
21#include "flutter/shell/common/pointer_data_dispatcher.h"
22#include "flutter/shell/common/vsync_waiter.h"
23#include "third_party/skia/include/core/SkSize.h"
24#include "third_party/skia/include/gpu/GrDirectContext.h"
25
26namespace flutter {
27
28class Shell;
29
30//------------------------------------------------------------------------------
31/// @brief Platform views are created by the shell on the platform task
32/// runner. Unless explicitly specified, all platform view methods
33/// are called on the platform task runner as well. Platform views
34/// are usually sub-classed on a per platform basis and the bulk of
35/// the window system integration happens using that subclass. Since
36/// most platform window toolkits are usually only safe to access on
37/// a single "main" thread, any interaction that requires access to
38/// the underlying platform's window toolkit is routed through the
39/// platform view associated with that shell. This involves
40/// operations like settings up and tearing down the render surface,
41/// platform messages, interacting with accessibility features on
42/// the platform, input events, etc.
43///
44class PlatformView {
45 public:
46 //----------------------------------------------------------------------------
47 /// @brief Used to forward events from the platform view to interested
48 /// subsystems. This forwarding is done by the shell which sets
49 /// itself up as the delegate of the platform view.
50 ///
51 class Delegate {
52 public:
53 //--------------------------------------------------------------------------
54 /// @brief Notifies the delegate that the platform view was created
55 /// with the given render surface. This surface is platform
56 /// (iOS, Android) and client-rendering API (OpenGL, Software,
57 /// Metal, Vulkan) specific. This is usually a sign to the
58 /// rasterizer to setup and begin rendering to that surface.
59 ///
60 /// @param[in] surface The surface
61 ///
62 virtual void OnPlatformViewCreated(std::unique_ptr<Surface> surface) = 0;
63
64 //--------------------------------------------------------------------------
65 /// @brief Notifies the delegate that the platform view was destroyed.
66 /// This is usually a sign to the rasterizer to suspend
67 /// rendering a previously configured surface and collect any
68 /// intermediate resources.
69 ///
70 virtual void OnPlatformViewDestroyed() = 0;
71
72 //--------------------------------------------------------------------------
73 /// @brief Notifies the delegate that the specified callback needs to
74 /// be invoked after the rasterizer is done rendering the next
75 /// frame. This callback will be called on the render thread and
76 /// it is caller responsibility to perform any re-threading as
77 /// necessary. Due to the asynchronous nature of rendering in
78 /// Flutter, embedders usually add a placeholder over the
79 /// contents in which Flutter is going to render when Flutter is
80 /// first initialized. This callback may be used as a signal to
81 /// remove that placeholder.
82 ///
83 /// @attention The callback will be invoked on the render thread and not
84 /// the calling thread.
85 ///
86 /// @param[in] closure The callback to execute on the next frame.
87 ///
88 virtual void OnPlatformViewSetNextFrameCallback(
89 const fml::closure& closure) = 0;
90
91 //--------------------------------------------------------------------------
92 /// @brief Notifies the delegate the viewport metrics of the platform
93 /// view have been updated. The rasterizer will need to be
94 /// reconfigured to render the frame in the updated viewport
95 /// metrics.
96 ///
97 /// @param[in] metrics The updated viewport metrics.
98 ///
99 virtual void OnPlatformViewSetViewportMetrics(
100 const ViewportMetrics& metrics) = 0;
101
102 //--------------------------------------------------------------------------
103 /// @brief Notifies the delegate that the platform has dispatched a
104 /// platform message from the embedder to the Flutter
105 /// application. This message must be forwarded to the running
106 /// isolate hosted by the engine on the UI thread.
107 ///
108 /// @param[in] message The platform message to dispatch to the running
109 /// root isolate.
110 ///
111 virtual void OnPlatformViewDispatchPlatformMessage(
112 fml::RefPtr<PlatformMessage> message) = 0;
113
114 //--------------------------------------------------------------------------
115 /// @brief Notifies the delegate that the platform view has encountered
116 /// a pointer event. This pointer event needs to be forwarded to
117 /// the running root isolate hosted by the engine on the UI
118 /// thread.
119 ///
120 /// @param[in] packet The pointer data packet containing multiple pointer
121 /// events.
122 ///
123 virtual void OnPlatformViewDispatchPointerDataPacket(
124 std::unique_ptr<PointerDataPacket> packet) = 0;
125
126 //--------------------------------------------------------------------------
127 /// @brief Notifies the delegate that the platform view has encountered
128 /// an accessibility related action on the specified node. This
129 /// event must be forwarded to the running root isolate hosted
130 /// by the engine on the UI thread.
131 ///
132 /// @param[in] id The identifier of the accessibility node.
133 /// @param[in] action The accessibility related action performed on the
134 /// node of the specified ID.
135 /// @param[in] args An optional list of argument that apply to the
136 /// specified action.
137 ///
138 virtual void OnPlatformViewDispatchSemanticsAction(
139 int32_t id,
140 SemanticsAction action,
141 std::vector<uint8_t> args) = 0;
142
143 //--------------------------------------------------------------------------
144 /// @brief Notifies the delegate that the embedder has expressed an
145 /// opinion about whether the accessibility tree needs to be
146 /// enabled or disabled. This information needs to be forwarded
147 /// to the root isolate running on the UI thread.
148 ///
149 /// @param[in] enabled Whether the accessibility tree is enabled or
150 /// disabled.
151 ///
152 virtual void OnPlatformViewSetSemanticsEnabled(bool enabled) = 0;
153
154 //--------------------------------------------------------------------------
155 /// @brief Notifies the delegate that the embedder has expressed an
156 /// opinion about the features to enable in the accessibility
157 /// tree.
158 ///
159 /// The engine does not care about the accessibility feature
160 /// flags as all it does is forward this information from the
161 /// embedder to the framework. However, curious readers may
162 /// refer to `AccessibilityFeatures` in `window.dart` for
163 /// currently supported accessibility feature flags.
164 ///
165 /// @param[in] flags The features to enable in the accessibility tree.
166 ///
167 virtual void OnPlatformViewSetAccessibilityFeatures(int32_t flags) = 0;
168
169 //--------------------------------------------------------------------------
170 /// @brief Notifies the delegate that the embedder has specified a
171 /// texture that it want the rasterizer to composite within the
172 /// Flutter layer tree. All textures must have a unique
173 /// identifier. When the rasterizer encounters an external
174 /// texture within its hierarchy, it gives the embedder a chance
175 /// to update that texture on the raster thread before it
176 /// composites the same on-screen.
177 ///
178 /// @param[in] texture The texture that is being updated by the embedder
179 /// but composited by Flutter in its own hierarchy.
180 ///
181 virtual void OnPlatformViewRegisterTexture(
182 std::shared_ptr<Texture> texture) = 0;
183
184 //--------------------------------------------------------------------------
185 /// @brief Notifies the delegate that the embedder will no longer
186 /// attempt to composite the specified texture within the layer
187 /// tree. This allows the rasterizer to collect associated
188 /// resources.
189 ///
190 /// @param[in] texture_id The identifier of the texture to unregister. If
191 /// the texture has not been previously registered,
192 /// this call does nothing.
193 ///
194 virtual void OnPlatformViewUnregisterTexture(int64_t texture_id) = 0;
195
196 //--------------------------------------------------------------------------
197 /// @brief Notifies the delegate that the embedder has updated the
198 /// contents of the texture with the specified identifier.
199 /// Typically, Flutter will only render a frame if there is an
200 /// updated layer tree. However, in cases where the layer tree
201 /// is static but one of the externally composited textures has
202 /// been updated by the embedder, the embedder needs to notify
203 /// the rasterizer to render a new frame. In such cases, the
204 /// existing layer tree may be reused with the frame composited
205 /// with all updated external textures.
206 ///
207 /// @param[in] texture_id The identifier of the texture that has been
208 /// updated.
209 ///
210 virtual void OnPlatformViewMarkTextureFrameAvailable(
211 int64_t texture_id) = 0;
212
213 //--------------------------------------------------------------------------
214 /// @brief Directly invokes platform-specific APIs to compute the
215 /// locale the platform would have natively resolved to.
216 ///
217 /// @param[in] supported_locale_data The vector of strings that represents
218 /// the locales supported by the app.
219 /// Each locale consists of three
220 /// strings: languageCode, countryCode,
221 /// and scriptCode in that order.
222 ///
223 /// @return A vector of 3 strings languageCode, countryCode, and
224 /// scriptCode that represents the locale selected by the
225 /// platform. Empty strings mean the value was unassigned. Empty
226 /// vector represents a null locale.
227 ///
228 virtual std::unique_ptr<std::vector<std::string>>
229 ComputePlatformViewResolvedLocale(
230 const std::vector<std::string>& supported_locale_data) = 0;
231 };
232
233 //----------------------------------------------------------------------------
234 /// @brief Creates a platform view with the specified delegate and task
235 /// runner. The base class by itself does not do much but is
236 /// suitable for use in test environments where full platform
237 /// integration may not be necessary. The platform view may only
238 /// be created, accessed and destroyed on the platform task
239 /// runner.
240 ///
241 /// @param delegate The delegate. This is typically the shell.
242 /// @param[in] task_runners The task runners used by this platform view.
243 ///
244 explicit PlatformView(Delegate& delegate, TaskRunners task_runners);
245
246 //----------------------------------------------------------------------------
247 /// @brief Destroys the platform view. The platform view is owned by the
248 /// shell and will be destroyed by the same on the platform tasks
249 /// runner.
250 ///
251 virtual ~PlatformView();
252
253 //----------------------------------------------------------------------------
254 /// @brief Invoked by the shell to obtain a platform specific vsync
255 /// waiter. It is optional for platforms to override this method
256 /// and provide a custom vsync waiter because a timer based
257 /// fall-back waiter is used by default. However, it is highly
258 /// recommended that platform provide their own Vsync waiter as
259 /// the timer based fall-back will not render frames aligned with
260 /// vsync boundaries.
261 ///
262 /// @attention If a timer based fall-back is used, a warning is logged to the
263 /// console. In case this method is overridden in a subclass, it
264 /// must return a valid vsync waiter. Returning null will lead to
265 /// internal errors. If a valid vsync waiter cannot be returned,
266 /// subclasses should just call the based class method instead.
267 ///
268 /// @return A vsync waiter. If is an internal error to return a null
269 /// waiter.
270 ///
271 virtual std::unique_ptr<VsyncWaiter> CreateVSyncWaiter();
272
273 //----------------------------------------------------------------------------
274 /// @brief Used by embedders to dispatch a platform message to a
275 /// running root isolate hosted by the engine. If an isolate is
276 /// not running, the message is dropped. If there is no one on the
277 /// other side listening on the channel, the message is dropped.
278 /// When a platform message is dropped, any response handles
279 /// associated with that message will be dropped as well. All
280 /// users of platform messages must assume that message may not be
281 /// delivered and/or their response handles may not be invoked.
282 /// Platform messages are not buffered.
283 ///
284 /// For embedders that wish to respond to platform message
285 /// directed from the framework to the embedder, the
286 /// `HandlePlatformMessage` method may be overridden.
287 ///
288 /// @see HandlePlatformMessage()
289 ///
290 /// @param[in] message The platform message to deliver to the root isolate.
291 ///
292 void DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message);
293
294 //----------------------------------------------------------------------------
295 /// @brief Overridden by embedders to perform actions in response to
296 /// platform messages sent from the framework to the embedder.
297 /// Default implementation of this method simply returns an empty
298 /// response.
299 ///
300 /// Embedders that wish to send platform messages to the framework
301 /// may use the `DispatchPlatformMessage` method. This method is
302 /// for messages that go the other way.
303 ///
304 /// @see DisplatchPlatformMessage()
305 ///
306 /// @param[in] message The message
307 ///
308 virtual void HandlePlatformMessage(fml::RefPtr<PlatformMessage> message);
309
310 //----------------------------------------------------------------------------
311 /// @brief Used by embedders to dispatch an accessibility action to a
312 /// running isolate hosted by the engine.
313 ///
314 /// @param[in] id The identifier of the accessibility node on which to
315 /// perform the action.
316 /// @param[in] action The action
317 /// @param[in] args The arguments
318 ///
319 void DispatchSemanticsAction(int32_t id,
320 SemanticsAction action,
321 std::vector<uint8_t> args);
322
323 //----------------------------------------------------------------------------
324 /// @brief Used by embedder to notify the running isolate hosted by the
325 /// engine on the UI thread that the accessibility tree needs to
326 /// be generated.
327 ///
328 /// @attention Subclasses may choose to override this method to perform
329 /// platform specific functions. However, they must call the base
330 /// class method at some point in their implementation.
331 ///
332 /// @param[in] enabled Whether the accessibility tree needs to be generated.
333 ///
334 virtual void SetSemanticsEnabled(bool enabled);
335
336 //----------------------------------------------------------------------------
337 /// @brief Used by the embedder to specify the features to enable in the
338 /// accessibility tree generated by the isolate. This information
339 /// is forwarded to the root isolate hosted by the engine on the
340 /// UI thread.
341 ///
342 /// The engine does not care about the accessibility feature flags
343 /// as all it does is forward this information from the embedder
344 /// to the framework. However, curious readers may refer to
345 /// `AccessibilityFeatures` in `window.dart` for currently
346 /// supported accessibility feature flags.
347 ///
348 /// @attention Subclasses may choose to override this method to perform
349 /// platform specific functions. However, they must call the base
350 /// class method at some point in their implementation.
351 ///
352 /// @param[in] flags The features to enable in the accessibility tree.
353 ///
354 virtual void SetAccessibilityFeatures(int32_t flags);
355
356 //----------------------------------------------------------------------------
357 /// @brief Used by the framework to tell the embedder to apply the
358 /// specified semantics node updates. The default implementation
359 /// of this method does nothing.
360 ///
361 /// @see SemanticsNode, SemticsNodeUpdates,
362 /// CustomAccessibilityActionUpdates
363 ///
364 /// @param[in] updates A map with the stable semantics node identifier as
365 /// key and the node properties as the value.
366 /// @param[in] actions A map with the stable semantics node identifier as
367 /// key and the custom node action as the value.
368 ///
369 virtual void UpdateSemantics(SemanticsNodeUpdates updates,
370 CustomAccessibilityActionUpdates actions);
371
372 //----------------------------------------------------------------------------
373 /// @brief Used by embedders to specify the updated viewport metrics. In
374 /// response to this call, on the raster thread, the rasterizer
375 /// may need to be reconfigured to the updated viewport
376 /// dimensions. On the UI thread, the framework may need to start
377 /// generating a new frame for the updated viewport metrics as
378 /// well.
379 ///
380 /// @param[in] metrics The updated viewport metrics.
381 ///
382 void SetViewportMetrics(const ViewportMetrics& metrics);
383
384 //----------------------------------------------------------------------------
385 /// @brief Used by embedders to notify the shell that a platform view
386 /// has been created. This notification is used to create a
387 /// rendering surface and pick the client rendering API to use to
388 /// render into this surface. No frames will be scheduled or
389 /// rendered before this call. The surface must remain valid till
390 /// the corresponding call to NotifyDestroyed.
391 ///
392 void NotifyCreated();
393
394 //----------------------------------------------------------------------------
395 /// @brief Used by embedders to notify the shell that the platform view
396 /// has been destroyed. This notification used to collect the
397 /// rendering surface and all associated resources. Frame
398 /// scheduling is also suspended.
399 ///
400 /// @attention Subclasses may choose to override this method to perform
401 /// platform specific functions. However, they must call the base
402 /// class method at some point in their implementation.
403 ///
404 virtual void NotifyDestroyed();
405
406 //----------------------------------------------------------------------------
407 /// @brief Used by the shell to obtain a Skia GPU context that is capable
408 /// of operating on the IO thread. The context must be in the same
409 /// share-group as the Skia GPU context used on the render thread.
410 /// This context will always be used on the IO thread. Because it
411 /// is in the same share-group as the separate render thread
412 /// context, any GPU resources uploaded in this context will be
413 /// visible to the render thread context (synchronization of GPU
414 /// resources is managed by Skia).
415 ///
416 /// If such context cannot be created on the IO thread, callers
417 /// may return `nullptr`. This will mean that all texture uploads
418 /// will be queued onto the render thread which will cause
419 /// performance issues. When this context is `nullptr`, an error
420 /// is logged to the console. It is highly recommended that all
421 /// platforms provide a resource context.
422 ///
423 /// @attention Unlike all other methods on the platform view, this will be
424 /// called on IO task runner.
425 ///
426 /// @return The Skia GPU context that is in the same share-group as the
427 /// main render thread GPU context. May be `nullptr` in case such
428 /// a context cannot be created.
429 ///
430 virtual sk_sp<GrDirectContext> CreateResourceContext() const;
431
432 //----------------------------------------------------------------------------
433 /// @brief Used by the shell to notify the embedder that the resource
434 /// context previously obtained via a call to
435 /// `CreateResourceContext()` is being collected. The embedder is
436 /// free to collect an platform specific resources associated with
437 /// this context.
438 ///
439 /// @attention Unlike all other methods on the platform view, this will be
440 /// called on IO task runner.
441 ///
442 virtual void ReleaseResourceContext() const;
443
444 //--------------------------------------------------------------------------
445 /// @brief Returns a platform-specific PointerDataDispatcherMaker so the
446 /// `Engine` can construct the PointerDataPacketDispatcher based
447 /// on platforms.
448 virtual PointerDataDispatcherMaker GetDispatcherMaker();
449
450 //----------------------------------------------------------------------------
451 /// @brief Returns a weak pointer to the platform view. Since the
452 /// platform view may only be created, accessed and destroyed
453 /// on the platform thread, any access to the platform view
454 /// from a non-platform task runner needs a weak pointer to
455 /// the platform view along with a reference to the platform
456 /// task runner. A task must be posted to the platform task
457 /// runner with the weak pointer captured in the same. The
458 /// platform view method may only be called in the posted task
459 /// once the weak pointer validity has been checked. This
460 /// method is used by callers to obtain that weak pointer.
461 ///
462 /// @return The weak pointer to the platform view.
463 ///
464 fml::WeakPtr<PlatformView> GetWeakPtr() const;
465
466 //----------------------------------------------------------------------------
467 /// @brief Gives embedders a chance to react to a "cold restart" of the
468 /// running isolate. The default implementation of this method
469 /// does nothing.
470 ///
471 /// While a "hot restart" patches a running isolate, a "cold
472 /// restart" restarts the root isolate in a running shell.
473 ///
474 virtual void OnPreEngineRestart() const;
475
476 //----------------------------------------------------------------------------
477 /// @brief Sets a callback that gets executed when the rasterizer renders
478 /// the next frame. Due to the asynchronous nature of
479 /// rendering in Flutter, embedders usually add a placeholder
480 /// over the contents in which Flutter is going to render when
481 /// Flutter is first initialized. This callback may be used as
482 /// a signal to remove that placeholder. The callback is
483 /// executed on the render task runner and not the platform
484 /// task runner. It is the embedder's responsibility to
485 /// re-thread as necessary.
486 ///
487 /// @attention The callback is executed on the render task runner and not the
488 /// platform task runner. Embedders must re-thread as necessary.
489 ///
490 /// @param[in] closure The callback to execute on the render thread when the
491 /// next frame gets rendered.
492 ///
493 void SetNextFrameCallback(const fml::closure& closure);
494
495 //----------------------------------------------------------------------------
496 /// @brief Dispatches pointer events from the embedder to the
497 /// framework. Each pointer data packet may contain multiple
498 /// pointer input events. Each call to this method wakes up
499 /// the UI thread.
500 ///
501 /// @param[in] packet The pointer data packet to dispatch to the framework.
502 ///
503 void DispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet);
504
505 //--------------------------------------------------------------------------
506 /// @brief Used by the embedder to specify a texture that it wants the
507 /// rasterizer to composite within the Flutter layer tree. All
508 /// textures must have a unique identifier. When the
509 /// rasterizer encounters an external texture within its
510 /// hierarchy, it gives the embedder a chance to update that
511 /// texture on the raster thread before it composites the same
512 /// on-screen.
513 ///
514 /// @attention This method must only be called once per texture. When the
515 /// texture is updated, calling `MarkTextureFrameAvailable`
516 /// with the specified texture identifier is sufficient to
517 /// make Flutter re-render the frame with the updated texture
518 /// composited in-line.
519 ///
520 /// @see UnregisterTexture, MarkTextureFrameAvailable
521 ///
522 /// @param[in] texture The texture that is being updated by the embedder
523 /// but composited by Flutter in its own hierarchy.
524 ///
525 void RegisterTexture(std::shared_ptr<flutter::Texture> texture);
526
527 //--------------------------------------------------------------------------
528 /// @brief Used by the embedder to notify the rasterizer that it will
529 /// no
530 /// longer attempt to composite the specified texture within
531 /// the layer tree. This allows the rasterizer to collect
532 /// associated resources.
533 ///
534 /// @attention This call must only be called once per texture identifier.
535 ///
536 /// @see RegisterTexture, MarkTextureFrameAvailable
537 ///
538 /// @param[in] texture_id The identifier of the texture to unregister. If
539 /// the texture has not been previously registered,
540 /// this call does nothing.
541 ///
542 void UnregisterTexture(int64_t texture_id);
543
544 //--------------------------------------------------------------------------
545 /// @brief Used by the embedder to notify the rasterizer that the context
546 /// of the previously registered texture have been updated.
547 /// Typically, Flutter will only render a frame if there is an
548 /// updated layer tree. However, in cases where the layer tree
549 /// is static but one of the externally composited textures
550 /// has been updated by the embedder, the embedder needs to
551 /// notify the rasterizer to render a new frame. In such
552 /// cases, the existing layer tree may be reused with the
553 /// frame re-composited with all updated external textures.
554 /// Unlike the calls to register and unregister the texture,
555 /// this call must be made each time a new texture frame is
556 /// available.
557 ///
558 /// @see RegisterTexture, UnregisterTexture
559 ///
560 /// @param[in] texture_id The identifier of the texture that has been
561 /// updated.
562 ///
563 void MarkTextureFrameAvailable(int64_t texture_id);
564
565 //--------------------------------------------------------------------------
566 /// @brief Directly invokes platform-specific APIs to compute the
567 /// locale the platform would have natively resolved to.
568 ///
569 /// @param[in] supported_locale_data The vector of strings that represents
570 /// the locales supported by the app.
571 /// Each locale consists of three
572 /// strings: languageCode, countryCode,
573 /// and scriptCode in that order.
574 ///
575 /// @return A vector of 3 strings languageCode, countryCode, and
576 /// scriptCode that represents the locale selected by the
577 /// platform. Empty strings mean the value was unassigned. Empty
578 /// vector represents a null locale.
579 ///
580 virtual std::unique_ptr<std::vector<std::string>>
581 ComputePlatformResolvedLocales(
582 const std::vector<std::string>& supported_locale_data);
583
584 protected:
585 PlatformView::Delegate& delegate_;
586 const TaskRunners task_runners_;
587
588 PointerDataPacketConverter pointer_data_packet_converter_;
589 SkISize size_;
590 fml::WeakPtrFactory<PlatformView> weak_factory_;
591
592 // Unlike all other methods on the platform view, this is called on the
593 // GPU task runner.
594 virtual std::unique_ptr<Surface> CreateRenderingSurface();
595
596 private:
597 FML_DISALLOW_COPY_AND_ASSIGN(PlatformView);
598};
599
600} // namespace flutter
601
602#endif // COMMON_PLATFORM_VIEW_H_
603