blob: d07bc33a4ffb0dbf8ae4eb187ab4749fb1a2a22c [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.observation.geometry;
using fuchsia.math as math;
using zx;
const BUFFER_SIZE uint32 = 512;
const MAX_VIEW_COUNT uint32 = 1024;
/// A description of abnormal conditions.
type Error = flexible enum {
/// The number of snapshots exceeded BUFFER_SIZE; pending data is discarded.
BUFFER_OVERFLOW = 1;
};
/// A method of obtaining view tree snapshots for a particular view, the "context
/// view", and its child views, if any. The returned data is a sequence of
/// snapshots during the period of observation, which starts at the client's
/// prior Watch() call's [`epoch_end`] (or zx.time 0), and ending at the
/// current [`epoch_end`]. The timebase is ZX_CLOCK_MONOTONIC.
///
/// Usage note. With this protocol, a client can watch for changes to the view
/// tree over which it has authority. For example, if a client owns view A, then
/// A serves as the context view for A's subtree (i.e., a "root view"), where A
/// is a parent of view B, and B is a parent of view C. The client can then
/// observe key lifecycle events in all of A, B, and C, such as newly connected
/// views, changes to view position and size, etc. In doing so, a client can
/// gate its actions on changes to the view tree, in a reliable and ergonomic
/// manner. For example, a client can wait for a descendant view C to become
/// connected before requesting a focus transfer to C.
///
/// Configuration: The context view is determined outside of this protocol.
///
/// Frequency: A snapshot is issued at most once per frame, but for relatively
/// static content, can be issued at a slower rate.
///
/// Issuance: If the context view is disconnected from a display, no
/// frames are issued on behalf of the context view, and a Watch() call will
/// sit quietly.
///
/// Lifecycle: The server endpoint is closed when the context view dies.
protocol Provider {
/// A method of obtaining view tree snapshots for a particular view.
///
/// This call is formulated as a "hanging get" pattern: the client asks for
/// a set of recent snapshots, and receives them via the callback. This
/// pull-based approach ensures that clients consume events at their own
/// pace; events don't clog up the channel in an unbounded manner.
///
/// Flow control. The caller is allowed at most one in-flight |Watch| call
/// at a time; it is a logical error to have concurrent calls to |Watch|.
/// Non-compliance results in channel closure.
///
/// Client pacing. The server will dispatch snapshots to the caller on a
/// lossless, best-effort basis, but the caller must allocate enough time to
/// keep up with new snapshots.
///
/// In case of BUFFER_OVERFLOW, the most recent updates are returned. If
/// Error.BUFFER_OVERFLOW is returned, the client may try again.
Watch() -> (struct {
epoch_end zx.time;
updates vector<ViewTreeSnapshot>:BUFFER_SIZE;
}) error Error;
};
/// A description of the context view and its descendant views, if any.
type ViewTreeSnapshot = table {
/// When the snapshot was taken.
1: time zx.time;
/// The context view (at element 0) and a complete list of its descendant views.
///
/// If MAX_VIEW_COUNT is exceeded, this field is left empty. Instead, a best
/// effort description of the view tree, starting from the context view, is
/// laid out in `incomplete`.
2: views vector<ViewDescriptor>:MAX_VIEW_COUNT;
/// The context view (at element 0) and an incomplete list of its descendant
/// views. Undiscerning clients may log an error, ignore this field, and
/// continue receiving snapshots until the view tree can be described
/// completely. Discerning clients may try to make sense of the world with
/// incomplete data.
3: incomplete vector<ViewDescriptor>:MAX_VIEW_COUNT;
};
/// A view's bounding box, described in the view's own coordinate system.
/// Concretely, |AlignedExtent| describes the minimal and maximal points of a
/// view's bounding box, which is rectangular and axis-aligned.
///
/// Note: For describing a view's bounding box in another view's coordinate
/// system, see |RotatableExtent|.
///
/// The origin is min.
/// The size is: (abs(max.x - min.x), abs(max.y - min.y)).
type AlignedExtent = struct {
/// The minimal position of the view's bounding box.
min math.PointF;
/// The maximal position of the view's bounding box.
max math.PointF;
};
/// A view bounding box, described in another view's coordinate system.
/// Concretely, |RotatableExtent| describes the origin, size, and rotation angle
/// about the origin, for a view's bounding box.
///
/// Note: For describing a view's bounding box in the view's own coordinate
/// system, see |AlignedExtent|.
///
/// We use "V" to refer to the view being described, and "W" to refer to the
/// view where V is being described.
///
/// Note that while |angle| can be arbitrary, typical usage is axis aligned.
/// To find the bounding box of V in W in clockwise order, starting with
/// |origin|, where |angle| is 0, 90, 180, or 270, and using o=origin, w=width,
/// h=height, a=angle:
/// a= 0: (o.x, o.y), (o.x + w, o.y), (o.x + w, o.y + h), (o.x, o.y + h)
/// a= 90: (o.x, o.y), (o.x, o.y - w), (o.x + h, o.y - w), (o.x + h, o.y)
/// a=180: (o.x, o.y), (o.x - w, o.y), (o.x - w, o.y - h), (o.x, o.y - h)
/// a=270: (o.x, o.y), (o.x, o.y + w), (o.x - h, o.y + w), (o.x - h, o.y)
/// A formula based on sin a and cos a is readily obtained, but floating point
/// computation may give only approximate results.
type RotatableExtent = struct {
/// The origin point of V's bounding box, in W's coordinate system.
origin math.PointF;
/// The width of V's bounding box (along the direction where V's x axis
/// increases), in W's coordinate system.
width float32;
/// The height of V's bounding box (along the direction where V's y axis
/// increases), in W's coordinate system.
height float32;
/// The clockwise rotation about the origin, in degrees.
angle float32;
};
/// The ratio from physical pixels (of a display) to logical pixels (of the
/// coordinate system of a view).
/// - The values are placed in (x, y) order.
alias PixelScale = array<float32, 2>;
/// Geometric data of a view.
///
/// Note that these are server-side values, and some graphics APIs do not have
/// consistency guarantees with UI clients around when these values "take
/// effect". I.e., the UI client may need to be directly queried to learn what
/// values they are currently using. However, UI clients are expected to use
/// these values "immediately", within a few frames.
type Layout = struct {
/// The minimal and maximal points of a view's bounding box, in the
/// coordinate system of that view.
extent AlignedExtent;
/// The conversion ratio from physical pixels (of a display) to logical pixels
/// (of the coordinate system of the view).
pixel_scale PixelScale;
/// The offset data for the view's bounding box, in the coordinate system of
/// that view.
inset math.InsetF;
};
/// Data for a particular view: identifier, position, and children.
type ViewDescriptor = table {
/// This view's fuchsia.ui.views.ViewRef koid.
1: view_ref_koid zx.koid;
/// This view's origin, logical size, pixel scale, and inset data, in the view's
/// own coordinate system.
///
/// Limitations. Data consistency between server and client depend on the
/// specific graphics API. Some APIs provide weak consistency, where the
/// server-side data (this data) and the client-side data (in the view's UI
/// client) are allowed to diverge for some time.
2: layout Layout;
/// This view's extent, in the context view's coordinate system.
/// It does NOT describe the child view's logical size.
///
/// This describes the "ground truth" position of this view within the context
/// view, regardless of view tree depth, or specific layout state of
/// intermediate views.
///
/// Limitations. It does NOT describe whether the view is "visible" (e.g.,
/// whether the view has opacity applied, or is not occluded by another view),
/// and it does NOT describe whether the view is "hittable" (e.g., whether the
/// view is positioned fully inside of every ancestor view's bounding box).
3: extent_in_context RotatableExtent;
/// The space occupied within the parent view's coordinate system.
/// It does NOT describe the child view's logical size.
4: extent_in_parent RotatableExtent;
/// The list of child views, in the order known to the graphics API.
///
/// Each integer in this vector refers to the child's position in the
/// |views| or |incomplete| vector that the parent is in.
///
/// The identity, position, and size of each child view. Position and size are
/// described by the extent of the child view within the parent view's
/// coordinate system.
///
/// The view tree topology is reliable. A child placed here is equivalent to
/// the parent view receiving a "child view connected" signal.
///
/// Limitations. A child's view boundary is described in the parent view's
/// coordinate system, which is subject to weak consistency (depending on the
/// graphics API). That is, when a parent view has a change in size or metrics,
/// the context view may observe a "jump" as the parent view incorporates those
/// data. In such cases, a new ViewTreeSnapshot is issued to describe the
/// change in position, relative to the context view.
5: children vector<uint32>:MAX_VIEW_COUNT;
};