blob: 7479a97f26f773b7b02b54fe5c27b45a20f5959d [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.
library fuchsia.ui.composition;
using fuchsia.math;
using fuchsia.scenic.scheduling;
using fuchsia.ui.pointer;
using fuchsia.ui.views;
using zx;
/// The set of error codes returned in [`OnError`]. Everything except NO_ERROR, causes Flatland
/// channel to be closed.
type FlatlandError = strict enum {
/// Indicates that the parameters used the function calls are invalid.
BAD_OPERATION = 1;
/// Indicates that `additional_present_credits` field was not properly processed and the client
/// queued more [`Present`]s than allowed.
NO_PRESENTS_REMAINING = 2;
/// Indicates that the client has overwritten hanging gets in the protocols returned.
BAD_HANGING_GET = 3;
};
/// In Flatland, the +X axis is to the right and +Y axis is down. There is no notion of a Z axis.
/// Due to the lack of a Z axis, there is no mathematical notion of "handedness" (either right or
/// left) with respect to rotation. Thus, we define a counter-clockwise rotation in the same way
/// as if a skeuomorphic clock were to be displayed on the screen, with the hands of said clock
/// moving in a CCW motion from the POV of the observer.
type Orientation = strict enum {
CCW_0_DEGREES = 1;
CCW_90_DEGREES = 2;
CCW_180_DEGREES = 3;
CCW_270_DEGREES = 4;
};
/// The set of possible blending functions to choose from when determining how an image should
/// be composited on top of other images.
type BlendMode = strict enum {
/// Indicates that the source pixels replace the destination pixels. In other words,
/// the source pixels are treated as opaque, regardless of what alpha values are set.
SRC = 1;
/// The source pixels are drawn over the destination pixels. The final pixel color
/// that is displayed is calculated as: C_src + (1.0 - alpha_src) * C_dst).
SRC_OVER = 2;
};
/// Represents a color with alpha channel.
/// Values are unorm (i.e. the valid range is [0,1]), and are in linear color
/// space. They are not gamma-corrected nor premultiplied.
type ColorRgba = struct {
red float32;
green float32;
blue float32;
alpha float32;
};
/// The set of possible image flip functions to choose from when determining how the image texture
/// should be displayed.
@available(added=10)
type ImageFlip = strict enum {
NONE = 0;
/// Let V be the vertical axis of reflection, positioned at width/2. Then each pixel's x
/// coordinate is reflected across V. The y coordinates remain constant. For instance:
/// |1234| |4321|
/// |abcd| would become |dcba|
LEFT_RIGHT = 1;
/// Let H be the horizontal axis of reflection, positioned at height/2. Then each pixel's y
/// coordinate is reflected across H. The x coordinates remain constant. For instance:
/// |1234| |abcd|
/// |abcd| would become |1234|
UP_DOWN = 2;
};
/// The return type of [`GetLayout`]. This table contains most of the information necessary
/// for a client to decide how to layout their content in a Flatland instance. This data may be
/// provided to the client before the command that creates the View is presented, so that the
/// client may lay out content properly before their first call to [`Present`].
type LayoutInfo = table {
/// The layout size of a View in logical pixels, defined by the parent's call to
/// [`SetViewportProperties`].
///
/// The logical size also serves as the clip boundary of the View. Anything outside the clip
/// boundary will not be rendered. Hence, the View's Root Transform has a useful coordinate
/// space of (0, 0) to (logical_size.width, logical_size.height).
///
/// Clients should re-layout their content when this value changes.
1: logical_size fuchsia.math.SizeU;
/// The ratio from physical display pixels to logical pixels, defined by the sizes and scale
/// transforms of the parent: each logical pixel is displayed on-screen by one or more physical
/// pixels, as determined by this scale. Clients should not necessarily re-layout their content
/// when this value changes.
///
/// # Removed
///
/// This arg is deprecated at API version 9 with addition of |device_pixel_ratio| and is
/// removed at API version 11.
@available(deprecated=9, removed=11)
2: pixel_scale fuchsia.math.SizeU;
/// The ratio of display's physical pixels to device independent pixels. Each logical pixel of a
/// View is displayed on-screen by one or more physical pixels, as determined by this scale.
/// Clients should not necessarily re-layout their content when this value changes, but
/// accommodate by reallocating their Image buffers to avoid sampling artifacts. The HiDPI-aware
/// client should allocate buffers that are sized (`logical_size`*`device_pixel_ratio`).
@available(added=9)
3: device_pixel_ratio fuchsia.math.VecF;
/// The offsets between the edges and the visible rectangle of the View. The clients can assume
/// that the boundary region between the inset and the View edge is occluded, and should adjust
/// content layout to avoid this region. This inset is described in the view's logical
/// coordinate system. The HiDPI-aware clients should scale this by `device_pixel_ratio`.
@available(added=9)
4: inset fuchsia.math.Inset;
};
/// ParentViewportWatchers will be informed when they are actively attached to a output display
/// (either directly, or through a chain of parent Viewports) and when they are not. Until they are
/// connected to a display, some pieces of information (such as pixel scale) may be unavailable.
type ParentViewportStatus = strict enum {
CONNECTED_TO_DISPLAY = 1;
DISCONNECTED_FROM_DISPLAY = 2;
};
/// A protocol that provides information about the parent Viewport attached to a Flatland instance's
/// sole View. Although Flatland instances can have at most one view, it is possible to have
/// multiple ParentViewportWatchers during the brief transition period when replacing the instance's
/// View with another, e.g. via [`CreateView`]. During this period, certain updates may be
/// duplicated and sent to each ParentViewportWatcher connection.
///
/// A ParentViewportWatcher will remain connected as long as the corresponding parent Viewport
/// exists; the connection will also be closed if the parents's ViewportCreationToken is dropped
/// without using it to create a Viewport.
closed protocol ParentViewportWatcher {
/// A hanging get for receiving layout information. Clients may receive layout information
/// before the ParentViewportWatcher operation has been presented. This allows children to
/// layout their content before their first call to [`Present`]. In transition cases where two
/// ParentViewportWatcher channels exist at the same time, both protocol instances will be
/// receiving different layout information.
///
/// This hanging get will only fire when the LayoutInfo is different than the previously
/// returned LayoutInfo. Note that, since LayoutInfo is a table, only some fields may have
/// changed.
///
/// It is invalid to call `GetLayout` while a previous call is still pending. Doing so will
/// cause both this channel and the Flatland channel that handed out ParentViewportWatcher to be
/// closed.
strict GetLayout() -> (struct {
info LayoutInfo;
});
/// A hanging get for receiving the status of the parent Viewport. This provides global
/// connectivity information to the child.
///
/// This hanging get will only fire when the ParentViewportStatus is different than the
/// previously returned ParentViewportStatus.
///
/// It is invalid to call `GetStatus` while a previous call is still pending. Doing so will
/// cause both this channel and the Flatland channel that handed out ParentViewportWatcher to be
/// closed.
strict GetStatus() -> (struct {
status ParentViewportStatus;
});
};
type ChildViewStatus = strict enum {
/// The underlying Flatland instance has connected its View, called [`Present`], and the
/// acquisition fences of the [`Present`] call have all be reached, indicating that it has some
/// content ready to be displayed, and NOT that the child content has actually been shown on the
/// screen (a common use case is for the parent to wait for the child content to be ready before
/// attaching the child to the global scene graph).
// TODO(https://fxbug.dev/42168962): rename to CONTENT_IS_AVAILABLE.
CONTENT_HAS_PRESENTED = 1;
};
/// A protocol that provides information about a particular child View which is attached to the
/// Viewport owned by the parent client; connections to this protocol are estabished in
/// [`CreateViewport`]. Since a Flatland instance may contain any number of Viewports, each of
/// which may or may not be attached to a transform, the client can maintain connections to an
/// equal number of ChildViewWatcher instances.
///
/// Each ChildViewWatcher instance will remain connected as long as the corresponding child View
/// exists; the connection will also be closed if the child's ViewCreationToken is dropped without
/// using it to create a View.
closed protocol ChildViewWatcher {
/// A hanging get for receiving the status of a View. This provides information to the parent,
/// such as whether or not the child has successfully presented content through this View.
///
/// This hanging get will only fire when the ChildViewStatus is different than the previously
/// returned ChildViewStatus. This can happen immediately, and even if the creator of the
/// Viewport hasn't yet called Present() after calling CreateViewport(). This allows the parent
/// to know that the child has content ready to display before the parent modifies their own
/// local scene graph to incorporate the child content.
///
/// It is invalid to call `GetStatus` while a previous call is still pending. Doing so will
/// cause both this channel and the Flatland channel that handed out ChildViewWatcher to be
/// closed.
strict GetStatus() -> (struct {
status ChildViewStatus;
});
/// Hanging get to receive the ViewRef of the child View. This will only fire when the View ref
/// is different from the previously-returned View ref. Note: currently the View ref will not
/// change after it is first received, but this will change if/when the API changes to allow
/// relinking of views.
///
/// The ViewRef is not returned until the View is included in the View tree, in other words when
/// there is a chain of ancestor transforms all the way back up to the root of the scene graph,
/// i.e. the display.
///
/// It is invalid to call `GetViewRef` while a previous call is still pending. Doing so will
/// cause both this channel and the Flatland channel that handed out ChildViewWatcher to be
/// closed.
///
/// A `GetViewRef` call will hang if the View was created using `CreateView`, but returns the
/// View if the View was created using CreateView2. This is because `CreateView` does not mint
/// a ViewRef for that View.
strict GetViewRef() -> (resource struct {
view_ref fuchsia.ui.views.ViewRef;
});
};
/// The properties of a Viewport as defined by the parent. This data, along with the set of attached
/// Transforms, will be used to compute the LayoutInfo for the View of the Viewport.
/// `ViewportProperties` must have `logical_size` set at least once. This is the initial size that
/// will drive the layout of the child.
type ViewportProperties = table {
/// The size of the Viewport in logical pixels. This maps directly to the logical_size field in
/// LayoutInfo. The valid logical_size must have positive X and Y components.
1: logical_size fuchsia.math.SizeU;
/// The offsets between the edges and the visible rectangle of the Viewport. This maps directly
/// to the `inset` field in LayoutInfo. The valid inset must have all components greater than or
/// equal to 0.
@available(added=9)
2: inset fuchsia.math.Inset;
};
/// The properties of an Image as defined by the client. These properties determine how an Image
/// uses the backing BufferCollection. See [`CreateImage`] for more information.
type ImageProperties = table {
/// The size of the Image in pixels.
1: size fuchsia.math.SizeU;
};
/// A user-defined identifier for a particular transform. See [`CreateTransform`] and
/// [`ReleaseTransform`] for more information.
type TransformId = struct {
value uint64;
};
/// A user-defined identifier for a particular piece of Content. See Content creation functions
/// (e.g. [`CreateViewport`], [`CreateImage`]) for more information.
type ContentId = struct {
value uint64;
};
// A maximum of 16 fences is enough for the current usage of these APIs.
const MAX_PRESENT_ARGS_FENCE_COUNT int32 = 16;
// TODO(https://fxbug.dev/42166463): delete.
const MAX_ACQUIRE_RELEASE_FENCE_COUNT int32 = 16;
/// Arguments passed into [`Present`]. All arguments are optional, and if an
/// argument is omitted Flatland will use a reasonable default, specified below.
type PresentArgs = resource table {
/// `requested_presentation_time` specifies the time on or after which the client would like the
/// enqueued operations to take visible effect (light up pixels on the screen), expressed in
/// nanoseconds in the `CLOCK_MONOTONIC` timebase.
///
/// The default `requested_presentation_time` is 0.
///
/// Using a `requested_presentation_time` in the present or past (such as 0) schedules enqueued
/// operations to take visible effect as soon as possible, during the next frame to be prepared.
///
/// Using a `requested_presentation_time` in the future schedules the enqueued operations to
/// take visible effect on or as closely as possible after the stated time, but no earlier.
///
/// Each rendered frame has a target presentation time. This is when Flatland aims to have the
/// frame presented to the user. Before rendering a frame, Flatland applies all
/// enqueued operations associated with all squashable calls to [`Present`] whose
/// `requested_presentation_time` is on or before the frame's target presentation time.
///
1: requested_presentation_time zx.Time;
/// Flatland will wait until all of a Flatland instance's `acquire_fences` are ready before it
/// will execute the presented commands. Not signaling `acquire_fences` will block the current
/// [`Present`] as well as the following ones even if their `acquire_fences` are signaled.
///
/// The default `acquire_fences` value is the empty vector.
2: acquire_fences vector<zx.Handle:EVENT>:MAX_PRESENT_ARGS_FENCE_COUNT;
/// Flatland will signal all `release_fences` when it is safe to reuse resources which no longer
/// appear in the local scene graph at the time of the current [`Present`]. At the latest, this
/// will happen when the local scene graph (checkpointed at this [`Present`]) has been
/// integrated into the global scene graph, and the global scene has been displayed on screen.
///
/// (Under some circumstances, the fences may be signaled earlier, but clients do not need to
/// worry about this: the fences will only be signaled when it is safe to reuse the associated
/// resources).
///
/// These fences are intended to manage the reuse of shared memory resources such as sysmem
/// buffers. For example, it is undesirable for the client to render into an image which is
/// currently displayed on screen, because this may result in graphical artifacts such as
/// tearing.
///
/// It is up to the client to maintain the mapping between each fence and the resources which
/// will become reusable when the fence is signaled. A common strategy is to keep track of
/// resources which were used by the previous [`Present`] but are no longer used by the current
/// [`Present`]. For example, if an image is removed from the scene by the current [`Present`],
/// the client would insert a fence here. When the fence is later signaled, the client knows
/// that it is safe to render into the image and insert it into the local scene graph in a
/// subsequent [`Present`].
///
/// If an error occurs, Flatland may close the channel without signaling these fences. Clients
/// may immediately release shared buffers, but they should not immediately modify such buffers,
/// because they may still be displayed on screen. There is currently no good signal available
/// to the client about when it is safe to reuse shared buffers.
///
/// The default `release_fences` value is the empty vector.
//
// TODO(https://fxbug.dev/42166476): when fixed, update documentation re: when it is safe to modify buffers
// upon channel closure.
3: release_fences vector<zx.Handle:EVENT>:MAX_PRESENT_ARGS_FENCE_COUNT;
/// If `unsquashable` is true, then the update is guaranteed to be uniquely shown for at
/// least one vsync interval.
///
/// If `unsquashable` is false, then the update can be combined with those that come after
/// it.
///
/// If absent, `unsquashable` is false.
4: unsquashable bool;
/// Unused. Originally intended to be a renaming of `acquire_fences`, but was never hooked up.
@available(deprecated=HEAD)
5: server_wait_fences vector<zx.Handle:EVENT>:MAX_PRESENT_ARGS_FENCE_COUNT;
/// Unused. Originally intended to be a renaming of `release_fences`, but was never hooked up.
@available(deprecated=HEAD)
6: server_signal_fences vector<zx.Handle:EVENT>:MAX_PRESENT_ARGS_FENCE_COUNT;
};
/// A user-defined identifier for future presentation info. A maximum of 8
/// future presentation counts is enough for the current usage of these APIs.
alias FuturePresentationInfos = vector<fuchsia.scenic.scheduling.PresentationInfo>:8;
/// Fields that a client needs in order to produce its next frame, returned in
/// [`OnNextFrameBegin`]. Each field is guaranteed to be set and contain valid information.
type OnNextFrameBeginValues = table {
/// The number of *additional* [`Present`] calls allowed to the client so that they
/// can call [`Present`] further times. This is a delta in the present
/// credit budget, not the absolute number of present credits.
1: additional_present_credits uint32;
/// Information about future presentation and latch times that a client may aim for
/// precise scheduling behavior.
2: future_presentation_infos FuturePresentationInfos;
};
/// The protocol endpoints bound to a Flatland ViewCreationToken. These protocols operate on the
/// View that ViewCreationToken created in the Flatland session.
type ViewBoundProtocols = resource table {
/// Learn when a View gains focus.
///
/// Server-bound ViewRef. The [`view_ref_focused`] client does not specify the ViewRef
/// explicitly; instead, the server implementation uses the ViewRef used in View creation for
/// reporting focus movement on/off this View.
1: view_ref_focused server_end:fuchsia.ui.views.ViewRefFocused;
/// Enable a View to request focus transfer to a child (target) View.
///
/// Server-bound ViewRef. The [`view_focuser`] client does not specify the "requestor" ViewRef
/// explicitly, only the "target" ViewRef. Instead, the server implementation uses the ViewRef
/// used in View creation as the "requestor" ViewRef.
2: view_focuser server_end:fuchsia.ui.views.Focuser;
/// Receive touch events that are associated with a View.
3: touch_source server_end:fuchsia.ui.pointer.TouchSource;
/// Receive mouse events that are associated with a View.
4: mouse_source server_end:fuchsia.ui.pointer.MouseSource;
};
/// A maximum of 64 hit regions is enough for the expected usage of these APIs.
const MAX_HIT_REGION_COUNT int32 = 64;
/// The kind of hit test interaction expected for a hit region.
type HitTestInteraction = flexible enum : uint8 {
/// The natural default behavior is for a hit region to interact with both regular hit testing
/// and accessibility hit testing.
DEFAULT = 0;
/// Some use cases require that a hit region to interact with regular hit testing, but not
/// interact with accessibility hit testing. Here, "semantics" refers to accessibility's
/// semantic tree data, which describes UI elements in a View.
SEMANTICALLY_INVISIBLE = 1;
};
/// An interactive area of a View, placed in the coordinate space of a specific Transform.
type HitRegion = struct {
/// The position and size of this hit region, in the coordinate space of the Transform that owns
/// this hit region.
region fuchsia.math.RectF;
/// The interaction behavior specified for this hit region.
/// To specify "no interaction at all", remove this hit region from the owning Transform.
hit_test HitTestInteraction;
};
/// Each Flatland instance contains a Graph, which consists of a set of objects, and the
/// relationships between those objects. The client can specify a subset of those objects
/// (specifically, the directed acyclic graph starting at the root transform) to be presented as
/// content to some kind of output -- usually, a display.
///
/// Flatland Graphs are both hierarchical, and distributed. Graphs from different Flatland instances
/// may be connected together, allowing multiple processes to be involved in authoring content for a
/// particular output.
///
/// All functions in this protocol are feed-forward. The operations they represent are not fully
/// executed until [`Present`] is called.
@discoverable
closed protocol Flatland {
/// Complete execution of all feed-forward operations.
///
/// If executing an operation produces an error (e.g., CreateTransform(0)), an [`OnError`] event
/// is emitted. Operations that produce errors are ignored and the channel is closed.
///
/// If the execution is completed successfully, [`OnNextFrameBegin`] emits NO_ERROR along
/// with other valid fields.
///
/// The client may only call [`Present`] when they have a non-zero number of present credits,
/// which are tracked by the server. The server may increment the number of credits when it
/// fires the [`OnNextFrameBegin`] event, which informs the client when it receives additional
/// present credits. Each [`Present`] call uses one present credit and decrements the server
/// count by one. If the client calls [`Present`] with no present credits, the server will
/// return a `NO_PRESENTS_REMAINING` error.
///
/// The client should assume that prior to receiving any [`OnNextFrameBegin`] events, they have
/// one present credit.
///
/// Every [`Present`] call results in one [`OnNextFrameBegin`] event, and one
/// [`OnFramePresented`] event, typically in that order.
///
/// When the commands flushed by [`Present`] make it to display, an [`OnFramePresented`] event
/// is fired. This event includes information pertaining to all [`Present`]s that had content
/// that were part of that frame.
///
/// See [`fuchsia.ui.composition/PresentArgs`] documentation above for more detailed information
/// on what arguments are passed in and their role.
strict Present(resource struct {
args PresentArgs;
});
/// This event is fired when clients should expect minimal resource contention. Clients may use
/// the timing of this event to begin their rendering work, using the information returned to
/// inform their scheduling decisions.
///
/// Importantly, OnNextFrameBegin is only fired when the client has one or more present credits,
/// including what is returned in this event. It is therefore safe to present once every time
/// this event fires.
///
/// - response `values` the table of information a client needs to produce its next frame. See
/// [`OnNextFrameBeginValues`] for more information.
strict -> OnNextFrameBegin(struct {
values OnNextFrameBeginValues;
});
/// This event is fired whenever a set of one or more [`Present`]s are presented simultaneously,
/// and are therefore no longer in flight.
///
/// This event signifies that the commands enqueued before the [`Present`] have taken effect in
/// the scene graph, and are globally visible.
///
/// Clients do NOT have to implement a handler for this event for basic frame scheduling, unless
/// they explicitly want feedback on prior frame presentation. All future frame information is
/// given in the [`OnNextFrameBegin`] event.
///
/// TODO(https://fxbug.dev/42141795): remove `num_presents_allowed` from this event.
strict -> OnFramePresented(struct {
frame_presented_info fuchsia.scenic.scheduling.FramePresentedInfo;
});
/// If an error occurs after a [`Present`], an `OnError` event will fire with associated
/// information.
///
/// FlatlandErrors will close the connection with the client.
///
/// - response `error` the error a client may receive after performing some invalid operations.
strict -> OnError(struct {
error FlatlandError;
});
// ***** View management *****
/// Two Flatland instances may be connected in a parent-child relationship. The parent endpoint
/// is held in a Viewport, and the child endpoint is held in a View. The parent Flatland
/// instance that creates a Viewport has control over how the child's View is integrated into
/// its own View.
///
/// The lifecycle of a parent-child connection starts with two endpoints of a channel object:
/// a ViewportCreationToken and a ViewCreationToken. Out-of-band protocols pass the
/// ViewportCreationToken to the parent, which calls [`CreateViewport`], and the
/// ViewCreationToken to the child, which calls [`CreateView`].
///
/// Only nodes connected to the Root Transform in this Flatland instance will be rendered into
/// the parent's Viewport.
///
/// Calling [`CreateView`] a second time will disconnect the Root Transform from the existing
/// parent's Viewport, and attach it to a new parent's Viewport. In other words, each View can
/// only have one parent.
///
/// This function is queued, meaning that the Root Transform will not be attached to the
/// parent Viewport until [`Present`] is called. However, clients will receive information
/// through their ParentViewportWatcher (e.g., LayoutInfo) immediately after calling this
/// function, even if they have not called [`Present`] or [`SetRootTransform`]. This allows
/// clients to wait for layout information from their parent before calling [`Present`].
///
/// Any illegal operations on ParentViewportWatcher will cause both ParentViewportWatcher
/// channel and this Flatland channel to be torn down.
///
/// Lifecycle note. The lifetime of the ParentViewportWatcher channel is bound by the peer
/// ViewportCreationToken. When the ViewportCreationToken dies, this ParentViewportWatcher
/// channel is destroyed.
///
/// Views and subgraphs of Views created using `CreateView` will not be represented in the
/// ViewTree, and hence will not be able to participate in any ViewTree-dependent interactions
/// such as touch, mouse or focus.
/// The Flatland protocol provides no way for Views in the subgraph of a View created with
/// `CreateView` to know that they are excluded from the ViewTree.
strict CreateView(resource struct {
token fuchsia.ui.views.ViewCreationToken;
parent_viewport_watcher server_end:ParentViewportWatcher;
});
/// Identical to [`CreateView`], except it allows association of View identity (ViewRef) and
/// view-bound protocols.
strict CreateView2(resource struct {
/// A typed wrapper for a channel, representing the child endpoint of the connection
/// between two Flatland instances.
token fuchsia.ui.views.ViewCreationToken;
/// The ViewRef to strongly associate with [`token`].
view_identity fuchsia.ui.views.ViewIdentityOnCreation;
/// The protocol endpoints that are strongly bound to the ViewRef in [`view_identity`].
/// The protocols are bound when the view is created and installed in the view tree.
protocols ViewBoundProtocols;
parent_viewport_watcher server_end:ParentViewportWatcher;
});
// ***** Transforms *****
/// Creates a new Transform node. Transforms are a hierarchical piece of a Flatland graph. They
/// can have children, and can reference Content. A sub-graph represented by a Transform and its
/// descendants can be rendered to a display.
///
/// Transforms are kept alive, even when released, as long as they are children of either an
/// unreleased Transform, or the Root Transform.
///
/// Each Transform can have a single piece of attached Content. Common types of Content include
/// bitmaps, asynchronous streams of images, and Viewports to Views hosted in other Flatland
/// instances.
///
/// Transforms have attributes. Child Transforms inherit the combined attributes of their
/// parents. Content attached to a Transform is also affected by that Transform's attributes.
///
/// When a sub-graph of Transforms is rendered, Content will be rendered back-to-front, starting
/// with the Content on the root transform, and continuing recursively through all of its child
/// Transforms in the order the children were added. See [`AddChild`] for more information.
///
/// Zero is not a valid transform id. All other values are valid, assuming they are not already
/// in use (see [`ReleaseTransform`] for more details).
strict CreateTransform(struct {
transform_id TransformId;
});
// ***** Transform Attributes *****
/// All Transform objects support all attributes.
///
/// Geometric attributes are applied in the following order:
/// 1. Scale (relative to the parent transform's coordinate space)
/// 2. Orientation (relative to the parent transform's coordinate space)
/// 3. Translation (relative to the parent transforms's coordinate space,
/// unaffected by scale applied to the current transform).
/// 4. Clipping (relative to the current transform's coordinate space)
///
/// The effects of each of these attributes are cumulative. This means the transform's position
/// in the view space, and its clip boundary, will be calculated based on that chain of
/// geometric attributes going up to the root transform.
///
/// For instance, in a nested hierarchy such as the following:
/// [Root-Transform -> Transform1 -> Transform2 -> CurrentTransform]
/// If Transform1 is translated by [2,0] and Transform2 is translated by [0,1] then the
/// view-space position of CurrentTransform will be [2,1].
///
/// Sets the translation on a Transform. The order of geometric attribute application is
/// addressed above.
strict SetTranslation(struct {
transform_id TransformId;
translation fuchsia.math.Vec;
});
/// Sets the orientation on a Transform. The order of geometric attribute application is
/// addressed in the documentation for [`SetTranslation`]. In Flatland, the +X axis is
/// to the right and the +Y axis is down. There is no notion of a Z axis. CCW is defined
/// from the POV of the user, as if a skeuomorphoic clock is displayed on the screen.
strict SetOrientation(struct {
transform_id TransformId;
orientation Orientation;
});
/// Sets the scale on a transform. The order of geometric attribute application is
/// addressed above. The (x,y) values in the VecF |scale| refer to the scale factor in the
/// x-axis (width) and y-axis (height) respectively. Scale values must be normal 32-bit
/// floating point values: https://en.wikipedia.org/wiki/Normal_number_%28computing%29
strict SetScale(struct {
transform_id TransformId;
scale fuchsia.math.VecF;
});
/// Sets an opacity in linear space to be applied to a transform and its descendents,
/// which include other transforms and content. Opacity values must be in the range
/// of [0.0, 1.0], where 0.0 is completely transparent and 1.0 is completely opaque.
/// Attempting to call this function with values outside that range will result in
/// an error. A transform's opacity value is multiplied with that of its parent. This
/// effect works differently from group opacity. Using group opacity, child nodes are
/// rendered together first, and then have the parent's opacity applied as a post-effect.
/// Here, opacity is applied to each child individually. This may result in a very
/// different effect.
strict SetOpacity(struct {
transform_id TransformId;
value float32;
});
/// Sets the bounds, expressed in the local coordinate space of the transform, that
/// constrains the region that content attached to this transform can be rendered to.
/// If the content's area exceeds the clip bounds, the area outside the bounds will
/// not be rendered. These bounds are valid for all children of this transform node as
/// well, which includes nested Flatland instances and their node hierarchies.
/// If a child transform attempts to set clip bounds larger than that of its parent,
/// it will be clipped to the parent's clip bounds. The default state is for a transform
/// to be unclipped, meaning it will not have any bounds placed on its render region.
/// The clip width/height must be positive. Negative values will result in an error.
/// Passing in an empty box to the |rect| parameter will remove the clip bounds.
strict SetClipBoundary(struct {
transform_id TransformId;
rect box<fuchsia.math.Rect>;
});
// ***** Transform management *****
/// Adds a child Transform to a parent Transform. The new child Transform, and any Content
/// attached to it or its children, will be rendered on top of the parent's Content, as well as
/// any previously added children.
strict AddChild(struct {
parent_transform_id TransformId;
child_transform_id TransformId;
});
/// Removes a child Transform from a parent Transform.
strict RemoveChild(struct {
parent_transform_id TransformId;
child_transform_id TransformId;
});
/// Sets the Root Transform for the graph.
///
/// The sub-graph defined by the Root Transform and its children will be rendered as View
/// in the connected parent's Viewport (see [`CreateView`]). Any parents of the Root Transform
/// in this Graph will be ignored.
///
/// The Root Transform, and all children of the Root Transform, are kept alive if they are
/// released (see [`ReleaseTransform`] for more details).
///
/// There is only ever one Root. Since 0 is not a valid transform id (see [`CreateTransform`]),
/// calling SetRootTransform(0) clears the current Root, destroying any previously released
/// objects that are not referenced by the new root.
///
/// Note that every View has a clip boundary equivalent to its logical size. Anything outside
/// that clip boundary will not be rendered. Hence, the Root Transform has a useful coordinate
/// space of (0, 0) to (logical_size.width, logical_size.height), where (0, 0) is the upper left
/// corner.
///
/// Setting the root transform installs a full screen hit region on the root transform. Clients
/// may remove this hit region if they don't want users to be able to interact with the root
/// transform's content. For additional details on hit regions, see the [`SetHitRegions`]
/// documentation.
///
/// Default hit region rules
///
/// A default hit region follows these rules:
/// - When [`SetRootTransform`](T) is called, T receives a maximal hit region, covering the
/// entire view.
/// - If [`SetHitRegions`] is called on T, either before or after [`SetRootTransform`](T),
/// then no default hit region is active and the client specified hit regions are used.
/// - If a transform is no longer the root transform, i.e., [`SetRootTransform`](U) is
/// called, then the original transform no longer has its default hit region.
/// - Clients can remove or modify the root transform's hit regions the same way they would
/// reset any other transform's hit regions, by calling [`SetHitRegions`] with the appropriate
/// vector.
strict SetRootTransform(struct {
transform_id TransformId;
});
/// Sets the interactive areas for a Transform. By default, Content is not interactive; hit
/// regions must be placed for a user to interact with the Content in a View. Because hit
/// regions are described in the Flatland protocol, a Flatland instance can synchronize Content
/// and hit regions.
///
/// Each hit region is placed in the coordinate space of the owning Transform, and may or may
/// not interact with different types of hit testing, depending on its [`HitTestInteraction`]
/// type. When there are multiple hit regions that intersect with a hit test, the precedence
/// rules given below dictate which hit region has interacted with the hit test. Only Transforms
/// that transitively connect to the root Transform have their hit regions interact with a hit
/// test.
///
/// Calling this function replaces any previous values set on this Transform. To reset a
/// Transform to "no hit testing": send an empty vector with [`SetHitRegions`].
///
/// Note that root transforms get a default hit region installed by Flatland. For more details,
/// see the [`SetRootTransform`] documentation.
///
/// Precedence rules
/// Within a Transform, if multiple hit regions overlap, the hit test examines each
/// intersecting hit region for a possible interaction. Thus, for a regular hit test R and an
/// accessibility hit test A, where R and A both intersect two hit regions D ([`DEFAULT`]) and
/// S ([`SEMANTICALLY_INVISIBLE`]) on the same Transform, (1) R interacts with both D and S,
/// and (2) A only interacts with D. Generally, hit regions that overlap in a single Transform
/// can cause confusing behavior.
///
/// Within a View, for a given hit test, the front-most Transform's hit regions take
/// precedence over those behind. This follows the expected reverse "render order" of
/// Transforms (described in [`CreateTransform`]), where a user expects to interact with
/// Content that is visible, or front-most.
///
/// Across Flatland instances, for a given hit test, the front-most instance's front-most
/// Transform's hit regions take precedence over those behind. This follows the expected
/// reverse "render order" of views, where a user expects to interact with the View that is
/// visible, or front-most. For example, if a child View owns Content that is rendered over
/// the parent View, the user expects to interact with the child's Content.
strict SetHitRegions(struct {
transform_id TransformId;
/// Each region's [`HitRegion.region.width`] and [`HitRegion.region.height`] field must be a
/// non-negative value.
regions vector<HitRegion>:MAX_HIT_REGION_COUNT;
});
/// Identical to [`SetHitRegions`], except the hit region associated with [`transform_id`]
/// covers an infinite region. The hit region is invariant against translation, scaling, and
/// orientation of the Transform.
///
/// An infinite hit region is still limited in extent by the View's clip boundary, just like a
/// finite hit region.
///
/// Calling this function replaces any previous values set on this Transform. To reset a
/// Transform to "no hit testing": send an empty vector with [`SetHitRegions`].
@available(added=10)
strict SetInfiniteHitRegion(struct {
transform_id TransformId;
hit_test HitTestInteraction;
});
// ***** Content *****
//
// Content comes in many forms, but most content can be treated conceptually as a bitmap.
// Content is attached to Transforms. Each Transform can have, at most, one piece of attached
// Content. Content will inherit all of the attributes from its attached Transform (which
// inherits the attributes of its parent Transform, and so on).
//
// Content is contained within a unit rectangle, with the top-left corner at the origin of the
// coordinate space defined by the attached Transform.
/// The Viewport and View pair, together, represent the connection between two Flatland
/// instances. The Viewport is created in the parent, and the View is created in the child. The
/// parent has control over how the child's View is integrated into its own View.
///
/// Any illegal operations on ChildViewWatcher will cause both ChildViewWatcher channel and this
/// Flatland channel to be torn down.
///
/// `ViewportProperties` must have logical_size set. This is the initial size that will drive
/// the layout of the child. The logical_size is also used as the default Content size, but
/// subsequent changes to the logical_size will have no effect on the Content size.
///
/// `ViewportProperties` may have inset field not set. In that case, the default value of
/// (0, 0, 0, 0) is used.
///
/// The logical_size must have positive X and Y components.
///
/// Zero is not a valid ContentId. All other values are valid, assuming they are not already
/// in use for another piece of Content (see [`ReleaseViewport`] for more details).
///
/// Lifecycle note. The lifetime of the ChildViewWatcher channel is bound by the peer
/// ViewCreationToken. When the ViewCreationToken dies, this ChildViewWatcher channel is
/// destroyed.
strict CreateViewport(resource struct {
viewport_id ContentId;
/// A typed wrapper for a channel, representing the parent endpoint of the connection
/// between two Flatland instances.
token fuchsia.ui.views.ViewportCreationToken;
properties ViewportProperties;
child_view_watcher server_end:ChildViewWatcher;
});
/// An Image is a bitmap backed by a specific VMO in a BufferCollection.
///
/// Image creation requires an allocated BufferCollection registered with Allocator. This
/// function will fail unless all clients of the specified BufferCollection have set their
/// constraints.
///
/// The Image must reference a valid VMO index and must have ImageProperties that fall within
/// the constraints specified by the backing BufferCollection (i.e. width and height within a
/// valid range, etc.)
///
/// Zero is not a valid Image id. All other values are valid, assuming they are not already in
/// use for another piece of Content (see [`ReleaseImage`] for more details).
strict CreateImage(resource struct {
image_id ContentId;
import_token BufferCollectionImportToken;
vmo_index uint32;
properties ImageProperties;
});
/// This function is used to determine the region (in texel space) of an image that will be used
/// by Flatland when rendering. The image to be sampled is referenced by [`image_id`] and the
/// sample region is specified by [`rect`] which itself is comprised of an origin point (x,y) as
/// well as a width and height, in unnormalized coordinates. It is illegal to call this function
/// on non-image content, or to sample a region outside of the texel space of the image. In
/// other words, the region specifed by [`rect`] must not exceed the ranges (0, image_width) and
/// (0, image_height). If (rect.x + rect.width > image_width) or (rect.y + rect.height >
/// image_height) or if any of the values are negative, this will result in an error.
///
/// If this method is not called, the default sample region is the rectangle with origin at
/// (0, 0) and width and height set at ImageProperties from [`CreateImage`].
strict SetImageSampleRegion(struct {
image_id ContentId;
rect fuchsia.math.RectF;
});
/// The content size for an Image is the size of the rectangle in the parent's logical
/// coordinate space that the image occupies. This combined with the global translation of the
/// transform it is attached to determines the size and location of where the content is
/// rendered on the display.
///
/// If this method is not called, the default image destination size is the width and height set
/// at ImageProperties from [`CreateImage`]. The destination size will be affected by scaling if
/// [`SetScale`] is used on the attached Transform or its parents.
strict SetImageDestinationSize(struct {
image_id ContentId;
size fuchsia.math.SizeU;
});
/// Determines the blend function to use when rendering the content specified by
/// |image_id|. |image_id| must be a valid ContentId associated to a transform through
/// a call to |CreateImage| or |CreateFilledRect|. For details on the different blend functions
/// that are available, please refer to the BlendMode enum. If this function is not called, then
/// the default blendmode is BlendMode::SRC.
strict SetImageBlendingFunction(struct {
image_id ContentId;
blend_mode BlendMode;
});
/// Sets an opacity in linear space to be applied to a flatland image. Opacity values must
/// be in the range [0.0, 1.0].
strict SetImageOpacity(struct {
image_id ContentId;
val float32;
});
/// Sets the image flip to be applied to a flatland image. This call must be performed after a
/// successful |CreateImage| call. If an invalid |image_id| is supplied, the channel will be
/// closed due to FlatlandError::BAD_OPERATION. This flip will be applied to the Image before
/// parent Transform Orientations. If this function is not called, then the default flip value
/// is ImageFlip::NONE.
@available(added=10)
strict SetImageFlip(struct {
image_id ContentId;
flip ImageFlip;
});
/// Creates a solid-color rectangle. By default a filled-rect does not have a defined
/// color or size. It is necessary to call |SetSolidFill| to specify a color and size
/// before a filled rect can be used for rendering. Not doing so will result the
// rectangle having a default size of (0,0) and so it will not show up when rendering.
strict CreateFilledRect(resource struct {
rect_id ContentId;
});
/// Defines the color and size of a filled rect. |rect_id| must refer to content that
/// was created via a call to CreateFilledRect. The color is not premultiplied. Color values
/// must be within the range [0,1] inclusive, and normal 32-bit
/// floating point values: https://en.wikipedia.org/wiki/Normal_number_%28computing%29. Values
/// that do not conform to these specifications will cause the channel to close.
/// The rectangle's top left corner will be at (0, 0) in its transform's coordinate space.
/// Hence, its bottom right corner will be at (size.width, size.height).
strict SetSolidFill(resource struct {
rect_id ContentId;
color ColorRgba;
size fuchsia.math.SizeU;
});
/// Automatically garbage collects the rectangle when it is no longer needed for
/// rendering. |rect_id| must have been instantiated with a call to
/// |CreateFilledRect|. Once released, the ID immediately goes out of scope and is free
/// to be used again.
strict ReleaseFilledRect(struct {
rect_id ContentId;
});
// ***** Content management *****
/// Setting a piece of Content on a Transform makes that Content visible in the render tree as
/// long as the Transform is visible from the root Transform. The Content will be rendered
/// before, and therefore "behind", any Content attached to the descendants of the Transform.
///
/// Because each Transform can have, at most, a single piece of Content on it, calling this
/// function on a Transform that already has Content will replace that Content.
///
/// A Content may be set on more than one Transform.
///
/// Calling this function with a Content id of 0 will remove any Content currently on the
/// Transform.
strict SetContent(struct {
transform_id TransformId;
content_id ContentId;
});
// ***** Content mutators *****
/// Transforms are usually sufficient to change how Content is presented. Viewports, however,
/// have special properties that are not part of the Transform hierarchy. Those properties can
/// be set using this function.
strict SetViewportProperties(struct {
viewport_id ContentId;
properties ViewportProperties;
});
// ***** Cleanup operations *****
/// Released Transforms will be garbage collected by the system once they are no longer
/// necessary for rendering. For Transforms, this means there is no path from any unreleased
/// Transform to the newly-released Transform.
///
/// Once released, the id immediately goes out of scope for future function calls and can be
/// reused when creating new Transforms.
///
/// It is an error to call functions with a released id (unless that id has been reused to
/// construct a new Transform).
strict ReleaseTransform(struct {
transform_id TransformId;
});
// Releases the View, which disconnects this Flatland instance from its parent Flatland
// instance.
//
// To clear the existing content from the screen without releasing the current View, use
// SetRootTransform(0) instead.
//
// Despite having a return type, this function is still feed-forward Like [`CreateView`] and
// requires a call to [`Present`] to be executed. The ViewCreationToken will be returned after
// the presented operations have been executed.
// TODO(https://fxbug.dev/42162046): Consider re-linking. We can return the ViewCreationToken used to
// establish the View. This token can then be used to establish a new View with the parent
// Viewport.
strict ReleaseView();
/// Releases a Viewport from the scene, even if the Viewport is still connected to a Transform.
/// Unlike other resources, Viewports are garbage collected by the system during the next
/// [`Present`] because a removed Viewport is guaranteed to provide no renderable content.
///
/// Use SetContent(transform_id, 0) to clean up references to released Viewports.
///
/// Despite having a return type, this function is still feed-forward like [`CreateView`] and
/// requires a call to [`Present`] to be executed. The ViewportCreationToken will be returned
/// after the presented operations have been executed.
strict ReleaseViewport(struct {
viewport_id ContentId;
}) -> (resource struct {
token fuchsia.ui.views.ViewportCreationToken;
});
/// Released Images will be garbage collected by the system once they are no longer necessary
/// for rendering. For Images, this means the Image is no longer attached to any Transform and
/// any pending rendering that references the Image is complete.
///
/// Use SetContent(transform_id, 0) to clean up references to released Images.
///
/// Once released, the id immediately goes out of scope for future function calls and can be
/// reused when creating new Images.
///
/// It is an error to call functions with a released id (unless that id has been reused to
/// construct a new Image).
strict ReleaseImage(struct {
image_id ContentId;
});
/// This function will reset all state on this interface. This includes destroying all existing
/// View and Viewports without returning the associated Token to the caller.
strict Clear();
// ***** Debug operations *****
/// Set debug name of the current client that can be used by Flatland to print as a prefix to
/// logs to help client distinguish what is theirs. [`name`] can be an arbitrary string, but the
/// current process name (see fsl::GetCurrentProcessName()) is a good default.
strict SetDebugName(struct {
name string:64;
});
};
// TODO(https://fxbug.dev/42156570): In the future this will be replaced with something
// that allows control over which hardware display to use. This API is sufficient for the purpose
// of initial bringup of Flatland.
/// This API connects to the singleton "primary display", and allows a tree of Flatland content to
/// be attached underneath. Only one FlatlandDisplay client connection is allowed at one time.
@discoverable
closed protocol FlatlandDisplay {
// TODO(https://fxbug.dev/42156570): Consider whether this should be:
// SetContent(ViewportCreationToken token) -> (ViewportCreationToken? previous_token);
// ... this way, whoever is using the display can keep track of multiple different pieces
// of content, and choose which to display. OTOH, an argument could be made that this API
// should be kept as simple as possible, and if one wanted to do this sort of thing they should
// create their own Flatland instance and do the content management there.
strict SetContent(resource struct {
token fuchsia.ui.views.ViewportCreationToken;
child_view_watcher server_end:ChildViewWatcher;
});
/// Sets the ratio of display's physical pixels to device independent pixels that should be used
/// for the tree of Flatland content that are attached to this display. See
/// [`LayoutInfo.device_pixel_ratio`] for details.
///
/// The default value is (1.0, 1.0). The valid values are 1.0 and above.
@available(added=9)
strict SetDevicePixelRatio(struct {
device_pixel_ratio fuchsia.math.VecF;
});
};