Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(764)

Unified Diff: sky/sdk/lib/rendering/README.md

Issue 1211573003: Fill out some more documentation about building RenderBox subclasses. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « sky/sdk/lib/base/node.dart ('k') | sky/sdk/lib/rendering/block.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sky/sdk/lib/rendering/README.md
diff --git a/sky/sdk/lib/rendering/README.md b/sky/sdk/lib/rendering/README.md
index 77ea6d3de4a2c564fc854329e52c37c390aab9a1..3570d0ac9b6246450191cf44d935d2015e671682 100644
--- a/sky/sdk/lib/rendering/README.md
+++ b/sky/sdk/lib/rendering/README.md
@@ -77,8 +77,31 @@ models and are free to invent novel child models for their specific use cases.
### Parent Data
+TODO(ianh): Describe the parent data concept.
+
+The `setParentData()` method is automatically called for each child
+when the child's parent is changed. However, if you need to
+preinitialise the `parentData` member to set its values before you add
+a node to its parent, you can preemptively call that future parent's
+`setParentData()` method with the future child as the argument.
+
### Box Model
+#### Dimensions
+
+All dimensions are expressed as logical pixel units. Font sizes are
+also in logical pixel units. Logical pixel units are approximately
+96dpi, but the precise value varies based on the hardware, in such a
+way as to optimise for performance and rendering quality while keeping
+interfaces roughly the same size across devices regardless of the
+hardware pixel density.
+
+Logical pixel units are automatically converted to device (hardware)
+pixels when painting by applying an appropriate scale factor.
+
+TODO(ianh): Define how you actually get the device pixel ratio if you
+need it, and document best practices around that.
+
#### EdgeDims
#### BoxConstraints
@@ -113,14 +136,208 @@ Writing new subclasses
### The RenderObject contract
+If you want to define a `RenderObject` that uses a new coordinate
+system, then you have to inherit straight from `RenderObject`.
abarth-chromium 2015/06/25 19:41:06 s/have to inherit straight/should inherit directly
+Examples of doing this can be found in [`RenderBox`](box.dart), which
+deals in rectangles in cartesian space, and in the [sector_layout.dart
+example](../../../examples/rendering/sector_layout.dart), which
abarth-chromium 2015/06/25 19:41:06 We should move the examples into the sdk directory
+implements a toy model based on polar coordinates. The `RenderView`
+class, which is used internally to adapt from the host system to this
+rendering framework, is another example.
+
+A subclass of `RenderObject` must fulfill the following contract:
+
+* It must fulfill the [AbstractNode contract](../base/README.md) when
+ dealing with children. Using `RenderObjectWithChildMixin` or
+ `ContainerRenderObjectMixin` can make this easier.
+
+* Information about the child managed by the parent, e.g. typically
+ position information and configuration for the parent's layout,
+ should be stored on the `parentData` member; to this effect, a
+ ParentData subclass should be defined and the `setParentData()`
+ method should be overriden to initialise the child's parent data
+ appropriately.
+
+* Layout constraints must be expressed in a Constraints subclass. This
+ subclass must implement operator== (and hashCode).
abarth-chromium 2015/06/25 19:41:06 `operator==` and `hashCode` because these are code
+
+* Whenever the layout needs updating, the `markNeedsLayout()` method
+ should be called.
+
+* Whenever the rendering needs updating without changing the layout,
+ the `markNeedsPaint()` method should be called. (Calling
+ `markNeedsLayout()` implies a call to `markNeedsPaint()`, so you
+ don't need to call both.)
+
+* The subclass must override `performLayout()` to perform layout based
+ on the constraints given in the `constraints` member. Each object is
+ responsible for sizing itself; positioning must be done by the
+ object calling `performLayout()`. Whether positioning is done before
+ or after the child's layout is a decision to be made by the class.
+ TODO(ianh): Document sizedByParent, performResize(), rotate
+
+* TODO(ianh): Document painting, hit testing, debug*
+
#### The ParentData contract
#### Using RenderObjectWithChildMixin
-#### Using ContainerParentDataMixin and ContainerRenderObjectMixin
+#### Using ContainerRenderObjectMixin (and ContainerParentDataMixin)
+
+This mixin can be used for classes that have a child list, to manage
+the list. It implements the list using linked list pointers in the
+`parentData` structure.
+
+TODO(ianh): Document this mixin.
+
+Subclasses must follow the following contract, in addition to the
+contracts of any other classes they subclass:
+
+* If the constructor takes a list of children, it must call addAll()
+ with that list.
+
+TODO(ianh): Document how to walk the children.
### The RenderBox contract
+A `RenderBox` subclass is required to implement the following contract:
+
+* It must fulfill the [AbstractNode contract](../base/README.md) when
+ dealing with children. Note that using `RenderObjectWithChildMixin`
+ or `ContainerRenderObjectMixin` takes care of this for you, assuming
+ you fulfill their contract instead.
+
+* If it has any data to store on its children, it must define a
+ BoxParentData subclass and override setParentData() to initialise
+ the child's parent data appropriately, as in the following example.
+ (If the subclass has an opinion about what type its children must
+ be, e.g. the way that `RenderBlock` wants its children to be
+ `RenderBox` nodes, then change the `setParentData()` signature
+ accordingly, to catch misuse of the method.)
+
+```dart
+ class FooParentData extends BoxParentData { ... }
+
+ // In RenderFoo
+ void setParentData(RenderObject child) {
+ if (child.parentData is! FooParentData)
+ child.parentData = new FooParentData();
+ }
+```
+
+* The class must encapsulate a layout algorithm that has the following
+ features:
+
+** It uses as input a set of constraints, described by a
+ BoxConstraints object, and a set of zero or more children, as
+ determined by the class itself, and has as output a Size (which is
+ set on the object's own `size` field), and positions for each child
+ (which are set on the children's `parentData.position` field).
+
+** The algorithm can decide the Size in one of two ways: either
+ exclusively based on the given constraints (i.e. it is effectively
+ sized entirely by its parent), or based on those constraints and
+ the dimensions of the children.
+
+ In the former case, the class must have a sizedByParent getter that
+ returns true, and it must have a `performResize()` method that uses
+ the object's `constraints` member to size itself by setting the
+ `size` member. The size must be consistent, a given set of
+ constraints must always result in the same size.
+
+ In the latter case, it will inherit the default `sizedByParent`
+ getter that returns false, and it will size itself in the
+ `performLayout()` function described below.
+
+ The `sizedByParent` distinction is purely a performance
+ optimisation. It allows nodes that only set their size based on the
+ incoming constraints to skip that logic when they need to be
+ re-laid-out.
abarth-chromium 2015/06/25 19:41:06 I wonder if we should remove this concept until we
+
+* The following methods must report numbers consistent with the output
+ of the layout algorithm used:
+
+** `double getMinIntrinsicWidth(BoxConstraints constraints)` must
+ return the width that fits within the given constraints below which
+ making the width constraint smaller would not increase the
+ resulting height, or, to put it another way, the narrowest width at
+ which the box can be rendered without failing to lay the children
+ out within itself.
+
+ For example, the minimum intrinsic width of a piece of text like "a
+ b cd e", where the text is allowed to wrap at spaces, would be the
+ width of "cd".
+
+** `double getMaxIntrinsicWidth(BoxConstraints constraints)` must
+ return the width that fits within the given constraints above which
+ making the width constraint larger would not decrease the resulting
+ height.
+
+ For example, the maximum intrinsic width of a piece of text like "a
+ b cd e", where the text is allowed to wrap at spaces, would be the
+ width of the whole "a b cd e" string, with no wrapping.
+
+** `double getMinIntrinsicHeight(BoxConstraints constraints)` must
+ return the height that fits within the given constraints below
+ which making the height constraint smaller would not increase the
+ resulting width, or, to put it another way, the shortest height at
+ which the box can be rendered without failing to lay the children
+ out within itself.
+
+ The minimum intrinsic height of a width-in-height-out algorithm,
+ like English text layout, would be the height of the text at the
+ width that would be used given the constraints. So for instance,
+ given the text "hello world", if the constraints were such that it
+ had to wrap at the space, then the minimum intrinsic height would
+ be the height of two lines (and the appropriate line spacing). If
+ the constraints were such that it all fit on one line, then it
+ would be the height of one line.
+
+** `double getMaxIntrinsicHeight(BoxConstraints constraints)` must
+ return the height that fits within the given constraints above
+ which making the height constraint larger would not decrease the
+ resulting width. If the height depends exclusively on the width,
+ and the width does not depend on the height, then
+ `getMinIntrinsicHeight()` and `getMaxIntrinsicHeight()` will return the
+ same number given the same constraints.
+
+ In the case of English text, the maximum intrinsic height is the
+ same as the minimum instrinsic height.
+
+* The box must have a `performLayout()` method that encapsulates the
+ layout algorithm that this class represents. It is responsible for
+ telling the children to lay out, positioning the children, and, if
+ sizedByParent is false, sizing the object.
+
+ Specifically, the method must walk over the object's children, if
+ any, and for each one call `child.layout()` with a BoxConstraints
+ object as the first argument, and a second argument named
+ `parentUsesSize` which is set to true if the child's resulting size
+ will in any way influence the layout, and omitted (or set to false)
+ if the child's resulting size is ignored. The children's positions
+ (`child.parentData.position`) must then be set.
+
+ (Calling `layout()` can result in the child's own `performLayout()`
+ method being called recursively, if the child also needs to be laid
+ out. If the child's constraints haven't changed and the child is not
+ marked as needing layout, however, this will be skipped.)
+
+ The parent must not set a child's `size` directly. If the parent
+ wants to influence the child's size, it must do so via the
+ constraints that it passes to the child's `layout()` method.
+
+ If an object's `sizedByParent` is false, then its `performLayout()`
+ must also size the object (by setting `size`), otherwise, the size
+ must be left untouched.
+
+* The `size` member must never be set to an infinite value.
+
+* The box must also implement `hitTestChildren()`.
+ TODO(ianh): Define this better
+
+* The box must also implement `paint()`.
+ TODO(ianh): Define this better
+
#### Using RenderProxyBox
### The Hit Testing contract
« no previous file with comments | « sky/sdk/lib/base/node.dart ('k') | sky/sdk/lib/rendering/block.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698