{% set rfcid = “RFC-0147” %} {% include “docs/contribute/governance/rfcs/_common/_rfc_header.md” %}
This RFC provides an overview of the Fuchsia View System: the set of APIs to reason about and interact with visual regions (“Views”) and their lifecycle. This set of functionality is also commonly referred to on other platforms as a windowing system. The scope of this RFC is limited to products with a single display. Changes to accommodate headless devices and/or multiple displays will be covered in future RFCs.
A View is a region of graphical content, and is the basic unit of graphics and user interaction on Fuchsia. Views connect to form a View tree hierarchy, with a distinguished root View. Fuchsia's graphics compositor, Scenic, renders graphical contents from each View in the View tree to produce output for the display. Scenic and the input pipeline are responsible for routing UI-targeted user input such as keyboard, mouse and touch to the correct View.
The View System is a critical part of the Fuchsia platform‘s support for “bring your own runtime” and the mechanism through which product developers use graphical content from multiple runtimes to build secure visual user experiences on Fuchsia. Fuchsia’s composition APIs (Flatland and GFX) are built on top of the View System.
The goal of this RFC is to document and ratify the “state of the world” with respect to the View System. Specifically, we'd like to ratify the following decisions.
Modifying these decisions requires an additional RFC and/or an update to this RFC.
Note: The the current Fuchsia implementation does contain exceptions to these statements, because it is a work in progress. For example, there is a legacy API that allows global access to pointer events. This RFC is a declaration of our intent to remove these exceptions.
Facilitator:
Reviewers:
This section expected to be updated during the review
Consulted:
sanjayc@google.com, hjfreyer@google.com, jjosh@google.com, lindkvist@google.com, geb@google.com
Socialization:
Draft doc was send to the Scenic and Input teams for discussion.
A Fuchsia View is the basic unit of graphics and interaction on Fuchsia. A View defines a visual region for displaying graphical content to the user. Not all Views are visible at a given time. The graphical contents for each View are supplied by a Fuchsia component. Platform support for managing Views and compositing their contents onto the screen is implemented by Scenic.
Each View:
Any graphical composition API supported by Scenic (such as fuchsia.ui.composition and fuchsia.ui.scenic) must provide methods to create a View and manage its lifecycle. Any future composition APIs must also operate on top of the View System. Fuchsia platform HCI APIs (such as pointer and keyboard) use Views to route input. (See Input below for details.)
There is one global View Tree, which is owned and implemented by Scenic. The View Tree has a distinguished root View that connects to the screen. Scenic is the only Fuchsia component that directly manipulates all Views and their positions.
Each View in a View Tree has bounds defined in its own coordinate system, and a position and orientation expressed in the parent View's coordinate system. Together, these determine the regions where graphical content is ultimately visible on-screen, and regions which are responsive to user input.
A View can embed additional graphical content from another View by creating an empty placeholder for it in its coordinate system; the placeholder is called a viewport. The two Views form a parent-child relationship in the View Tree, where the parent View‘s Viewport embeds a child View’s graphical content. To establish the relationship, the parent and child must provide matching tokens when creating their View and Viewport. These tokens are implemented as kernel objects, and are not clonable. The parent and child may obtain these matching tokens in a variety of ways, which are external to the View System.
Attaching or detaching a parent View from the View Tree also attaches/detaches its child View(s). Connections between Views within a subtree remain even when a subtree is detached from the global View Tree.
Note: The View System provides parent Views with the ability to restrict where their descendent Views can render or receive user input (“clipping”) for security reasons (for example, preventing clickjacking).
While a View can embed another View, the View System does not give a View access to the graphical content of any other View. This isolation guarantee forms one of the bases of View security.
Scenic is the sole component that talks to the display controller. It takes the graphical content of the entire View Tree, along with the relationships encoded in the tree, creates a single image (possibly with multiple layers). It then programs the hardware to display the final on-screen image.
The contents in a View are supplied by a single FIDL channel to a graphical composition API, which is implemented by Scenic. Each client endpoint of a FIDL channel to Scenic is termed a “UI client”, and a UI client can create at most one View.
Views may come from a variety of components including user-facing components (e.g. a browser), the system UI, as well as components that are part of the Fuchsia platform, such as the Accessibility Manager. A component may create multiple channels and thus multiple Views. Consequently, a single component may vend both a parent View and that View's child View in some cases.
In order to combine graphics from multiple components, developers should create a View or Views in each component and use child View and the View Tree to combine them. It is important to note that the View Tree hierarchy does not need to match the component instance hierarchy. In many cases, these structures intentionally look quite different.
For components written in a higher level language (like Dart or Javascript) the runner implementation is typically responsible for creating and managing the View. Developers working in these languages may be unaware of many of the details of the underlying OS; it is the runner's responsibility to translate the View lifecycle into language-specific or runtime-specific mechanisms.
Fuchsia separates three functions that are sometimes combined on other platforms.
The choice to keep the windowing system and composition separate provides a fast-path for graphical presentation and allows for an efficient implementation. While both the View System and the compositor(s) are currently implemented primarily within Scenic, they are separate both in terms of APIs and code. This separation makes it possible for the View System to support multiple composition strategies (Flatland and GFX).
By making window management a product-level concern we keep policy logic outside of the platform, ensuring a clean separation between platform and product.
The View System is the primary mechanism through which the Fuchsia platform determines how to route user input, such as pointer events or keyboard events. Fuchsia's user input APIs are designed such that each channel is scoped to a particular View. Input will be routed to a View based on either the current View focus (in the case of keyboard events) and/or to the View or Views corresponding to the location of the input event (as in the case of touch or mouse events). A View may only receive user input when conntected to the View Tree.
Multiple Views may participate in input processing for the same event. The window manager for a particular product may configure this routing based on product policy, for example by granting global access to mouse events to the system UI. For additional details see User Input Architecture. This system allows seamless user experiences across Views from multiple runtimes, including the ability to disambiguate touch gestures.
One important implication of this is that components outside of the Fuchsia platform do not get direct access to input events from the driver. They must receive this information mediated by the View System.
At any given time the View Tree has one distinguished View, called the focused View. The focused View is typically the View that the user expects will receive user input. Fuchsia's input subsystems rely on View focus as a means of determining where to route input. For additional information see the Focus Chain documentation. A parent View owner may control View focus within its subtree.
The platform uses tokens called ViewRefs to identify and communicate about Views. A ViewRef is a unique reference to a particular View that remains unique until system reboot. It is implemented as a kernel object, the handle of which can be freely duplicated and sent to other components over arbitrary protocols.
The View System APIs make heavy use of ViewRefs to provides a stable cross-component reference for each View. ViewRefs are also used to signal lifecycle events about the associated View. This allows other components inside and outside of the platform to communicate about Views, their lifecycles, and to route user input and accessibility protocols to Views.
Note: ViewRefs are distinct from ViewTokens, ViewHolderTokens, ViewCreationTokens, etc. View*Tokens are used to associate parent and child Views during View creation and installation.
Scenic is the source of authority for the View System because the View Tree and core View management APIs are implemented in Scenic. Each client uses its ViewRef to register to receive user input and accessibility events for the associated View. Scenic currently supports two graphical composition APIs: fuchsia.ui.scenic (legacy) and fuchsia.ui.composition (in development). The View System is independent of, but works in close conjunction, with each.
API implementation details are out of scope for this RFC but the relevant APIs can be found below. It's worth noting that these APIs evolved incrementally over multiple years. Some aspects may be simplified in the future.
Many aspects of the View System influence graphics and input performance. We describe some important aspects below.
The View System makes several guarantees for securely composing graphical content on Fuchsia, and these guarantees form the foundation for a secure UX. However, the View System alone cannot guarantee that every UX is secure - only that the View System respects its own security guarantees.
The View System attempts to enable secure UX by:
UI security relies on the guarantees provided by Component Framework with respect to capability routing. The details of View security will be addressed in future RFCs.
The View System is implemented at multiple layers of abstraction, so it is tested using a layered approach.
Within fuchsia.git:
Out of tree:
This RFC provides a high-level overview of the View System's role and responsibilities. Docs and possibly additional RFCs will be written to address details.
Some of the Scenic documentation will also need to be updated in light of this RFC and upcoming changes for Flatland.
The View System currently lacks a mechanism for synchronizing updates between multiple Views.
The View System is partially responsible for routing capabilities to runtimes that expose Views (using ViewRefs). This has some conceptual overlap with capability routing via Fuchsia's Component Framework, but is currently entirely separate. In the future, it may be advantageous to support View capabilities in the Component Framework.
The current APIs only allow View owners to create child Views. This isn't ideal for something like an application that wishes to create multiple top-level windows.
Because the View System APIs evolved organically over multiple years with many different contributors, the cognitive burden on runtime developers is currently quite high. This should be mitigated in the future by better documentation and examples, and possible API simplification.
The View System architecture makes a number of architectural choices.