| // 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; |
| |
| /// The maximum number of `ViewTreeSnapshot`s a client can expect in a `Watch` call's |
| /// response. The number of `ViewTreeSnapshot`s can be less than `BUFFER_SIZE` when |
| /// the size of a `Watch` call's response exceeds the limit of a FIDL channel. |
| /// |
| /// There is a limit on the number of `ViewTreeSnapshot`s that can be included in a |
| /// `Watch` call's response due to the size restrictions of a FIDL channel. This limit |
| /// was calculated by finding out the maximum number of `ViewTreeSnapshot`s which can be |
| /// included in a `Watch` call's response when `MAX_VIEW_COUNT` is 1. |
| /// |
| /// Note: This value would have to adjusted when modifying `ViewTreeSnapshot` or |
| /// `ViewDescriptor`. |
| const BUFFER_SIZE uint32 = 200; |
| |
| /// The maximum number of `ViewDescriptor`s a client can expect in a |
| /// `ViewTreeSnapshot`. |
| /// |
| /// There is a limit on the number of `ViewDescriptor`s that can be included in a |
| /// `ViewTreeSnapshot` due to the size restrictions of a FIDL channel. This limit was |
| /// calculated by finding out the maximum number of `ViewDescriptor`s which can be |
| /// included in a `ViewTreeSnapshot` when the `BUFFER_SIZE` is 1. |
| /// |
| /// Note: This value would have to adjusted when modifying `ViewDescriptor`. |
| const MAX_VIEW_COUNT uint32 = 300; |
| |
| /// 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 client can receive one or more snapshots per frame. Clients |
| /// should not "count snapshots", as the per-frame snapshot count can be |
| /// non-deterministic. Instead, clients should look for specific conditions on |
| /// the snapshot state. |
| /// |
| /// 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. |
| Watch() -> (struct { |
| response ProviderWatchResponse; |
| }); |
| }; |
| |
| /// Response for fuchsia.ui.observation.geometry.Provider.Watch. |
| type ProviderWatchResponse = table { |
| /// When the response is sent. |
| 1: epoch_end zx.time; |
| |
| /// A list of most recent updates for a particular view. |
| 2: updates vector<ViewTreeSnapshot>:BUFFER_SIZE; |
| |
| /// Only set if an error condition is detected. If unset, the client may assume |
| /// that updates has complete information over its epoch. |
| 3: 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 not set, and an error is reported in |
| /// `Error`. |
| 2: views vector<ViewDescriptor>:MAX_VIEW_COUNT; |
| }; |
| |
| // List of possible errors faced by a client during a `Watch` call. |
| type Error = table { |
| /// Set to true when appending a `ViewTreeSnapshot` in `ProviderWatchResponse.updates` |
| /// would exceed the limit of the FIDL channel. That snapshot is dropped, along with |
| /// older snapshots. |
| 1: channel_overflow bool; |
| |
| /// Set to true when appending a `ViewTreeSnapshot` in `ProviderWatchResponse.updates` |
| /// would exceed `BUFFER_SIZE`. That snapshot is dropped, along with older snapshots. |
| 2: buffer_overflow bool; |
| |
| /// Set to true when the size of `views` in a `ViewTreeSnapshot` exceeds |
| /// `MAX_VIEW_COUNT`. We represent this situation in the `ViewTreeSnapshot` with an |
| /// unset `views` field. |
| 3: views_overflow bool; |
| }; |
| |
| /// 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; |
| }; |