// Copyright 2019 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.

syntax = "proto2";

package components.feed.core.proto.ui.piet;

option optimize_for = LITE_RUNTIME;

import "components/feed/core/proto/ui/piet/accessibility.proto";
import "components/feed/core/proto/ui/piet/actions.proto";
import "components/feed/core/proto/ui/piet/binding_refs.proto";
import "components/feed/core/proto/ui/piet/images.proto";
import "components/feed/core/proto/ui/piet/log_data.proto";
import "components/feed/core/proto/ui/piet/styles.proto";
import "components/feed/core/proto/ui/piet/text.proto";

option java_package = "org.chromium.components.feed.core.proto.ui.piet";
option java_outer_classname = "ElementsProto";
option cc_enable_arenas = true;

// Content is a placeholder which contains a layout Element, or something which
// resolves to a layout Element.
message Content {
  // The payload of this content.
  oneof content_type {
    // Element, specified inline.
    Element element = 1;

    // A binding to look up an element.
    // May have a performance penalty on some platforms.
    ElementBindingRef bound_element = 2;

    // An instance of a Template, represented by a TemplateInvocation.
    //
    // If the referenced template has several binding contexts, an Element
    // instance will be created for each one.
    //
    // This may happen in one of two cases:
    //
    // The Content appears inside an ElementList, or repeated Element
    // --------------------------------------------------------------
    //
    // For example:
    // In case there's an ElementList with the following Contents:
    //
    //  +----------------------------+
    //  |         Template_1         |
    //  +----------------------------+
    //  |   Template_2 with binding  |
    //  |     values [ a , b , c ]   |
    //  +----------------------------+
    //  |         Template_3         |
    //  +----------------------------+
    //
    // After the bindings are resolved, it will become:
    //  +----------------------------+
    //  |         Template_1         |
    //  +----------------------------+
    //  | Template_2 {with data "a"} |
    //  +----------------------------+
    //  | Template_2 {with data "b"} |
    //  +----------------------------+
    //  | Template_2 {with data "c"} |
    //  +----------------------------+
    //  |         Template_3         |
    //  +----------------------------+
    //
    // The Content appears in a GridCell
    // ---------------------------------
    // A GridCell is created for each invocation of the template. The created
    // GridCells will be added to the GridRow containing this GridCell. The
    // width of the created GridCells is duplicated from the GridCell containing
    // this Content.
    //
    // For example:
    // In case there's a GridRow with the following GridCells:
    //  +----------+------------------------+----------+
    //  |   Cell   | Cell with Content with |   Cell   |
    //  |          |  Template 2 with data  |          |
    //  |     1    |    bindings {a,b,c }   |    3     |
    //  +----------+------------------------+----------+
    //
    // After the bindings are resolved, it will become:
    //  +----------+------------+------------+------------+---------+
    //  |   Cell   | Template 2 | Template 2 | Template 2 |   Cell  |
    //  |     1    | {data "a"} | {data "b"} | {data "c"} |     3   |
    //  +----------+------------+------------+------------+---------+
    //
    //
    // IMPORTANT:
    // This feature may not be supported on all platforms; see [INTERNAL LINK].
    TemplateInvocation template_invocation = 3;

    // See comment on template field; this looks up the template based on the
    // ID in the bindings.
    TemplateBindingRef template_binding = 4;
  }
}

// Indicates element's visibility, and the option to bind visibility state that
// overrides the default value.
// This message should be used to bind external values for controlling display
// of parts of the UI.
message VisibilityState {
  // Binding of values.
  optional VisibilityBindingRef overriding_bound_visibility = 1;

  // The default visibility.
  optional Visibility default_visibility = 2 [default = VISIBLE];
}

// Element is the "superclass" of all container and content types, holding all
// shared parameters (styles, actions, etc).
//
// Element size expands to fill its container, unless the content is taller than
// the container, and the container height is not specified explicitly. In that
// case, the Element and the container both get the height of the content.
// Next Id: 27
message Element {
  // The specific content represented by this Element.
  oneof elements {
    /*** CONTENT ELEMENTS ***/

    // An image container
    ImageElement image_element = 3;

    // A simple text line
    TextElement text_element = 2;

    /*** END CONTENT ELEMENTS ***/

    /*** CONTAINER ELEMENTS ***/

    // A horizontal layout of multiple items.
    GridRow grid_row = 5;

    // A vertical layout of multiple items.
    ElementList element_list = 6;

    // Multiple items stacked on top of each other (overlay).
    ElementStack element_stack = 24;

    /*** END CONTAINER ELEMENTS ***/

    /*** NON-NATIVE ELEMENTS ***/

    // A custom view that Piet knows nothing about. Servers can use this message
    // to populate a custom proto extension, which Piet passes along to the Host
    // for rendering. The Host is expected to be able to interpret and render
    // this view and return to Piet, which then simply places it within the
    // current view hierarchy at the proper position.
    // If a renderer cannot be found for a particular CustomElement in a client
    // implementation, Piet raises a ERR_CUSTOM_ELEMENT_RENDERER_MISSING & warns
    // the user at runtime. A black/grey box is displayed in place of the
    // CustomElement, but the rest of the Frame is still rendered. It is
    // possible for CustomElements to invoke Piet for rendering sub-views, but
    // only top-level Piet Frame protos can be embedded this way. (In other
    // words, do not try to embed Piet Elements directly inside a
    // CustomElement).
    CustomElement custom_element = 1;

    // A view that is implemented by a secondary (non-Core) Piet Module. Not all
    // Piet Elements are useful to all clients/servers, so only the basic ones
    // are included in Piet Core. Common shareable elements can be implemented
    // in secondary Piet Modules, which are optional modules that can be
    // included in or excluded from Piet-based apps on an as-needed basis.
    // ModuleElements work similar to CustomElements, with the only difference
    // being that CustomElements are rendered by non-Piet code, while
    // ModuleElements are rendered by secondary Piet Modules.
    ModuleElement module_element = 21;

    /*** END NON-NATIVE ELEMENTS ***/
  }

  // Every UI element can have accessibility-related fields.
  optional Accessibility accessibility = 11;

  // Defines Actions that may be associated with the content of the Element.
  // The server is responsible for ensuring that the size of this content is
  // large enough to present a clear click target for the user.
  oneof actions_data {
    // Inlined actions.
    Actions actions = 14;

    // Actions coming from a template.
    ActionsBindingRef actions_binding = 15;
  }

  // A list of Contents to be overlaid on top of this Element.
  // This field is repeated to allow multiple overlay layers with different
  // gravity settings. The index of the item inside the repeated field
  // determines the order in which views will be laid out. Later items will
  // appear above the earlier ones.
  // Deprecated: To make an overlay on an Element, wrap the Element in an
  // ElementStack.
  repeated Content overlays = 22 [deprecated = true];

  // Horizontal gravity of this element's content within the parent container
  // Deprecated: use gravity_horizontal on Style instead
  optional GravityHorizontal gravity_horizontal = 12 [deprecated = true];

  // Vertical gravity of this element's content within the parent container
  // Deprecated: use gravity_vertical on Style instead
  optional GravityVertical gravity_vertical = 18 [deprecated = true];

  // Defines the overflow behavior for contents that are wider than this
  // Element.
  // Contents can be wider than the container Element in two scenarios:
  //  1. An element has defined width in its style, and the width is larger
  //     than the size of the Element.
  //  2. The element is a GridRow, where the width sum of cells with defined dp
  //     width is larger than the containing Element.
  //
  // In all other cases, contents cannot be wider than the container
  // Element.
  //
  // IMPORTANT: This might not be supported in all implementations of Piet, due
  //   to implementation/product decisions (for example, horizontal scrolling in
  //   a swipable card might be disabled).
  optional OverflowBehavior horizontal_overflow = 16
      [default = OVERFLOW_HIDDEN];

  // Styles to apply to this Element. If any style_ids cannot be found,
  // ERR_MISSING_STYLES is raised.
  optional StyleIdsStack style_references = 17;

  // Visibility state that can be controlled with binding.
  optional VisibilityState visibility_state = 23;
  oneof log_data_value {
    LogData log_data = 25;
    LogDataBindingRef log_data_ref = 26;
  }

  // Please use CL numbers you own for extension numbers.
  extensions 10000 to max;

  // Deprecated field IDs.
  reserved 4, 7, 8, 13, 19, 20, 9, 10;
}

/*
 *** CONTENT ELEMENTS ***
 */
// An Image which is displayed as a horizontal slice within a parent container.
message ImageElement {
  // Content for this ImageElement.
  oneof content {
    // The image to be displayed.
    Image image = 3;

    // The binding to the BindingValue for an Image. It is an error if the
    // BindingValue doesn't define an Image.
    ImageBindingRef image_binding = 2;
  }

  // Styles applied to this ImageElement. If any style_ids cannot be found,
  // ERR_MISSING_STYLES is raised.
  // Deprecated: use the StyleIdsStack on Element instead.
  optional StyleIdsStack style_references = 1 [deprecated = true];

  // Please use CL numbers you own for extension numbers.
  extensions 10000 to max;
}

// A simple text line (Android TextView, iOS UILabel, or HTML <div>).
message TextElement {
  // Content for this TextElement.
  oneof content {
    // ChunkedText to be displayed. Styles referenced inside the text chunks
    // should override the style references in this TextElement.
    ChunkedText chunked_text = 5;

    // The binding to the BindingValue for a ChunkedText. It is an error if the
    // BindingValue doesn't define a ChunkedText. Styles referenced inside the
    // ChunkedText should override the style references in this TextElement.
    ChunkedTextBindingRef chunked_text_binding = 4;

    // The text to display.
    ParameterizedText parameterized_text = 3;

    // The binding to the BindingValue for a ParameterizedText. It is an error
    // if the BindingValue doesn't define a ParameterizedText.
    ParameterizedTextBindingRef parameterized_text_binding = 2;
  }

  // Styles applied to this TextElement. If any style_ids cannot be found,
  // ERR_MISSING_STYLES is raised.
  // Deprecated: use the StyleIdsStack on Element instead.
  optional StyleIdsStack style_references = 1 [deprecated = true];

  // Please use CL numbers you own for extension numbers.
  extensions 10000 to max;
}
/*
 *** END CONTENT ELEMENTS ***
 */

/*
 *** CONTAINER ELEMENTS ***
 */
// A horizontally-oriented left-to-right list of Contents with specified widths.
// Without explicit dimensions or constraints by the parent, this container is
// as tall as its tallest child, and as wide as the sum of its cells.
message GridRow {
  // A list of cells defining the content of the grid.
  repeated GridCell cells = 2;

  // Styles applied to this GridRow.
  // Deprecated: use the StyleIdsStack on Element instead.
  optional StyleIdsStack style_references = 1 [deprecated = true];

  // Please use CL numbers you own for extension numbers.
  extensions 10000 to max;
}

// The Grid Cell represents the contents within a GridRow.
// The content within each cell is always the same width as the cell (minus
// margins) - width on the content's style is ignored. If the cell has extra
// vertical space (the GridRow is taller than the content), the content can
// float vertically with gravity.
// If the child's style does not specify a height, it defaults to matching the
// height of the GridRow.
// Next Id: 8
message GridCell {
  // The content of the GridCell.
  optional Content content = 7;

  // The width of this cell, either fixed width or relative width.
  // If width is not specified, behaves as if weight = 1 by default.
  oneof cell_width {
    // Specified inline.
    GridCellWidth width = 4;

    // Width specified in bindings.
    GridCellWidthBindingRef width_binding = 5;
  }

  // Please use CL numbers you own for extension numbers.
  extensions 10000 to max;

  // Deprecated field IDs.
  reserved 1, 2, 3, 6;
}

// The width of a GridCell.
message GridCellWidth {
  // An enum that indicates the width of the GridCell, in reference to its
  // content. The width of the GridCell will be the width of the contained
  // element.
  enum ContentWidth {
    // Do not use. If used, this will raise
    // ERR_CONTENT_WIDTH_GRID_CELL_WITH_INVALID_CONTENT at runtime.
    INVALID_CONTENT_WIDTH = 0;

    // This cell will expand just enough to fit its content.
    CONTENT_WIDTH = 1;
  }

  // The width specification. One of these fields must be populated, otherwise
  // ERR_GRID_CELL_WIDTH_WITHOUT_CONTENTS warning will be raised.
  oneof width_spec {
    // The width of the cell expressed as DP.
    int32 dp = 1;

    // The width of the cell expressed as a weight. This weight is relative to
    // the remaining width, after DP and Content were allocated.
    // For more information, see [INTERNAL LINK].
    int32 weight = 2;

    // The width of the content, limited to Content of TextElement or
    // ImageElement. In case a different content is given to the cell,
    // ERR_CONTENT_WIDTH_GRID_CELL_WITH_INVALID_CONTENT is raised.
    ContentWidth content_width = 3;
  }

  // Whether this cell will shrink if the GridRow is too small for its contents.
  // This cell will always be less than or equal to the defined width.
  // If there are multiple collapsible cells in a row, they will shrink in order
  // from last to first (ex. the last cell will be width 0 before the cell
  // before it begins to shrink).
  // This is ignored if weight is set.
  optional bool is_collapsible = 4;
}

// A vertically-oriented top-to-bottom list of Contents.
// Without explicit dimensions or constraints by the parent, this container is
// as wide as its largest child, and as tall as the sum of its children.
// Cell height is always the size of the child Element, and vertical gravity is
// ignored. Cell width defaults to the width of the ElementList.
message ElementList {
  // The list items to be laid out vertically.
  repeated Content contents = 6;

  // Styles applied to this ElementList.
  // Deprecated: use the StyleIdsStack on Element instead.
  optional StyleIdsStack style_references = 3 [deprecated = true];

  // Please use CL numbers you own for extension numbers.
  extensions 10000 to max;

  // Deprecated field IDs.
  reserved 1, 2, 4, 5;
}

// A stacked (overlaid) bottom-to-top list of Contents.
// Children can be smaller than the ElementStack and float around within it
// subject to their horizontal and vertical gravity.
// Without explicit dimensions or constraints by the parent, this container is
// as large as its largest child.
// By default, children are the size of their content.
message ElementStack {
  // The items to be stacked from bottom to top.
  repeated Content contents = 1;

  // Please use CL numbers you own for extension numbers.
  extensions 10000 to max;
}

/*
 *** END CONTAINER ELEMENTS ***
 */

/*
*** NON-NATIVE ELEMENTS
*/
// A custom view that Piet knows nothing about. Servers can use this message to
// populate a custom proto extension, which Piet passes along to the Host for
// rendering. The Host is expected to be able to interpret and render this view
// and return to Piet, which then simply places it within the current view
// hierarchy at the proper position. If no renderer for this CustomElement can
// be found at runtime, ERR_CUSTOM_ELEMENT_RENDERER_MISSING is raised.
message CustomElement {
  // Content for this CustomElement.
  oneof content {
    // The data to be displayed.
    CustomElementData custom_element_data = 3;

    // The binding to the BindingValue for a CustomElement.
    CustomBindingRef custom_binding = 2;
  }

  // Styles applied to this CustomElement. If any style_ids cannot be found,
  // ERR_MISSING_STYLES is raised.
  // Deprecated: use the StyleIdsStack on Element instead.
  optional StyleIdsStack style_references = 1 [deprecated = true];

  // Please use CL numbers you own for extension numbers.
  extensions 10000 to max;
}

// Data to be displayed in a CustomElement. Clients using Piet should add
// extensions to this proto to pass their custom data to CustomElements.
message CustomElementData {
  // Please use CL numbers you own for extension numbers.
  extensions 10000 to max;
}

// A view that is implemented by a secondary (non-Core) Piet Module. Not all
// Piet Elements are useful to all clients/servers, so only the basic ones are
// included in Piet Core. Common shareable elements can be implemented in
// secondary Piet Modules, which are optional modules that can be included in or
// excluded from Piet-based apps on an as-needed basis.
// ModuleElements work similar to CustomElements, with the only difference being
// that CustomElements are rendered by non-Piet code, while ModuleElements are
// rendered by secondary Piet Modules.
message ModuleElement {
  // Content for this ModuleElement.
  oneof content {
    // The data to be displayed.
    ModuleElementData module_element_data = 3;

    // The binding to the BindingValue for a ModuleElement.
    ModuleBindingRef module_binding = 2;
  }

  // Please use CL numbers you own for extension numbers.
  extensions 10000 to max;
}

// Data to be displayed in a ModuleElement. Piet Modules should add extensions
// to this proto to pass their custom data to ModuleElements.
message ModuleElementData {
  // Please use CL numbers you own for extension numbers.
  extensions 10000 to max;
}
/*
 *** END NON-NATIVE ELEMENTS ***
 */

/*
 *** TEMPLATES AND BINDINGS ***
 */

// A template can be used to instantiate a single instance, or a list of
// instances at once: each of these is termed a TemplateInvocation. One instance
// is created for each `binding_context` provided.
//
// The types of objects instantiated by the template are determined by the
// element that holds the invocation. For example, an invocation from an
// ElementList will create one or more cells in that list. Invocation from a
// GridCell will create one or more GridCells.
message TemplateInvocation {
  // The Template to be used.
  optional string template_id = 1;

  // To isolate Templates, we define the BindingContext used by the template
  // within the invocation. When a TemplateInvocation is processed, we will
  // create a template instance for each BindingContext defined (if none is
  // defined, none will be created).
  repeated BindingContext binding_contexts = 2;

  // Please use CL numbers you own for extension numbers.
  extensions 10000 to max;
}

// A single binding context, such as a whole Frame, or a single row in a grid.
// Binding IDs must be unique; if two or more BindingValues with the same
// `binding_id` are found within the same binding context,
// ERR_DUPLICATE_BINDING_VALUE is raised.
message BindingContext {
  // The set of all bindings for a Template.
  repeated BindingValue binding_values = 1;
}

// A BindingValue is a name/value pair which provides a value to be substituted
// wherever the specified `binding_id` is defined in the Template.
// Next Id: 18
message BindingValue {
  // The name of the binding within the Template where this BindingValue should
  // be substituted. Must be unique within a binding context.
  optional string binding_id = 1;

  // The possible values for the BindingValue.
  oneof values {
    // Actions that may be bound at runtime.
    Actions actions = 10;

    // Binding value for visibility, which changes the VisibilityState of an
    // Element. This value can override the default visibility value set on an
    // Element.
    Visibility visibility = 13 [default = VISIBLE];

    // Use an already existing bound value in a transcluded template.
    // This should be used to pass parameters between templates.
    //
    // For example:
    // Let's assume we have a template that shows a text with styling:
    //
    // template {
    //   id: "StyledText"
    //   ...
    //   element {
    //     text_element {
    //       parameterized_text_binding { binding_id: "StyledTextContent" }
    //     }
    //   }
    //   ...
    // }
    //
    // And we want to create a template that shows the styled text overlayed
    // over an image:
    //
    // template {
    //   id: "ImageWithText"
    //   ...
    //   element {
    //     image_element {
    //       image_binding {
    //         binding_id: "TopLevelImage"
    //       }
    //     }
    //     overlays {
    //       template_invocation {
    //         id: 'StyledText'
    //         binding_contexts {
    //           binding_values {
    //             binding_id: "StyledTextContent"
    //             binding_id_from_transcluding_template: "TopLevelText"
    //           }
    //         }
    //       }
    //     }
    //   }
    //   ...
    // }
    //
    // The invocation of the template will then be:
    //
    // frame {
    //   template_invocation {
    //     id: "ImageWithText"
    //     binding_contexts {
    //       binding_values {
    //         binding_id: "TopLevelText"
    //         ...
    //       }
    //       binding_values {
    //         binding_id: "TopLevelImage"
    //         ...
    //       }
    //     }
    //   }
    // }
    string binding_id_from_transcluding_template = 16;

    // Style that is bound to an element, and overrides the styles defined by
    // the element. The Style attributes that can be bound are only a subset
    // of all possible Styles.
    BoundStyle bound_style = 11;

    // Width of a cell.
    GridCellWidth cell_width = 9;

    // ChunkedText to be used in a TextElement.
    ChunkedText chunked_text = 4;

    // Data to be displayed in a CustomElement. Clients using Piet should add
    // extensions to this proto to pass their custom data.
    CustomElementData custom_element_data = 2;

    // An Element, to allow binding of generic chunks of layout.
    // May have a performance penalty on some platforms.
    Element element = 15;

    // Image to be used in an ImageElement.
    Image image = 5;

    // ParameterizedText to be used in a TextElement.
    ParameterizedText parameterized_text = 3;

    // Binding value for a TemplateInvocation.
    TemplateInvocation template_invocation = 8;

    // A Base64-encoded serialized ClickTrackingCGI proto that identifies the
    // logged Visual Element corresponding to a bound Piet Template.
    string ved = 7;

    LogData log_data = 17;
  }

  // Data to provide a host in order for host to fulfill a binding for Piet.
  // When Piet binds a value it will first look to see if there is a
  // HostBindingData set. If there is one, then Piet asks the host for a new
  // BindingValue to use. The host will be given this BindingValue from which it
  // can use HostBindingData to determine how to create a new BindingValue. This
  // allows the host to selectively alter the server specified BindingValue. If
  // the BindingValue returned by the host has HostBindingData set it will be
  // ignored. If there is no binding provided in the oneof then an error will be
  // raised.  See [INTERNAL LINK] for a list of possible errors that could be
  // raised.
  //
  // Piet will use the binding reference and ask the host for a specific
  // binding based on that reference type. As an example, Piet will request the
  // host for an Image when ImageBindingRef is specified.
  //
  // An example usage of a host binding would be to check if something has
  // been stored on the device and signaling with icons whether content is
  // there or not.  The server can specify where this element will appear and
  // the host can determine what to show or even if the element should be
  // shown.
  optional HostBindingData host_binding_data = 14;

  // Please use CL numbers you own for extension numbers.
  extensions 10000 to max;

  // Deprecated field IDs.
  reserved 6;
}

// Data which is accompanied with BindingValue in order for a host to determine
// the information it needs to provide the correct BindingValue to fulfill a
// binding reference.  Client using Piet should add extensions to this proto to
// pass their host specific data needed to fulfill the binding reference.
message HostBindingData {
  // Please use CL numbers you own for extension numbers.
  extensions 10000 to max;
}

/*
 *** END TEMPLATES AND BINDINGS ***
 */

/*
 *** ENUMS ***
 */
// Controls the visibility of a UI element.
enum Visibility {
  VISIBILITY_UNSPECIFIED = 0;

  // By default, every element is visible. If set to VISIBLE, at least one of
  // the elements in the `values` oneof MUST be present, otherwise an error is
  // raised.
  VISIBLE = 1;

  // The UI element corresponding to this binding is included in
  // layout computation, but its visible UI is hidden.
  INVISIBLE = 2;

  // The UI element corresponding to this binding is completely
  // removed from the view hierarchy. It is not used to compute layout. This
  // is the equivalent of Android’s visibility:GONE.
  GONE = 3;
}

// Defines the behavior for elements that don't fit in the view
enum OverflowBehavior {
  // Unspecified value, will default to OVERFLOW_HIDDEN.
  OVERFLOW_UNSPECIFIED = 0;

  // All elements outside the boundaries of the view are hidden.
  OVERFLOW_HIDDEN = 1;

  // A scroll behavior is added to show elements that are outside of the view.
  OVERFLOW_SCROLL = 2;
}
/*
 *** END ENUMS ***
 */
