blob: c2326ce0b125fc5a462984cf725b55fff9b75637 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Primitives express the geometry of the scene, such as quads and references
// to embedded scenes. Primitives are arranged hierarchically as nodes,
// each with an associated transformation matrix.
[DartPackage="mojo_services"]
module mojo.gfx.composition;
import "mojo/services/geometry/interfaces/geometry.mojom";
import "mojo/services/gfx/composition/interfaces/hit_tests.mojom";
// Nodes express the geometry and content of the scene, such as images and
// references to embedded scenes. Nodes are arranged to form a directed
// acyclic graph of drawing commands.
//
// RENDERING
//
// The node graph is renderer in pre-order traversal. Starting from the
// root, the compositor applies the transformation, clip, applies the
// node's operation (if any), then recursively processes the node's children
// according to the node's combinator rule.
//
// BLOCKED NODES
//
// Due to the asynchronous nature of the system, it may happen that some
// nodes cannot be processed immediately at drawing time because they require
// access to certain resources which are not available, such as a specific
// version of a scene which has yet to be produced by some other application.
//
// When a node cannot be drawn due to an unsatisfied dependency, it is
// said to be "blocked". Blocked nodes prevent rendering of the entire
// subgraph below them.
//
// NODE COMBINATORS
//
// Node combinator rules describe what should happen when a node which is
// otherwise unblocked has one or more blocked children.
//
// With the |MERGE| combinator, the children of a node are all drawn in
// sequence if none of them are blocked, otherwise the node itself is
// blocked. This is the default.
//
// With the |PRUNE| combinator, the children of a node are all drawn in
// sequence while skipping over any of them which are blocked. Blocked
// children will not appear in the output.
//
// With the |FALLBACK| combinator, the first unblocked child of a node is
// drawn and the remaining nodes are ignored. If the node has children
// and all of them are blocked then the node itself is blocked.
//
// Combinators make it possible to express complex rules such as substituting
// missing content for an earlier version of that content or for a placeholder
// if not available.
//
// HIT TESTING
//
// Hit testing is the process of determining which nodes within a scene graph
// should be responsible for handling events which occur within their visual
// space on the screen.
//
// For example, when the user touches objects on a touch screen, the input
// system asks the compositor to performs a hit test at the contact point to
// find the nodes which represent the objects the user wants to interact with.
// The result of the hit test is a list of nodes, in dispatch order, which
// have asked to participate in handling events related to the contact point.
//
// Nodes may be opaque, translucent, or invisible to the hit testing
// process depending on whether they prevent or allow targets visually
// behind them from being hit and whether they can actually be hit,
// as specified by |HitTestBehavior.visibility|.
//
// Nodes are added to the hit test result whenever one of their opaque children
// is hit. This is useful for scrolling containers which may need to intercept
// certain gestures within the space of their children and therefore need to
// be added to the hit test result themselves.
//
// Nodes can also request to prune hit testing for their children, which
// prevents their children from being hit.
//
// Hit testing proceeds recursively in post-order traversal (the reverse of
// the drawing order). Intuitively, this means that the most specific
// (deepest) nodes of the tree are tested before their ancestors.
//
// Starting from the root, the compositor transforms the point of interest
// into the node's coordinate system, rejects the node if the point is
// outside of the node's clip region, otherwise recursively tests the
// node's children (those which were selected by the combinator rule)
// until the first opaque target hit is found, then evaluates the node's
// |HitTestBehavior| to determine whether the node was hit. Nodes are
// accumulated into a hit test result in the order in which they were
// determined to have been hit.
//
// See |HitTestBehavior| for more details.
//
// INSTANCING
//
// The compositor allows nodes to be referenced and reused multiple times
// within a scene (this is known as instancing). Instancing makes it easier
// to take advantage of combinators for interleaving placeholder content
// when certain nodes are blocked from rendering (see above). It also allows
// common elements to be reused if desired.
//
// Likewise, the compositor allows scenes to be multiply referenced so that
// the same content can be presented simultaneously in several places.
//
// CYCLES
//
// The compositor forbids cycles among nodes within scenes and will
// reject scene updates which introduce node cycles by closing the client's
// connection.
//
// Likewise, the compositor forbids cycles across scenes and will respond
// to them by considering any scene within a cycle to be blocked from
// rendering.
//
// For example, if there are scenes A, B, and C linked such that rendering
// would traverse a path A -> B -> C -> B, the compositor will consider both
// scenes B and C to be blocked and will apply A's combinator rules as required
// to resolve the problem at the point where it would have entered the cycle.
// This may cause A itself to be blocked if there are no applicable |PRUNE|
// or |FALLBACK| predicated alternatives.
//
// This policy protects clients from cross-scene cycles which may have been
// introduced downstream in the graph without their knowledge or which may
// occur transiently, so long as they are not within the cycle themselves.
// It also ensures that cycles are resolved deterministically regardless of
// where they are encountered during traversal; all scenes within the cycle
// are suppressed.
//
// TIPS
//
// 1. Reuse nodes when possible to reduce the size of the graph. Consider
// using LayerNodeOps to flatten common elements to a texture which can
// be redrawn efficiently in many places.
//
// 2. Insert |PRUNE| or |FALLBACK| nodes in places where blocking is likely to
// occur, such as when embedding scenes produced by other applications.
// Provide alternate content where possible to avoid stalling the
// rendering pipeline at these points.
//
struct Node {
// The combinator specifies how child nodes are processed.
enum Combinator {
// All children are drawn in sequence, blocking if any are blocked.
MERGE,
// All children are drawn in sequence, skipping any that are blocked.
PRUNE,
// The first unblocked node is drawn, blocking if there are children
// and all of them are blocked.
FALLBACK,
};
// The forward transformation from the node's content space to its
// containing node's content space. If null, an identity transformation
// is assumed.
//
// For example, if you want to translate the content of the node so that
// it is drawn at X = 100 relative to its containing node's origin, simply
// set a transformation matrix with the X translation component equal to 100.
// Take care not to specify the inverse transform by mistake.
mojo.Transform? content_transform;
// The clip rectangle to apply to this node's content and to its children
// in content space in addition to any clipping performed by the container.
// If null, the node does not apply any clipping of its own.
mojo.RectF? content_clip;
// The Combinator to apply when processing the children of this node.
Combinator combinator = Combinator.MERGE;
// The hit testing behavior of the node.
// If null, the node is considered invisible for hit testing.
HitTestBehavior? hit_test_behavior;
// The ids of the children of this node.
// It is an error to specify a node id that does not refer to a valid
// node or which creates a cycle in the graph; the compositor will close
// the connection when the scene is published.
array<uint32>? child_node_ids;
// The drawing operation to apply when processing this node.
// If null, no drawing operation occurs at this node.
NodeOp? op;
};
// A drawing operation to apply when processing the node.
union NodeOp {
RectNodeOp rect;
ImageNodeOp image;
SceneNodeOp scene;
LayerNodeOp layer;
// TODO(jeffbrown): Color filters.
};
// Fills a rectangle with a solid color.
struct RectNodeOp {
// The rectangle to fill in content space.
mojo.RectF content_rect;
// The rectangle's color.
Color color;
};
// Draws an image at the specified location.
//
// The node containing this operation will be blocked if the image resource
// is not ready for use at draw time.
struct ImageNodeOp {
// The rectangle in which to draw the image in content space.
mojo.RectF content_rect;
// The portion of the image to draw.
// If null, draws the entire image.
mojo.RectF? image_rect;
// The resource id of a valid |MailboxTextureResource| to draw.
// It is an error to specify a resource id that does not refer to an image
// resource; the compositor will close the connection when the scene
// is published.
uint32 image_resource_id;
// The blending parameters. If null, uses the default values specified
// in the |Blend| structure declaration.
Blend? blend;
};
// Draws a scene.
//
// A scene operation embeds another scene at this point in the scene graph.
// It has essentially the same effect as drawing the root node of the
// referenced scene and drawing it as if it were a child of this node.
//
// The node containing this operation will be blocked if the specified
// version of the scene is not ready for use at draw time or if it too
// is blocked.
//
// It is often useful to wrap this node with a |LayerNodeOp| when blending
// the scene with other content.
struct SceneNodeOp {
// The resource id of a valid |SceneResource| to link into the scene.
// It is an error to specify a resource id that does not refer to a scene
// resource; the compositor will close the connection when the scene
// is published.
// If a cycle is introduced then the scene will be substituted with
// placeholder content by the compositor.
uint32 scene_resource_id;
// The version of the scene that we would like to reference.
// Use |kSceneVersionNone| to request the most recently published
// version of the scene if synchronization is unimportant.
uint32 scene_version = 0; // kSceneVersionNone
};
// Draws a layer.
//
// Conceptually, this operation has the effect of drawing the children of
// the node to a temporary buffer which is then composited in place like an
// image. This is useful for ensuring correct blending of layered content.
struct LayerNodeOp {
// The region of the node's content space to render to a layer.
// Drawing within this region will be included in the layer.
mojo.RectF layer_rect;
// The blending parameters. If null, uses the default values specified
// in the |Blend| structure declaration.
Blend? blend;
};
// Specifies a color to draw.
// TODO(jeffbrown): This is silly but unambiguous for prototyping.
// Make it less silly.
struct Color {
uint8 red;
uint8 green;
uint8 blue;
uint8 alpha;
};
// Specifies how blending should take place.
struct Blend {
// The opacity for composition in a range from 0 (fully transparent)
// to 255 (fully opaque).
uint8 alpha = 255;
// TODO(jeffbrown): Blend modes and texture filtering.
};