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

Side by Side 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, 5 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 unified diff | 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 »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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)
OLDNEW
« 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