diff options
Diffstat (limited to 'doc')
-rw-r--r-- | doc/dw-out-of-flow.doc | 409 | ||||
-rw-r--r-- | doc/dw-widget-sizes.doc | 186 |
2 files changed, 527 insertions, 68 deletions
diff --git a/doc/dw-out-of-flow.doc b/doc/dw-out-of-flow.doc new file mode 100644 index 00000000..b6f65a28 --- /dev/null +++ b/doc/dw-out-of-flow.doc @@ -0,0 +1,409 @@ +/** \page dw-out-of-flow Handling Elements Out Of Flow + +<div style="border: 2px solid #ffff00; margin-bottom: 0.5em; +padding: 0.5em 1em; background-color: #ffffe0"><b>Info:</b> +Should be incorporated into dw::Textblock.</div> + +This texts deals with both floats and absolute positions, which have +in common, that there is a distinction between generating block and +containing block (we are here using the same notation as in the +CSS 2 specification). Consider this snippet (regarding floats): + + + <ul> + <li>Some text.</li> + <li> + <div style="float:right; width=50%">Some longer text, so + that the effect described in this passage can be + demonstrated. + </div> + Some more and longer text.</li> + <li>Final text.</li> + </ul> + +which may be rendered like this + + - - - - - - - - - - - - - - - - - - - - - - - - - . + | * Some text. + * Some more and - - - - - - - - - - - -.| + | longer text. |Some longer text, so that + * Final text. the effect described || + ` - - - - - - - - - - - |above in this passage can ' + be demonstrated. | + ` - - - - - - - - - - - - + +The float (the DIV section) is defined ("generated") within the list +item, so, in CSS 2 terms, the list item is the generating block of the +float. However, as the image shows, the float is not contained by the +list item, but another block, several levels above (not shown +here). In terms of ::dw, this means that the dw::Textblock +representing the float cannot be a child of the dw::Textblock +representing the generating block, the list item, since the allocation +of a child widget must be within the allocation of the parent +widget. Instead, to each dw::Textblock, another dw::Textblock is +assigned as the containing box. + +Definition of "containing block" +================================ + +The following definition follows the definition in the CSS 2 +specification. For a given dw::Textblock, the containing block is +defined as the one dw::Textblock following these rules: + +- For the toplevel widget, the containing block is itself (see + dw::Textblock::notifySetAsTopLevel). + +- Otherwise, ... TODO: Has been changed; see + dw::Textblock::notifySetParent. + +TODO: + +1. Compare this to + <http://www.w3.org/TR/CSS2/visudet.html#containing-block-details>. +2. Handle fixed positions: in this case, the viewport is the + containing box, but the viewport is not represented by a widget. +3. Clarify: the element out of flow must not be a dw::Textblock. + + +Implementation overview +======================= + +Widget level +------------ + +The terms _generating block_ and _containing block_ have been raised +to a higher level, the one of dw::core::Widget, and are here called +_generating widget_ and _containing widget_. To represent the +distinction, the type of dw::core::Content has been split into three +parts: + +- If a widget is out of flow, the generating widget keeps a reference + with the type dw::core::Content::WIDGET_OOF_REF, while the + containing block refers to it as dw::core::Content::WIDGET_OOF_CONT. + +- For widgets within flow, dw::core::Content::WIDGET_IN_FLOW is used. + +Notice that in the first case, there are two pieces of content +referring to the same widget. + +An application of this distinction is iterators. TODO: more. And still +missing: DeepIterator may need the generating parent widget in some +cases. + + +Textblock level +--------------- +Both dw::Textblock::notifySetAsTopLevel and +dw::Textblock::notifySetParent set the member +dw::Textblock::containingBlock appropriately, according to the rules +defined above. + +Handling widgets out of flow is partly the task of the new class +dw::OutOfFlowMgr, which is stored by dw::Textblock::outOfFlowMgr, but +only for containing blocks. Generating blocks should refer to +_containingBlock->outOfFlowMgr_. (Perhaps dw::OutOfFlowMgr may become +independent of dw::Textblock.) + +dw::Textblock::addWidget is extended, so that floats and absolutely +positioned elements can be added. Notice that not this widget, but the +containing block becomes the parent of the newly added child, if it is +out of flow. dw::Textblock::addWidget decides this by calling +dw::OutOfFlowMgr::isOutOfFlow. (See new content types above.) + +dw::core::Widget::parentRef has become a new representation. Before, +it represented the line numer. Now (least signifant bit left): + + +---+---+- - - - - - - - - - -+---+ + | line number | 0 | + +---+---+- - - - - - - - - - -+---+ + + +---+---+- - - - - - - - -+---+---+ + | number of left float | 0 | 1 | + +---+---+- - - - - - - - -+---+---+ + + +---+---+- - - - - - - - -+---+---+ + | number of right float | 1 | 1 | + +---+---+- - - - - - - - -+---+---+ + +The latter two must be changed, as soom as absolute positions are +introduced. Details are hidden by static inline methods of +dw::OutOfFlowMgr. + + +Interaction between generating box and containing box +===================================================== + +<div style="border: 2px solid #ff0000; margin-bottom: 0.5em; padding: +0.5em 1em; background-color: #ffefe0"><b>Warning:</b> This section +documents the current state, which is not free of errors.</div> + +A new widget out of flow is added to the generating block +--------------------------------------------------------- +With the respective style attributes set, this is delegated to the +dw::OutOfFlowMgr of the containing block: + + ,-------------. ,-------------. ,-------------. ,-------------. + | float | | OOFM | | cont. block | | gen. block | + `-------------' `-------------' `-------------' `-------------' + | | | | + ------------------------------------------------------------>| + | | | addWidget | + | | | (with an | + | | | appr. style) | + | | | | + | |<----------------------------------| + | | addWidget | | + +As with widgets in flow, dw::Textblock::wordWrap is called by/for the +generating block: + + | | | |--. + | | | | |wordWrap + | | | |<-' + +First, the generating block will tell the dw::OutOfFlowMgr about the +float position: + + | |<----------------------------------| + | | tellPosition | | + | | [1] | | + | | | | + | |---------------->| | + | | borderChanged | | + | | | | + | | |---------------->| + | | | borderChanged | + | | | | + | | | |--. + | | | | |queueResize + | | | |<-' + +After this, the line with must be calculated, with some implications: + + | | | |--. + | | | | |calcAvail\ + | | | | |Width + | | | |<-' + | | | | + | | | |--. + | | | | |lineLeft\ + | | | | |Border [1] + | | | |<-' + | | | | + | |<----------------------------------| + | | getLeftBorder | | + | | | | + | |--. | | + | | |ensureFloat\ | | + | | |Size | | + | |<-' | | + | | | | + |<----------------| | | + | sizeRequest | | | + | (perhaps) | | | + +"getRightBorder" in an analogue way. + +[1] Here, the values of diffXToContainingBlock, + restWidthToContainingBlock, and diffYToContainingBlock are + used. TODO: These may not be set correctly. + +The size of a float changes its size +------------------------------------ +First, the standard part: + + ,-------------. ,-------------. ,-------------. ,-------------. + | float | | OOFM | | cont. block | | gen. block | + `-------------' `-------------' `-------------' `-------------' + | | | | + |--. | | | + | |queueResize | | | + |<-' | | | + | | | | + |---------------------------------->| | + | | markSizeChange | | + +Since dw::core::Widget::parentRef indicates this child as out of flow, +this is delegated to the dw::OutOfFlowMgr: + + | |<----------------| | + | | markSizeChange | | + | | | | + | |---------------->| | + | | borderChanged | | + | | | | + | | |---------------->| + | | | borderChanged | + | | | | + | | | |--. + | | | | |queueResize + | | | |<-' + +Notice that the size of the float is not yet calculated, instead a +size request is queued (dw::OutOfFlowMgr::Float::dirty is set), which +will result in a new calculation of the size of the containing block. + +Also, queueResize is called recursively here: before the call for the +float is finished, it is called for the generating block. (See \ref +dw-widget-sizes for details.) + +Calculating the size +-------------------- +As usually, it starts at the top of the widget tree; in this case, the +containing block is regarded: + + ,-------------. ,-------------. ,-------------. ,-------------. + | Float | | OOFM | | cont. block | | gen. block | + `-------------' `-------------' `-------------' `-------------' + | | | | + ------------------------------------------>| | + | | sizeRequest | | + | | | | + | | |--. | + | | | sizeRequestImpl | + | | |<-' | + +During rewrapping, the size of the child is requested. We omit some +steps, since nothing has changed, except that + +- dw::Textblock::diffXToContainingBlock, +- dw::Textblock::restWidthToContainingBlock, and +- dw::Textblock::diffYToContainingBlock + +are set for the child, before this call: + + | | |---------------->| + | | | sizeRequest | + | | | | + | | | |--. + | | | | sizeRequest\ + | | | | Impl + | | | |<-' + +It may be that the child, the generating block, has to rewrap the +lines: + + | | | |--. + | | | | rewrap + | | | |<-' + | | | | + | |<----------------------------------| + | | tellNoPosition | | + | | | | +The rest is then similar to above: + + | | | |--. + | | | | wordWrap + | | | |<-' + | | | | + | |<----------------------------------| + | | tellPosition | | + | | [1] | | + | | | | + | |---------------->| | + | | borderChanged | | + | | | | + | | |---------------->| + | | | borderChanged | + | | | | + | | | |--. + | | | | |queueResize + | | | |<-' + | | | | + | | | |--. + | | | | |calcAvail\ + | | | | |Width + | | | |<-' + | | | | + | | | |--. + | | | | |lineLeft\ + | | | | |Border [1] + | | | |<-' + | | | | + | |<----------------------------------| + | | getLeftBorder | | + | | | | + | |--. | | + | | |ensureFloat\ | | + | | |Size | | + | |<-' | | + | | | | + |<----------------| | | + | sizeRequest | | | + | (perhaps) | | | + +Notice the nested sizeRequest (containing block -- generating block -- +float), but also the call of dw::core::Widget::queueResize within +dw::core::Widget::sizeRequestImpl, which is allowed, see +\ref dw-widget-sizes. + +[1] Here, the values of diffXToContainingBlock, + restWidthToContainingBlock, and diffYToContainingBlock are used. + + +Bugs and Things Needing Improvement +=================================== + +High Priority +------------- +**Misplaced/missing floats, wrong widths etc.:** Best is to provide +test pages with these errors, which are as simple as possible. + +**Extremes:** Extremes will be implemented by +dw::OutOfFlowMgr::getExtremes, which must be considered by +dw::Textblock::getExtremesImpl, like dw::OutOfFlowMgr::getSize is used +by dw::Textblock::sizeRequestImpl. The last two points (lines with no +contents/collisions of floats) lead to a very simple of +dw::OutOfFlowMgr::getExtremes: the result is simply the maximum of the +floats extremes. (This is at least correct for the minimal width.) + +**Rewrapping** (via dw::Textblock::borderChanged) sometimes does not +imply redrawing. Reproduce? + +(Plus some more; list must be updated.) + +Medium Priority +--------------- +**Position of a text block:** Setting, +dw::Textblock::diffXToContainingBlock, +dw::Textblock::restWidthToContainingBlock, and +dw::Textblock::diffYToContainingBlock in the current way is ugly, +should be replaced by something like size hints. + +**Determining the containing block:** In +dw::Textblock::notifySetAsTopLevel and dw::Textblock::notifySetParent: +should other widgets be able to be generating/containing block? + +**Determining whether a widget cares about floats:** Both variants of +_mustBorderBeRegarded_, and all variants of _getTextblockForLine_: +Perhaps, there should be only one widget of this type per line. + +**Implementing the attribute "clear":** ... + +**Exact positions of floats:** See dw::OutOfFlowMgr::calcBorderDiff. + +Low Priority +------------- +**Absolute positions:** Will be incorporated into the +dw::OutOfFlowMgr. + +**Fixed elements:** Some notes about what has do be done for fixed +elements: (i) In the current design, there is only one containing +block for a given generating block. However, a given generating block +may contain an element with absolute position (or, a float), + +Not a Bug (Kind of) +------------------- + +*Floats too far left?* Sometimes, floats seem too far on the +left side, as in test/floats-and-absolute.html, and also in +Wikipedia. This is only due to the fact that dillo does not yet +support absolute positions, and so absolutely positioned elements are +not regarded as containing block. (Or related to *Exact positions of +floats* above?) + +**Update:** Floats refer to the border of the *generating* box, not of +the *containing* box, so this is not an issue at all; furthermore, +this has been fixed. + +*/
\ No newline at end of file diff --git a/doc/dw-widget-sizes.doc b/doc/dw-widget-sizes.doc index 419a4a73..a4675c8a 100644 --- a/doc/dw-widget-sizes.doc +++ b/doc/dw-widget-sizes.doc @@ -1,22 +1,20 @@ /** \page dw-widget-sizes Sizes of Dillo Widgets -<h2>Allocation</h2> +Allocation +========== Each widget has an \em allocation at a given time, this includes -<ul> -<li> the position (\em x, \em y) relative to the upper left corner of the - canvas, and -<li> the size (\em width, \em ascent, \em descent). -</ul> +- the position (\em x, \em y) relative to the upper left corner of the + canvas, and +- the size (\em width, \em ascent, \em descent). The \em canvas is the whole area available for the widgets, in most -cases, only a part is seen in a viewport. The allocation of the toplevel widget is exactly the allocation of the canvas, i.e. +cases, only a part is seen in a viewport. The allocation of the +toplevel widget is exactly the allocation of the canvas, i.e. -<ul> -<li> the position of the toplevel widget is always (0, 0), and -<li> the canvas size is defined by the size of the toplevel widget. -</ul> +- the position of the toplevel widget is always (0, 0), and +- the canvas size is defined by the size of the toplevel widget. The size of a widget is not simply defined by the width and the height, instead, widgets may have a base line, and so are vertically @@ -31,13 +29,11 @@ defined by the limits of the C++ type \em int. In the example in the image, the widget has the following allocation: -<ul> -<li>\em x = 50 -<li>\em y = 50 -<li>\em width = 150 -<li>\em ascent = 150 -<li>\em descent = 100 -</ul> +- \em x = 50 +- \em y = 50 +- \em width = 150 +- \em ascent = 150 +- \em descent = 100 The current allocation of a widget is hold in dw::core::Widget::allocation. It can be set from outside by @@ -54,7 +50,9 @@ appropriate child allocations. dw::core::Widget::allocation should not be changed here, this is already done in dw::core::Widget::sizeAllocate. -<h2>Requisitions</h2> + +Requisitions +============ A widget may prefer a given size for the allocation. This size, the \em requisition, should be returned by the method @@ -62,14 +60,12 @@ dw::core::Widget::sizeRequestImpl. In the simplest case, this is independent of the context, e.g. for an image. dw::Image::sizeRequestImpl returns the following size: -<ul> -<li> If no buffer has yet been assigned (see dw::Image for more details), - the size necessary for the alternative text is returned. If no - alternative text has been set, zero is returned. +- If no buffer has yet been assigned (see dw::Image for more details), + the size necessary for the alternative text is returned. If no + alternative text has been set, zero is returned. -<li> If a buffer has been assigned (by dw::Image::setBuffer), the root - size is returned (i.e. the original size of the image to display). -</ul> +- If a buffer has been assigned (by dw::Image::setBuffer), the root + size is returned (i.e. the original size of the image to display). This is a bit simplified, dw::Image::sizeRequestImpl should also deal with margins, borders and paddings, see dw::core::style. @@ -87,7 +83,9 @@ widget), may, but also may not consider the requisition. Instead, a widget must deal with any allocation. (For example, dw::Image scales the image buffer when allocated at another size.) -<h2>Size Hints</h2> + +Size Hints +========== Some widgets do not have an inherent size, but depend on the context, e.g. the viewport size. These widgets should adhere to <i>size hints</i>, @@ -95,11 +93,9 @@ i.e. implement the methods dw::core::Widget::setWidth, dw::core::Widget::setAscent and dw::core::Widget::setDescent. The values passed to the callees are -<ul> -<li> the viewport size (ascent is the heigt here, while descent is 0) for - the toplevel widget, and -<li> determined by the parent for its child widgets. -</ul> +- the viewport size (ascent is the heigt here, while descent is 0) for + the toplevel widget, and +- determined by the parent for its child widgets. Generally, the values should define the available space for the widget. @@ -109,42 +105,41 @@ dw::core::Widget::queueResize, when apropriate. \todo There should be a definition of "available space". -<h2>Width Extremes</h2> + +Width Extremes +============== dw::Table uses width extremes for fast calculation of column widths. The structure dw::core::Extremes represents the minimal and maximal width of a widget, as defined by: -<ul> -<li> the minimal width is the smallest width, at which a widget can still - display contents, and -<li> the maximal width is the largest width, above which increasing the width - does not make any sense. -</ul> +- the minimal width is the smallest width, at which a widget can still + display contents, and +- the maximal width is the largest width, above which increasing the + width- does not make any sense. Especially the latter is vaguely defined, here are some examples: -<ul> -<li> For those widgets, which do not depend on size hints, the minimal and - the maximal width is the inherent width (the one returned by - dw::core::Widget::sizeRequest). +- For those widgets, which do not depend on size hints, the minimal + and the maximal width is the inherent width (the one returned by + dw::core::Widget::sizeRequest). -<li> For a textblock, the minimal width is the width of the widest - (unbreakable) word, the maximal width is the width of the total - paragraph (stretching a paragraph further would only waste space). - Actually, the implementation of dw::Textblock::getExtremesImpl is - a bit more complex. +- For a textblock, the minimal width is the width of the widest + (unbreakable) word, the maximal width is the width of the total + paragraph (stretching a paragraph further would only waste space). + Actually, the implementation of dw::Textblock::getExtremesImpl is a + bit more complex. -<li> dw::Table is an example, where the width extremes are calculated - from the width extremes of the children. -</ul> +- dw::Table is an example, where the width extremes are calculated + from the width extremes of the children. Handling width extremes is similar to handling requisitions, a widget must implement dw::core::Widget::getExtremesImpl, but a caller will use dw::core::Widget::getExtremes. -<h2>Resizing</h2> +Resizing +======== When the widget changes its size (requisition), it should call dw::core::Widget::queueResize. The next call of @@ -160,27 +155,82 @@ done before. In this case, a widget must exactly know the reasons, why a call of dw::core::Widget::sizeRequestImpl is necessary. To make use of this, a widget must implement the following: -<ol> -<li> There is a member dw::core::Widget::parentRef, which is - totally under control of the parent widget (and so sometimes not - used at all). It is necessary to define how parentRef is used - by a specific parent widget, and it has to be set to the correct - value whenever necessary. - -<li> The widget must implement dw::core::Widget::markSizeChange and +1. There is a member dw::core::Widget::parentRef, which is totally + under control of the parent widget (and so sometimes not used at + all). It is necessary to define how parentRef is used by a specific + parent widget, and it has to be set to the correct value whenever + necessary. +2. The widget must implement dw::core::Widget::markSizeChange and dw::core::Widget::markExtremesChange, these methods are called in two cases: - - <ol> - <li> directly after dw::core::Widget::queueResize, with the argument - ref was passed to dw::core::Widget::queueResize, and - <li> if a child widget has called dw::core::Widget::queueResize, - with the value of the parent_ref member of this child. - </ol> -</ol> + 1. directly after dw::core::Widget::queueResize, with the + argument ref was passed to dw::core::Widget::queueResize, + and + 2. if a child widget has called dw::core::Widget::queueResize, + with the value of the parent_ref member of this child. This way, a widget can exactly keep track on size changes, and so implement resizing in a faster way. A good example on how to use this is dw::Textblock. + +Rules for Methods Related to Resizing +===================================== + +<div style="border: 2px solid #ff0000; margin-bottom: 0.5em; +padding: 0.5em 1em; background-color: #ffefe0"><b>Warning:</b> +This section still needs some work.</div> + +Which method can be called, when the call of another method is not +finished? These rules are important in two circumstances: + +1. To know which method can be called, and, especially, which methods + _must not_ be called, within the implementation of + dw::core::Widget::sizeRequestImpl (called by + dw::core::Widget::sizeRequest), dw::core::Widget::markSizeChange, + and dw::core::Widget::markExtremesChange (the latter two are + called by dw::core::Widget::queueResize). +2. On the other hand, to make sure that the calls, which are allowed, + are handled correctly, especially in implementations of + dw::core::Widget::sizeRequestImpl, + dw::core::Widget::markSizeChange, and + dw::core::Widget::markExtremesChange. + +The rules in detail: + +- Within dw::core::Widget::sizeRequest / + dw::core::Widget::sizeRequestImpl: + 1. dw::core::Widget::sizeRequest must only be called for + children. Otherwise, an endless recursion would easily occur. + 2. dw::core::Widget::queueResize can be called. See below for + details. + +- Within queueResize / dw::core::Widget::markSizeChange / + dw::core::Widget::markExtremesChange. + 1. dw::core::Widget::sizeRequest must _not_ be called. As a example, + look at dw::Image::setBuffer: Here, dw::core::Widget::queueResize + is called at the beginning, while dw::Image::buffer, which is + needed by dw::Image::sizeRequest, is set later. If the + implementation of dw::core::Widget::markSizeChange or + dw::core::Widget::markExtremesChange of a parent widget calls + dw::core::Widget::sizeRequest for the image widget, a wrong value + for the buffer would be used. (Of course, it is possible to first + set dw::Image::buffer, and the call + dw::core::Widget::queueResize, but this does not change the fact + that these considerations should not be necessary on this level.) + 2. dw::core::Widget::queueResize can be called with some + limitations. It has to be ensured that no endless recursion is + caused, e. g. by calling dw::core::Widget::queueResize for a + child. (But this is not the only case.) See below for details. + +The facts that dw::core::Widget::queueResize can be called within +other methods, leads to following guidelines: + +- dw::core::Widget::queueResize simply goes up in the hierarchy of + widgeds, sets some flags, and calls dw::core::Widget::markSizeChange + and dw::core::Widget::markExtremesChange. +- dw::core::Widget::markSizeChange and + dw::core::Widget::markExtremesChange should be kept extremely + simple. (TODO: Details) + */ |