summaryrefslogtreecommitdiff
path: root/doc/dw-grows.doc
blob: a0304ef93922e5d057d6f90c417cb5f40be800ab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/** \page dw-grows GROWS - Grand Redesign Of Widget Sizes

This paper describes (will describe) some design changes to
calculating widget sizes. Goals are:

- Simplification of widget size calculation by the parent widget;
  dw::Textblock::calcWidgetSize, dw::OutOfFlowMgr::ensureFloatSize
  etc. should become simpler or perhaps even obsolete.

- Making the implementation of some features possible:

  - *max-width*, *max-height*, *min-width*, *min-height*;
  - correct aspect ratio for images with only one percentage size defined;
  - *display: inline-block*;
  - <button>.


A short sketch
==============

**dw::core::Widget::sizeRequest and dw::core::Widget::getExtremes will
return final results.** The caller does not have to correct the size,
e. g. when percentages are defined. As an example,
dw::Textblock::calcWidgetSize has already become much simpler.

**A new hierarchy, *container*:** Aside from dw::core::Widget::parent
and dw::core::Widget::generator, there is a third hierarchy
dw::core::Widget::container, which is (unlike *generator*) always a
direct ancestor, and represents what in CSS is called *containing
block*. Containers are important to define the "context size", which
is (not solely) used for percentage sizes.

(There is another "containing block", dw::Textblock::containingBlock;
these may be consolidated some day.)

**The process of size calculation is split between the widget itself
and its container:**

- The container provides some abstract methods:
  dw::core::Widget::getAvailWidthOfChild,
  dw::core::Widget::getAvailHeightOfChild,
  dw::core::Widget::correctRequisitionOfChild, and
  dw::core::Widget::correctExtremesOfChild, which can be used in the
  actual implementation of dw::core::Widget::sizeRequestImpl;
  different containers with different ways how to arrange their
  children will implement these methods in a different way. (Simple
  example: the *available width* for children within a textblock is
  the *available width* for the textblock itself, minus
  margin/border/padding; on the other hand, it is completely different
  for children of tables, for which a complex column width calculation
  is used.)

- The actual size calculation is, however, controlled by the widget
  itself, which only *uses* these methods above.

<div style="border: 2px solid #ffff00; margin-top: 0.5em;
   margin-bottom: 0.5em; padding: 0.5em 1em; background-color: #ffffe0">
   <b>Update:</b> This is not fully correct; the parents are also involved
   for calculating available widths and heights, at least when CSS 'width'
   and 'height' are not set.</div>

**Size hints are removed.** Instead, the container methods in the
previous paragraph are used. Changes of container sizes (especially
viewport the size) are handled in a different way.

**Extremes are extended by intrinsic values.** In some cases (see
dw::Table::forceCalcCellSizes, case *minWidth* > *totalWidth*, for an
example) it is useful to know about minimal and maximal width of a
widget independent of CSS attributes. For this, dw::core::Extremes is
extended by:

- dw::core::Extremes::minWidthIntrinsic and
- dw::core::Extremes::maxWidthIntrinsic.

The rules for the calculation:

1. If a widget has no children, it calculates *minWidthIntrinsic* and
   *maxWidthIntrinsic* as those values not affected by CSS hints.
   (dw::core::Widget::correctExtremes will not change these values.)
2. A widget must calculate *minWidthIntrinsic* and *maxWidthIntrinsic*
   from *minWidthIntrinsic* and *maxWidthIntrinsic* of its children,
   and *minWidth* and *maxWidth* from *minWidth* and *maxWidth* of its
   children.
3. At the end, *minWidth* and *maxWidth* of a widget are corrected by
   CSS attributes. (dw::core::Widget::correctExtremes will do this.)

<div style="border: 2px solid #ffff00; margin-top: 0.5em;
   margin-bottom: 0.5em; padding: 0.5em 1em; background-color: #ffffe0">
   <b>Notice:</b> Currently, dw::core::Widget::getExtremesImpl must
   set all four members in dw::core::Extremes; this may change.</div>

Another **extension of extremes: *adjustmentWidth*.** This is used as
minimum for the width, when "adjust_min_width" (or,
"adjust_table_min_width", respectively) is set.

The rules for the calculation:

1. If a widget has no children, it can choose a suitable value,
   typically based on dw::core::Extremes::minWidth and
   dw::core::Extremes::minWidthIntrinsic.
2. A widget must calculate *adjustmentWidth* from *adjustmentWidth* of
   its children.

*Note:* An implementation of dw::core::Widget::getExtremesImpl may set
this value *after* calling dw::core::Widget::correctExtremesOfChild,
so that it cannot be used for the correction of extremes. In this case
*useAdjustmentWidth = false* should be passed to
dw::core::Widget::correctExtremesOfChild. On the other hand, if known
before, *useAdjustmentWidth* should be set to *true*.

Rules for *new* methods related to resizing
===========================================

- Of course, *sizeRequestImpl* may (should) call *correctRequisition*,
  and *getExtremesImpl* may (should) call *correctExtremes*.

- *sizeRequestImpl* (and *correctRequisition*) is allowed to call
  *getAvailWidth* and *getAvailHeight* with *forceValue* set, but
  *getExtremesImpl* (and *correctExtremes*) is allowed to call these
  only with *forceValue* unset.

- For this reason, *sizeRequestImpl* is indeed allowed to call
  *getExtremes* (dw::Table does so), but the opposite
  (*getExtremesImpl* calling *sizeRequest*) is not allowed
  anymore. (Before GROWS, the standard implementation
  dw::core::Widget::getExtremesImpl did so.)

- Finally, *getAvailWidth* and *getAvailHeight* may call
  *getExtremes*, if and only if *forceValue* is set.

Here is a diagram showing all permitted dependencies:

\dot
digraph G {
   node [shape=record, fontname=Helvetica, fontsize=10, color="#c0c0c0"];
   edge [arrowhead="open", arrowtail="none", color="#404040"];

   "sizeRequest[Impl]" -> "getExtremes[Impl]";
   "sizeRequest[Impl]" -> correctRequisition;
   "getExtremes[Impl]" -> correctExtremes;
   "sizeRequest[Impl]" -> "getAvail[Width|Height] (true)";
   "getExtremes[Impl]" -> "getAvail[Width|Height] (false)";
   correctRequisition -> "getAvail[Width|Height] (true)";
   correctExtremes -> "getAvail[Width|Height] (false)";
   "getAvail[Width|Height] (true)" -> "getExtremes[Impl]";   
}
\enddot

Open issues
===========

**Do CSS size dimensions override intrinsic sizes in all cases?** If a
textblock needs at least, say, 100 pixels width so that the text can
be read, but has a specification "width: 50px", should half of the
text be invisible? Or should the width be corrected again to 100
pixels?

Currently, in the CSS size specification is honoured in all cases,
with one exception: see dw::Textblock::sizeRequestImpl and see
dw::Textblock::getExtremesImpl (the time when
dw::core::Widget::correctRequisition and
dw::core::Widget::correctExtremes, respectively, is called).

*Not* honouring the CSS size specification in all cases could improve
readability in some cases, so this could depend on a user preference.

**Update:** There is now a dillorc option <tt>adjust_min_width</tt>,
which is implemented for widths, but not heights (since it is based on
width extremes, but there are currently no height extremes).

Another problem is that in most cases, there is no clippping, so that
contents may exceed the allocation of the widget, but redrawing is not
necessarily triggered.

**Percentage values for margins and paddings, as well as negative
margins** are interesting applications, but have not been considered
yet. For negative margins, a new attribute
dw::core::Widget::extraSpace could solve the problem of widgets
sticking out of the allocation of parent.

**Clarify percentage heights.** Search in widget.cc, and compare
section 10.5 ('height') of the CSS 2.1 specification to section 10.2
('width').

**Fast queue resize does not work fully.** Example: run
*test/dw-simple-container-test* (dw_simple_container_test.cc), resize
(best maximize) the window and follow (e.&nbsp;g. by using RTFL) what
happens in consequence of dw::core::Layout::viewportSizeChanged. The
dw::SimpleContainer in the middle is not affected, so only the two
dw::Textblock's (at the top and at the bottom) call queueResize with
*fast = true*, and so get *NEEDS_RESIZE* set; but since it is not set
for the dw::SimpleContainer, *sizeRequest* is never called for the
bottom dw::Textblock.

There does not seem to be a real case for this problem in dillo, since
all widgets which may contain other widgets (except
dw::SimpleContainer, which is not used outside tests) use the
available width and height (dw::core::Widget::usesAvailWidth and
dw::core::Widget::usesAvailHeight), and so are always affected by
viewport size changes.

*/