Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 Sky Rendering | 1 Sky Rendering |
| 2 ============= | 2 ============= |
| 3 | 3 |
| 4 The Sky render tree is a low-level layout and painting system based on a | 4 The Sky render tree is a low-level layout and painting system based on a |
| 5 retained tree of objects that inherit from [`RenderObject`](object.dart). Most | 5 retained tree of objects that inherit from [`RenderObject`](object.dart). Most |
| 6 developers using Sky will not need to interact directly with the rendering tree. | 6 developers using Sky will not need to interact directly with the rendering tree. |
| 7 Instead, most developers should use [Sky widgets](../widgets/README.md), which | 7 Instead, most developers should use [Sky widgets](../widgets/README.md), which |
| 8 are built using the render tree. | 8 are built using the render tree. |
| 9 | 9 |
| 10 Overview | 10 Overview |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 70 have a unique child. | 70 have a unique child. |
| 71 | 71 |
| 72 * `ContainerRenderObjectMixin` is useful for subclasses of `RenderObject` that | 72 * `ContainerRenderObjectMixin` is useful for subclasses of `RenderObject` that |
| 73 have a child list. | 73 have a child list. |
| 74 | 74 |
| 75 Subclasses of `RenderObject` are not required to use either of these child | 75 Subclasses of `RenderObject` are not required to use either of these child |
| 76 models and are free to invent novel child models for their specific use cases. | 76 models and are free to invent novel child models for their specific use cases. |
| 77 | 77 |
| 78 ### Parent Data | 78 ### Parent Data |
| 79 | 79 |
| 80 TODO(ianh): Describe the parent data concept. | |
| 81 | |
| 82 The `setParentData()` method is automatically called for each child | |
| 83 when the child's parent is changed. However, if you need to | |
| 84 preinitialise the `parentData` member to set its values before you add | |
| 85 a node to its parent, you can preemptively call that future parent's | |
| 86 `setParentData()` method with the future child as the argument. | |
| 87 | |
| 80 ### Box Model | 88 ### Box Model |
| 81 | 89 |
| 90 #### Dimensions | |
| 91 | |
| 92 All dimensions are expressed as logical pixel units. Font sizes are | |
| 93 also in logical pixel units. Logical pixel units are approximately | |
| 94 96dpi, but the precise value varies based on the hardware, in such a | |
| 95 way as to optimise for performance and rendering quality while keeping | |
| 96 interfaces roughly the same size across devices regardless of the | |
| 97 hardware pixel density. | |
| 98 | |
| 99 Logical pixel units are automatically converted to device (hardware) | |
| 100 pixels when painting by applying an appropriate scale factor. | |
| 101 | |
| 102 TODO(ianh): Define how you actually get the device pixel ratio if you | |
| 103 need it, and document best practices around that. | |
| 104 | |
| 82 #### EdgeDims | 105 #### EdgeDims |
| 83 | 106 |
| 84 #### BoxConstraints | 107 #### BoxConstraints |
| 85 | 108 |
| 86 ### Bespoke Models | 109 ### Bespoke Models |
| 87 | 110 |
| 88 | 111 |
| 89 Using the provided subclasses | 112 Using the provided subclasses |
| 90 ----------------------------- | 113 ----------------------------- |
| 91 | 114 |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 106 ### RenderBlock (render_block.dart) | 129 ### RenderBlock (render_block.dart) |
| 107 ### RenderFlex (render_flex.dart) | 130 ### RenderFlex (render_flex.dart) |
| 108 ### RenderParagraph (render_paragraph.dart) | 131 ### RenderParagraph (render_paragraph.dart) |
| 109 ### RenderStack (render_stack.dart) | 132 ### RenderStack (render_stack.dart) |
| 110 | 133 |
| 111 Writing new subclasses | 134 Writing new subclasses |
| 112 ---------------------- | 135 ---------------------- |
| 113 | 136 |
| 114 ### The RenderObject contract | 137 ### The RenderObject contract |
| 115 | 138 |
| 139 If you want to define a `RenderObject` that uses a new coordinate | |
| 140 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
| |
| 141 Examples of doing this can be found in [`RenderBox`](box.dart), which | |
| 142 deals in rectangles in cartesian space, and in the [sector_layout.dart | |
| 143 example](../../../examples/rendering/sector_layout.dart), which | |
|
abarth-chromium
2015/06/25 19:41:06
We should move the examples into the sdk directory
| |
| 144 implements a toy model based on polar coordinates. The `RenderView` | |
| 145 class, which is used internally to adapt from the host system to this | |
| 146 rendering framework, is another example. | |
| 147 | |
| 148 A subclass of `RenderObject` must fulfill the following contract: | |
| 149 | |
| 150 * It must fulfill the [AbstractNode contract](../base/README.md) when | |
| 151 dealing with children. Using `RenderObjectWithChildMixin` or | |
| 152 `ContainerRenderObjectMixin` can make this easier. | |
| 153 | |
| 154 * Information about the child managed by the parent, e.g. typically | |
| 155 position information and configuration for the parent's layout, | |
| 156 should be stored on the `parentData` member; to this effect, a | |
| 157 ParentData subclass should be defined and the `setParentData()` | |
| 158 method should be overriden to initialise the child's parent data | |
| 159 appropriately. | |
| 160 | |
| 161 * Layout constraints must be expressed in a Constraints subclass. This | |
| 162 subclass must implement operator== (and hashCode). | |
|
abarth-chromium
2015/06/25 19:41:06
`operator==` and `hashCode` because these are code
| |
| 163 | |
| 164 * Whenever the layout needs updating, the `markNeedsLayout()` method | |
| 165 should be called. | |
| 166 | |
| 167 * Whenever the rendering needs updating without changing the layout, | |
| 168 the `markNeedsPaint()` method should be called. (Calling | |
| 169 `markNeedsLayout()` implies a call to `markNeedsPaint()`, so you | |
| 170 don't need to call both.) | |
| 171 | |
| 172 * The subclass must override `performLayout()` to perform layout based | |
| 173 on the constraints given in the `constraints` member. Each object is | |
| 174 responsible for sizing itself; positioning must be done by the | |
| 175 object calling `performLayout()`. Whether positioning is done before | |
| 176 or after the child's layout is a decision to be made by the class. | |
| 177 TODO(ianh): Document sizedByParent, performResize(), rotate | |
| 178 | |
| 179 * TODO(ianh): Document painting, hit testing, debug* | |
| 180 | |
| 116 #### The ParentData contract | 181 #### The ParentData contract |
| 117 | 182 |
| 118 #### Using RenderObjectWithChildMixin | 183 #### Using RenderObjectWithChildMixin |
| 119 | 184 |
| 120 #### Using ContainerParentDataMixin and ContainerRenderObjectMixin | 185 #### Using ContainerRenderObjectMixin (and ContainerParentDataMixin) |
| 186 | |
| 187 This mixin can be used for classes that have a child list, to manage | |
| 188 the list. It implements the list using linked list pointers in the | |
| 189 `parentData` structure. | |
| 190 | |
| 191 TODO(ianh): Document this mixin. | |
| 192 | |
| 193 Subclasses must follow the following contract, in addition to the | |
| 194 contracts of any other classes they subclass: | |
| 195 | |
| 196 * If the constructor takes a list of children, it must call addAll() | |
| 197 with that list. | |
| 198 | |
| 199 TODO(ianh): Document how to walk the children. | |
| 121 | 200 |
| 122 ### The RenderBox contract | 201 ### The RenderBox contract |
| 123 | 202 |
| 203 A `RenderBox` subclass is required to implement the following contract: | |
| 204 | |
| 205 * It must fulfill the [AbstractNode contract](../base/README.md) when | |
| 206 dealing with children. Note that using `RenderObjectWithChildMixin` | |
| 207 or `ContainerRenderObjectMixin` takes care of this for you, assuming | |
| 208 you fulfill their contract instead. | |
| 209 | |
| 210 * If it has any data to store on its children, it must define a | |
| 211 BoxParentData subclass and override setParentData() to initialise | |
| 212 the child's parent data appropriately, as in the following example. | |
| 213 (If the subclass has an opinion about what type its children must | |
| 214 be, e.g. the way that `RenderBlock` wants its children to be | |
| 215 `RenderBox` nodes, then change the `setParentData()` signature | |
| 216 accordingly, to catch misuse of the method.) | |
| 217 | |
| 218 ```dart | |
| 219 class FooParentData extends BoxParentData { ... } | |
| 220 | |
| 221 // In RenderFoo | |
| 222 void setParentData(RenderObject child) { | |
| 223 if (child.parentData is! FooParentData) | |
| 224 child.parentData = new FooParentData(); | |
| 225 } | |
| 226 ``` | |
| 227 | |
| 228 * The class must encapsulate a layout algorithm that has the following | |
| 229 features: | |
| 230 | |
| 231 ** It uses as input a set of constraints, described by a | |
| 232 BoxConstraints object, and a set of zero or more children, as | |
| 233 determined by the class itself, and has as output a Size (which is | |
| 234 set on the object's own `size` field), and positions for each child | |
| 235 (which are set on the children's `parentData.position` field). | |
| 236 | |
| 237 ** The algorithm can decide the Size in one of two ways: either | |
| 238 exclusively based on the given constraints (i.e. it is effectively | |
| 239 sized entirely by its parent), or based on those constraints and | |
| 240 the dimensions of the children. | |
| 241 | |
| 242 In the former case, the class must have a sizedByParent getter that | |
| 243 returns true, and it must have a `performResize()` method that uses | |
| 244 the object's `constraints` member to size itself by setting the | |
| 245 `size` member. The size must be consistent, a given set of | |
| 246 constraints must always result in the same size. | |
| 247 | |
| 248 In the latter case, it will inherit the default `sizedByParent` | |
| 249 getter that returns false, and it will size itself in the | |
| 250 `performLayout()` function described below. | |
| 251 | |
| 252 The `sizedByParent` distinction is purely a performance | |
| 253 optimisation. It allows nodes that only set their size based on the | |
| 254 incoming constraints to skip that logic when they need to be | |
| 255 re-laid-out. | |
|
abarth-chromium
2015/06/25 19:41:06
I wonder if we should remove this concept until we
| |
| 256 | |
| 257 * The following methods must report numbers consistent with the output | |
| 258 of the layout algorithm used: | |
| 259 | |
| 260 ** `double getMinIntrinsicWidth(BoxConstraints constraints)` must | |
| 261 return the width that fits within the given constraints below which | |
| 262 making the width constraint smaller would not increase the | |
| 263 resulting height, or, to put it another way, the narrowest width at | |
| 264 which the box can be rendered without failing to lay the children | |
| 265 out within itself. | |
| 266 | |
| 267 For example, the minimum intrinsic width of a piece of text like "a | |
| 268 b cd e", where the text is allowed to wrap at spaces, would be the | |
| 269 width of "cd". | |
| 270 | |
| 271 ** `double getMaxIntrinsicWidth(BoxConstraints constraints)` must | |
| 272 return the width that fits within the given constraints above which | |
| 273 making the width constraint larger would not decrease the resulting | |
| 274 height. | |
| 275 | |
| 276 For example, the maximum intrinsic width of a piece of text like "a | |
| 277 b cd e", where the text is allowed to wrap at spaces, would be the | |
| 278 width of the whole "a b cd e" string, with no wrapping. | |
| 279 | |
| 280 ** `double getMinIntrinsicHeight(BoxConstraints constraints)` must | |
| 281 return the height that fits within the given constraints below | |
| 282 which making the height constraint smaller would not increase the | |
| 283 resulting width, or, to put it another way, the shortest height at | |
| 284 which the box can be rendered without failing to lay the children | |
| 285 out within itself. | |
| 286 | |
| 287 The minimum intrinsic height of a width-in-height-out algorithm, | |
| 288 like English text layout, would be the height of the text at the | |
| 289 width that would be used given the constraints. So for instance, | |
| 290 given the text "hello world", if the constraints were such that it | |
| 291 had to wrap at the space, then the minimum intrinsic height would | |
| 292 be the height of two lines (and the appropriate line spacing). If | |
| 293 the constraints were such that it all fit on one line, then it | |
| 294 would be the height of one line. | |
| 295 | |
| 296 ** `double getMaxIntrinsicHeight(BoxConstraints constraints)` must | |
| 297 return the height that fits within the given constraints above | |
| 298 which making the height constraint larger would not decrease the | |
| 299 resulting width. If the height depends exclusively on the width, | |
| 300 and the width does not depend on the height, then | |
| 301 `getMinIntrinsicHeight()` and `getMaxIntrinsicHeight()` will return the | |
| 302 same number given the same constraints. | |
| 303 | |
| 304 In the case of English text, the maximum intrinsic height is the | |
| 305 same as the minimum instrinsic height. | |
| 306 | |
| 307 * The box must have a `performLayout()` method that encapsulates the | |
| 308 layout algorithm that this class represents. It is responsible for | |
| 309 telling the children to lay out, positioning the children, and, if | |
| 310 sizedByParent is false, sizing the object. | |
| 311 | |
| 312 Specifically, the method must walk over the object's children, if | |
| 313 any, and for each one call `child.layout()` with a BoxConstraints | |
| 314 object as the first argument, and a second argument named | |
| 315 `parentUsesSize` which is set to true if the child's resulting size | |
| 316 will in any way influence the layout, and omitted (or set to false) | |
| 317 if the child's resulting size is ignored. The children's positions | |
| 318 (`child.parentData.position`) must then be set. | |
| 319 | |
| 320 (Calling `layout()` can result in the child's own `performLayout()` | |
| 321 method being called recursively, if the child also needs to be laid | |
| 322 out. If the child's constraints haven't changed and the child is not | |
| 323 marked as needing layout, however, this will be skipped.) | |
| 324 | |
| 325 The parent must not set a child's `size` directly. If the parent | |
| 326 wants to influence the child's size, it must do so via the | |
| 327 constraints that it passes to the child's `layout()` method. | |
| 328 | |
| 329 If an object's `sizedByParent` is false, then its `performLayout()` | |
| 330 must also size the object (by setting `size`), otherwise, the size | |
| 331 must be left untouched. | |
| 332 | |
| 333 * The `size` member must never be set to an infinite value. | |
| 334 | |
| 335 * The box must also implement `hitTestChildren()`. | |
| 336 TODO(ianh): Define this better | |
| 337 | |
| 338 * The box must also implement `paint()`. | |
| 339 TODO(ianh): Define this better | |
| 340 | |
| 124 #### Using RenderProxyBox | 341 #### Using RenderProxyBox |
| 125 | 342 |
| 126 ### The Hit Testing contract | 343 ### The Hit Testing contract |
| 127 | 344 |
| 128 | 345 |
| 129 Performance rules of thumb | 346 Performance rules of thumb |
| 130 -------------------------- | 347 -------------------------- |
| 131 | 348 |
| 132 * Avoid using transforms where mere maths would be sufficient (e.g. | 349 * Avoid using transforms where mere maths would be sufficient (e.g. |
| 133 draw your rectangle at x,y rather than translating by x,y and | 350 draw your rectangle at x,y rather than translating by x,y and |
| 134 drawing it at 0,0). | 351 drawing it at 0,0). |
| 135 | 352 |
| 136 * Avoid using save/restore on canvases. | 353 * Avoid using save/restore on canvases. |
| 137 | 354 |
| 138 | 355 |
| 139 Dependencies | 356 Dependencies |
| 140 ------------ | 357 ------------ |
| 141 | 358 |
| 142 * [`package:sky/base`](../base) | 359 * [`package:sky/base`](../base) |
| 143 * [`package:sky/mojo`](../mojo) | 360 * [`package:sky/mojo`](../mojo) |
| 144 * [`package:sky/animation`](../mojo) | 361 * [`package:sky/animation`](../mojo) |
| OLD | NEW |